fix: Restore DNS prefetching for static resources (#1820)

* fix: Restore DNS prefetching for static resources

* fix: CDN paths
feat: preload instead of prefetch for key bundles

* csp

* fix: Turns out prefetch-src is still behind a flag in Chrome, not publicly available yet
This commit is contained in:
Tom Moor 2021-01-18 15:48:46 -08:00 committed by GitHub
parent 27fca28450
commit 3bace8c9e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 53 deletions

View File

@ -203,7 +203,7 @@
"url-loader": "^0.6.2", "url-loader": "^0.6.2",
"webpack": "4.44.1", "webpack": "4.44.1",
"webpack-cli": "^3.3.12", "webpack-cli": "^3.3.12",
"webpack-manifest-plugin": "^2.2.0" "webpack-manifest-plugin": "^3.0.0"
}, },
"resolutions": { "resolutions": {
"dot-prop": "^5.2.0", "dot-prop": "^5.2.0",

View File

@ -23,21 +23,21 @@ const isProduction = process.env.NODE_ENV === "production";
const isTest = process.env.NODE_ENV === "test"; const isTest = process.env.NODE_ENV === "test";
// Construct scripts CSP based on services in use by this installation // Construct scripts CSP based on services in use by this installation
const defaultSrc = ["'self'"];
const scriptSrc = [ const scriptSrc = [
"'self'", "'self'",
"'unsafe-inline'", "'unsafe-inline'",
"'unsafe-eval'", "'unsafe-eval'",
"gist.github.com", "gist.github.com",
"browser.sentry-cdn.com",
]; ];
if (env.GOOGLE_ANALYTICS_ID) { if (env.GOOGLE_ANALYTICS_ID) {
scriptSrc.push("www.google-analytics.com"); scriptSrc.push("www.google-analytics.com");
} }
if (env.SENTRY_DSN) {
scriptSrc.push("browser.sentry-cdn.com");
}
if (env.CDN_URL) { if (env.CDN_URL) {
scriptSrc.push(env.CDN_URL); scriptSrc.push(env.CDN_URL);
defaultSrc.push(env.CDN_URL);
} }
app.use(compress()); app.use(compress());
@ -167,7 +167,7 @@ app.use(helmet());
app.use( app.use(
contentSecurityPolicy({ contentSecurityPolicy({
directives: { directives: {
defaultSrc: ["'self'"], defaultSrc,
scriptSrc, scriptSrc,
styleSrc: ["'self'", "'unsafe-inline'", "github.githubassets.com"], styleSrc: ["'self'", "'unsafe-inline'", "github.githubassets.com"],
imgSrc: ["*", "data:", "blob:"], imgSrc: ["*", "data:", "blob:"],

View File

@ -10,6 +10,7 @@ import { languages } from "../shared/i18n";
import environment from "./env"; import environment from "./env";
import apexRedirect from "./middlewares/apexRedirect"; import apexRedirect from "./middlewares/apexRedirect";
import { opensearchResponse } from "./utils/opensearch"; import { opensearchResponse } from "./utils/opensearch";
import prefetchTags from "./utils/prefetchTags";
import { robotsResponse } from "./utils/robots"; import { robotsResponse } from "./utils/robots";
const isProduction = process.env.NODE_ENV === "production"; const isProduction = process.env.NODE_ENV === "production";
@ -50,6 +51,7 @@ const renderApp = async (ctx, next) => {
ctx.body = page ctx.body = page
.toString() .toString()
.replace(/\/\/inject-env\/\//g, env) .replace(/\/\/inject-env\/\//g, env)
.replace(/\/\/inject-prefetch\/\//g, prefetchTags)
.replace(/\/\/inject-sentry-dsn\/\//g, process.env.SENTRY_DSN || "") .replace(/\/\/inject-sentry-dsn\/\//g, process.env.SENTRY_DSN || "")
.replace(/\/\/inject-slack-app-id\/\//g, process.env.SLACK_APP_ID || ""); .replace(/\/\/inject-slack-app-id\/\//g, process.env.SLACK_APP_ID || "");
}; };

View File

@ -4,6 +4,7 @@
<title>Outline</title> <title>Outline</title>
<meta name="slack-app-id" content="//inject-slack-app-id//" /> <meta name="slack-app-id" content="//inject-slack-app-id//" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
//inject-prefetch//
<link <link
rel="shortcut icon" rel="shortcut icon"
type="image/png" type="image/png"

View File

@ -2,48 +2,57 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import * as React from "react"; import * as React from "react";
import webpackConfig from "../../webpack.config"; import ReactDOMServer from "react-dom/server";
import env from "../env";
const PUBLIC_PATH = webpackConfig.output.publicPath; const prefetchTags = [];
const prefetchTags = [ if (process.env.AWS_S3_UPLOAD_BUCKET_URL) {
<link prefetchTags.push(
rel="dns-prefetch" <link
href={process.env.AWS_S3_UPLOAD_BUCKET_URL} rel="dns-prefetch"
key="dns" href={process.env.AWS_S3_UPLOAD_BUCKET_URL}
/>, key="dns"
]; />
);
}
let manifestData = {};
try { try {
const manifest = fs.readFileSync( const manifest = fs.readFileSync(
path.join(__dirname, "../../app/manifest.json"), path.join(__dirname, "../../app/manifest.json"),
"utf8" "utf8"
); );
const manifestData = JSON.parse(manifest); manifestData = JSON.parse(manifest);
Object.values(manifestData).forEach((filename) => { } catch (err) {
if (typeof filename !== "string") return; console.warn(err);
if (filename.endsWith(".js")) {
prefetchTags.push(
<link
rel="prefetch"
href={`${PUBLIC_PATH}${filename}`}
key={filename}
as="script"
/>
);
} else if (filename.endsWith(".css")) {
prefetchTags.push(
<link
rel="prefetch"
href={`${PUBLIC_PATH}${filename}`}
key={filename}
as="style"
/>
);
}
});
} catch (_e) {
// no-op
} }
export default prefetchTags; Object.values(manifestData).forEach((filename) => {
if (typeof filename !== "string") return;
if (!env.CDN_URL) return;
if (filename.endsWith(".js")) {
// Preload resources you have high-confidence will be used in the current
// page.Prefetch resources likely to be used for future navigations
const shouldPreload =
filename.includes("/main") ||
filename.includes("/runtime") ||
filename.includes("/vendors");
prefetchTags.push(
<link
rel={shouldPreload ? "preload" : "prefetch"}
href={filename}
key={filename}
as="script"
/>
);
} else if (filename.endsWith(".css")) {
prefetchTags.push(
<link rel="prefetch" href={filename} key={filename} as="style" />
);
}
});
export default ReactDOMServer.renderToString(prefetchTags);

View File

@ -1,7 +1,7 @@
/* eslint-disable */ /* eslint-disable */
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const ManifestPlugin = require('webpack-manifest-plugin'); const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
commonWebpackConfig = require('./webpack.config'); commonWebpackConfig = require('./webpack.config');
@ -42,7 +42,7 @@ productionWebpackConfig = Object.assign(commonWebpackConfig, {
productionWebpackConfig.plugins = [ productionWebpackConfig.plugins = [
...productionWebpackConfig.plugins, ...productionWebpackConfig.plugins,
new ManifestPlugin() new WebpackManifestPlugin()
]; ];
module.exports = productionWebpackConfig; module.exports = productionWebpackConfig;

View File

@ -7946,7 +7946,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
"lodash@>=3.5 <5", lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5: lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5:
version "4.17.20" version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@ -8728,7 +8728,7 @@ object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.1:
has-symbols "^1.0.1" has-symbols "^1.0.1"
object-keys "^1.1.1" object-keys "^1.1.1"
object.entries@^1.1.0, object.entries@^1.1.2: object.entries@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==
@ -11071,7 +11071,7 @@ sort-keys@^2.0.0:
dependencies: dependencies:
is-plain-obj "^1.0.0" is-plain-obj "^1.0.0"
source-list-map@^2.0.0: source-list-map@^2.0.0, source-list-map@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
@ -11552,6 +11552,11 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tapable@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
tar@^6.0.2: tar@^6.0.2:
version "6.0.5" version "6.0.5"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f"
@ -12599,15 +12604,13 @@ webpack-hot-middleware@2.x:
querystring "^0.2.0" querystring "^0.2.0"
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
webpack-manifest-plugin@^2.2.0: webpack-manifest-plugin@^3.0.0:
version "2.2.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz#19ca69b435b0baec7e29fbe90fb4015de2de4f16" resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-3.0.0.tgz#426644300e5dc41a75a9c996c4d4f876eb3c2b5b"
integrity sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ== integrity sha512-nbORTdky2HxD8XSaaT+zrsHb30AAgyWAWgCLWaAeQO21VGCScGb52ipqlHA/njix1Z8OW8IOlo4+XK0OKr1fkw==
dependencies: dependencies:
fs-extra "^7.0.0" tapable "^2.0.0"
lodash ">=3.5 <5" webpack-sources "^2.2.0"
object.entries "^1.1.0"
tapable "^1.0.0"
webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
version "1.4.3" version "1.4.3"
@ -12617,6 +12620,14 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
source-list-map "^2.0.0" source-list-map "^2.0.0"
source-map "~0.6.1" source-map "~0.6.1"
webpack-sources@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac"
integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==
dependencies:
source-list-map "^2.0.1"
source-map "^0.6.1"
webpack@4.44.1: webpack@4.44.1:
version "4.44.1" version "4.44.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.1.tgz#17e69fff9f321b8f117d1fda714edfc0b939cc21" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.1.tgz#17e69fff9f321b8f117d1fda714edfc0b939cc21"