diff --git a/package.json b/package.json index c16ad909..db3e648b 100644 --- a/package.json +++ b/package.json @@ -200,6 +200,7 @@ "nodemon": "1.11.0", "prettier": "1.8.2", "raf": "^3.4.0", - "react-test-renderer": "^16.1.0" + "react-test-renderer": "^16.1.0", + "webpack-manifest-plugin": "^1.3.2" } } diff --git a/server/pages/components/Layout.js b/server/pages/components/Layout.js index 02c40de7..5248eaf7 100644 --- a/server/pages/components/Layout.js +++ b/server/pages/components/Layout.js @@ -5,6 +5,7 @@ import { TopNavigation, BottomNavigation } from './Navigation'; import Analytics from '../../../shared/components/Analytics'; import globalStyles from '../../../shared/styles/globals'; import { color } from '../../../shared/styles/constants'; +import prefetchTags from '../../utils/prefetchTags'; type Props = { children?: React$Element<*>, @@ -40,10 +41,7 @@ export default function Layout({ children }: Props) { href="/favicon-32.png" sizes="32x32" /> - + {prefetchTags} diff --git a/server/utils/prefetchTags.js b/server/utils/prefetchTags.js new file mode 100644 index 00000000..4534e84c --- /dev/null +++ b/server/utils/prefetchTags.js @@ -0,0 +1,33 @@ +// @flow +import React from 'react'; +import webpackConfig from '../../webpack.config'; + +const PUBLIC_PATH = webpackConfig.output.publicPath; + +const prefetchTags = [ + , +]; + +if (process.env.NODE_ENV === 'production') { + try { + const manifest = require('../../dist/manifest.json'); + Object.values(manifest).forEach(filename => { + if (typeof filename !== 'string') return; + if (filename.endsWith('.js')) { + prefetchTags.push( + + ); + } else if (filename.endsWith('.css')) { + prefetchTags.push( + + ); + } + }); + } catch (_e) { + console.warn( + 'Warning: Unable to load dist/manifest.json. Please `yarn build` before starting production server' + ); + } +} + +export default prefetchTags; diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 94519629..6a88b72c 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -16,12 +16,13 @@ const developmentWebpackConfig = Object.assign(commonWebpackConfig, { ], }); -developmentWebpackConfig.plugins.push(new ExtractTextPlugin({ filename: 'styles.css' })); -developmentWebpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); -developmentWebpackConfig.plugins.push( +developmentWebpackConfig.plugins = [ + ...developmentWebpackConfig.plugins, + new ExtractTextPlugin({ filename: 'styles.css' }), + new webpack.HotModuleReplacementPlugin(), new HtmlWebpackPlugin({ title: 'Outline', - }) -); + }), +]; module.exports = developmentWebpackConfig; diff --git a/webpack.config.prod.js b/webpack.config.prod.js index 623d0e65..9365753e 100644 --- a/webpack.config.prod.js +++ b/webpack.config.prod.js @@ -3,6 +3,7 @@ var path = require('path'); var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); +var ManifestPlugin = require('webpack-manifest-plugin'); commonWebpackConfig = require('./webpack.config'); @@ -17,27 +18,23 @@ productionWebpackConfig = Object.assign(commonWebpackConfig, { }, stats: "normal" }); -productionWebpackConfig.plugins.push( +productionWebpackConfig.plugins = [ + ...productionWebpackConfig.plugins, + new ManifestPlugin(), new HtmlWebpackPlugin({ template: 'server/static/index.html', - }) -); -productionWebpackConfig.plugins.push( - new ExtractTextPlugin({ filename: 'styles.[hash].css' }) -); -productionWebpackConfig.plugins.push( + }), + new ExtractTextPlugin({ filename: 'styles.[hash].css' }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, - }) -); -productionWebpackConfig.plugins.push( + }), new webpack.DefinePlugin({ 'process.env': { URL: JSON.stringify(process.env.URL), NODE_ENV: JSON.stringify('production'), GOOGLE_ANALYTICS_ID: JSON.stringify(process.env.GOOGLE_ANALYTICS_ID), }, - }) -); + }), +]; module.exports = productionWebpackConfig; diff --git a/yarn.lock b/yarn.lock index 1397f3a2..1ebc4e74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3612,6 +3612,16 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + fs-extra@^4.0.0, fs-extra@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" @@ -3922,7 +3932,7 @@ graceful-fs@^3.0.0, graceful-fs@~3.0.2: dependencies: natives "^1.1.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -5369,6 +5379,12 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" @@ -5468,6 +5484,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + koa-bodyparser@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.2.0.tgz#bce6e08bc65f8709b6d1faa9411c7f0d8938aa54" @@ -6086,7 +6108,7 @@ lodash.values@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" -lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -9910,6 +9932,13 @@ webpack-hot-middleware@2.x: querystring "^0.2.0" strip-ansi "^3.0.0" +webpack-manifest-plugin@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-1.3.2.tgz#5ea8ee5756359ddc1d98814324fe43496349a7d4" + dependencies: + fs-extra "^0.30.0" + lodash ">=3.5 <5" + webpack-sources@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"