diff --git a/.eslintignore b/.eslintignore
index 5cc1873034..890258d49f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,3 +1,4 @@
generated
__fixtures__
-dist
\ No newline at end of file
+dist
+website
\ No newline at end of file
diff --git a/lib/commands/build.js b/lib/commands/build.js
index 7f017ca84e..cbb6501d7c 100644
--- a/lib/commands/build.js
+++ b/lib/commands/build.js
@@ -4,7 +4,8 @@ const chalk = require('chalk');
const fs = require('fs-extra');
const globby = require('globby');
const load = require('../load');
-const createProdConfig = require('../webpack/prod');
+const createServerConfig = require('../webpack/server');
+const createClientConfig = require('../webpack/client');
function compile(config) {
return new Promise((resolve, reject) => {
@@ -35,11 +36,14 @@ module.exports = async function build(siteDir, cliOptions = {}) {
const props = await load(siteDir);
- // create compiler from generated webpack config
- const config = createProdConfig(props).toConfig();
+ const serverConfig = createServerConfig(props).toConfig();
+ const clientConfig = createClientConfig(props).toConfig();
- // compile!
- await compile(config);
+ // we build the client bundles first
+ await compile(clientConfig);
+
+ // then we build the server bundles (render the static HTML and pick client bundle)
+ await compile(serverConfig);
// copy static files
const {outDir} = props;
diff --git a/lib/commands/start.js b/lib/commands/start.js
index a42804ad2b..a8ee2f4f5f 100644
--- a/lib/commands/start.js
+++ b/lib/commands/start.js
@@ -10,8 +10,9 @@ const serveStatic = require('koa-static');
const history = require('connect-history-api-fallback');
const portfinder = require('portfinder');
const serve = require('webpack-serve');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
const load = require('../load');
-const createDevConfig = require('../webpack/dev');
+const createClientConfig = require('../webpack/client');
async function getPort(reqPort) {
portfinder.basePort = parseInt(reqPort, 10) || 3000;
@@ -52,7 +53,18 @@ module.exports = async function start(siteDir, cliOptions = {}) {
const {baseUrl} = props;
// create compiler from generated webpack config
- const config = createDevConfig(props).toConfig();
+ let config = createClientConfig(props);
+
+ const {siteConfig} = props;
+ config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [
+ {
+ hash: true,
+ template: path.resolve(__dirname, '../core/devTemplate.ejs'),
+ filename: 'index.html',
+ title: siteConfig.title
+ }
+ ]);
+ config = config.toConfig();
const compiler = webpack(config);
// webpack-serve
diff --git a/lib/core/clientEntry.js b/lib/core/clientEntry.js
new file mode 100644
index 0000000000..38f475e627
--- /dev/null
+++ b/lib/core/clientEntry.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import {BrowserRouter} from 'react-router-dom';
+import ReactDOM from 'react-dom';
+
+import App from './App';
+import prerender from './prerender';
+import routes from '@generated/routes'; // eslint-disable-line
+
+// Client side render (e.g: running in browser) to become single-page application (SPA)
+if (typeof window !== 'undefined' && typeof document !== 'undefined') {
+ prerender(routes, window.location.pathname).then(() => {
+ ReactDOM.render(
+
+
+ ,
+ document.getElementById('app')
+ );
+ });
+}
diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js
deleted file mode 100644
index 3cfc7386bc..0000000000
--- a/lib/core/devEntry.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import {BrowserRouter} from 'react-router-dom';
-
-import App from './App';
-
-ReactDOM.render(
-
-
- ,
- document.getElementById('app')
-);
diff --git a/lib/core/prerender.js b/lib/core/prerender.js
new file mode 100644
index 0000000000..7e41893617
--- /dev/null
+++ b/lib/core/prerender.js
@@ -0,0 +1,18 @@
+import {matchRoutes} from 'react-router-config';
+
+/**
+ * This helps us to make sure all the async component for that particular route
+ * is loaded before rendering. This is to avoid loading screens on first page load
+ */
+export default function prerender(routeConfig, providedLocation) {
+ const matches = matchRoutes(routeConfig, providedLocation);
+ return Promise.all(
+ matches.map(match => {
+ const {component} = match.route;
+ if (component && component.preload) {
+ return component.preload();
+ }
+ return undefined;
+ })
+ );
+}
diff --git a/lib/core/prodEntry.js b/lib/core/prodEntry.js
deleted file mode 100644
index 24ff2ac532..0000000000
--- a/lib/core/prodEntry.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-import {BrowserRouter, StaticRouter} from 'react-router-dom';
-import ReactDOM from 'react-dom';
-import ReactDOMServer from 'react-dom/server';
-
-import App from './App';
-
-// Client side render (e.g: running in browser) to become single-page application (SPA)
-if (typeof document !== 'undefined') {
- ReactDOM.render(
-
-
- ,
- document.getElementById('app')
- );
-}
-
-// Renderer for static-site-generator-webpack-plugin (async rendering via callbacks)
-export default function render(locals, callback) {
- const context = {};
- const body = ReactDOMServer.renderToString(
-
-
-
- );
-
- // Build HTML template
- const assets = Object.keys(locals.webpackStats.compilation.assets);
- const css = assets.filter(value => value.match(/\.css$/));
- const js = assets.filter(value => value.match(/\.js$/));
- const {title, baseUrl, lang = 'en', template} = locals;
- const html = template({body, baseUrl, css, js, title, lang});
-
- callback(null, html);
-}
diff --git a/lib/core/prodTemplate.ejs b/lib/core/prodTemplate.ejs
deleted file mode 100644
index 2c11428a73..0000000000
--- a/lib/core/prodTemplate.ejs
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
- <%- title %>
- <% css.forEach(function(file){ %>
-
- <% }); %>
-
-
- <%- body %>
- <% js.forEach(function(file){ %>
-
- <% }); %>
-
-
\ No newline at end of file
diff --git a/lib/core/serverEntry.js b/lib/core/serverEntry.js
new file mode 100644
index 0000000000..1bd7dab180
--- /dev/null
+++ b/lib/core/serverEntry.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import {StaticRouter} from 'react-router-dom';
+import ReactDOMServer from 'react-dom/server';
+import Helmet from 'react-helmet';
+
+import App from './App';
+import prerender from './prerender';
+import routes from '@generated/routes'; // eslint-disable-line
+import webpackClientStats from '@build/client.stats.json'; //eslint-disable-line
+
+// Renderer for static-site-generator-webpack-plugin (async rendering via promises)
+export default function render(locals) {
+ return prerender(routes, locals.path).then(() => {
+ const context = {};
+ const appHtml = ReactDOMServer.renderToString(
+
+
+
+ );
+
+ const helmet = Helmet.renderStatic();
+ const htmlAttributes = helmet.htmlAttributes.toString();
+ const bodyAttributes = helmet.bodyAttributes.toString();
+ const metaStrings = [
+ helmet.title.toString(),
+ helmet.meta.toString(),
+ helmet.link.toString()
+ ];
+ const metaHtml = metaStrings.filter(Boolean).join('\n ');
+
+ const assets = webpackClientStats.assetsByChunkName.main;
+ const jsFiles = assets.filter(value => value.match(/\.js$/));
+ const cssFiles = assets.filter(value => value.match(/\.css$/));
+ const {baseUrl} = locals;
+
+ const html = `
+
+
+
+ ${metaHtml}
+
+
+ ${cssFiles.map(
+ cssFile =>
+ ``
+ )}
+
+
+ ${appHtml}
+ ${jsFiles.map(
+ jsFile =>
+ ``
+ )}
+
+
+`;
+ return html;
+ });
+}
diff --git a/lib/load/routes.js b/lib/load/routes.js
index 2b6f48fd60..286ca42b76 100644
--- a/lib/load/routes.js
+++ b/lib/load/routes.js
@@ -1,40 +1,32 @@
-const {fileToComponentName} = require('./utils');
-
async function genRoutesConfig({docsData = [], pagesData = []}) {
function genDocsRoute({path: docsPath, source}) {
- const componentName = fileToComponentName(source);
return `
{
path: ${JSON.stringify(docsPath)},
exact: true,
- component: (props) => (
-
- <${componentName} />
-
- )
+ component: Loadable({
+ loader: () => import('@docs/${source}'),
+ loading: Loading,
+ render(loaded, props) {
+ let Content = loaded.default;
+ return ;
+ }
+ })
}`;
}
- function genDocsImport({source}) {
- const componentName = fileToComponentName(source);
- return `import ${componentName} from '@docs/${source}';`;
- }
-
function genPagesRoute({path: pagesPath, source}) {
- const componentName = fileToComponentName(source);
return `
{
path: ${JSON.stringify(pagesPath)},
exact: true,
- component: ${componentName}
+ component: Loadable({
+ loader: () => import('@pages/${source}'),
+ loading: Loading
+ })
}`;
}
- function genPagesImport({source}) {
- const componentName = fileToComponentName(source);
- return `import ${componentName} from '@pages/${source}';`;
- }
-
const notFoundRoute = `,
{
path: '*',
@@ -43,10 +35,10 @@ async function genRoutesConfig({docsData = [], pagesData = []}) {
return (
`import React from 'react';\n` +
+ `import Loading from '@theme/Loading';\n` +
+ `import Loadable from 'react-loadable';\n` +
`import Docs from '@theme/Docs';\n` +
`import NotFound from '@theme/NotFound';\n` +
- `${pagesData.map(genPagesImport).join('\n')}\n` +
- `${docsData.map(genDocsImport).join('\n')}\n` +
`const routes = [${docsData.map(genDocsRoute).join(',')},${pagesData
.map(genPagesRoute)
.join(',')}${notFoundRoute}\n];\n` +
diff --git a/lib/theme/Loading.js b/lib/theme/Loading.js
new file mode 100644
index 0000000000..c4af8d5525
--- /dev/null
+++ b/lib/theme/Loading.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+export default props => {
+ if (props.error) {
+ return (
+
+ Error!{' '}
+
+
+ );
+ }
+ return Loading...
;
+};
diff --git a/lib/webpack/base.js b/lib/webpack/base.js
index db3eec401e..2e3b496294 100644
--- a/lib/webpack/base.js
+++ b/lib/webpack/base.js
@@ -4,7 +4,7 @@ const path = require('path');
const mdLoader = require.resolve('./loader/markdown');
-module.exports = function createBaseConfig(props) {
+module.exports = function createBaseConfig(props, isServer) {
const {
siteConfig,
outDir,
@@ -34,6 +34,7 @@ module.exports = function createBaseConfig(props) {
.set('@site', siteDir)
.set('@docs', docsDir)
.set('@pages', pagesDir)
+ .set('@build', outDir)
.set('@generated', path.resolve(__dirname, '../core/generated'))
.set('@core', path.resolve(__dirname, '../core'))
.end();
@@ -44,7 +45,8 @@ module.exports = function createBaseConfig(props) {
.loader('babel-loader')
.options({
babelrc: false,
- presets: ['env', 'react']
+ presets: ['env', 'react'],
+ plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import']
});
}
diff --git a/lib/webpack/client.js b/lib/webpack/client.js
new file mode 100644
index 0000000000..b7f21758be
--- /dev/null
+++ b/lib/webpack/client.js
@@ -0,0 +1,20 @@
+const path = require('path');
+const webpackNiceLog = require('webpack-nicelog');
+const {StatsWriterPlugin} = require('webpack-stats-plugin');
+const createBaseConfig = require('./base');
+
+module.exports = function createClientConfig(props) {
+ const config = createBaseConfig(props);
+
+ config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js'));
+
+ // write webpack stats object to a file so we can
+ // programmatically refer to the correct bundle path in Node.js server.
+ config
+ .plugin('stats')
+ .use(StatsWriterPlugin, [{filename: 'client.stats.json'}]);
+
+ config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]);
+
+ return config;
+};
diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js
deleted file mode 100644
index dcdc3a6e51..0000000000
--- a/lib/webpack/dev.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const path = require('path');
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const webpackNiceLog = require('webpack-nicelog');
-const createBaseConfig = require('./base');
-
-module.exports = function createDevConfig(props) {
- const config = createBaseConfig(props);
-
- config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js'));
-
- const {siteConfig} = props;
- config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [
- {
- inject: false,
- hash: true,
- template: path.resolve(__dirname, '../core/devTemplate.ejs'),
- filename: 'index.html',
- title: siteConfig.title
- }
- ]);
- config.plugin('niceLog').use(webpackNiceLog, [{name: 'Development'}]);
-
- return config;
-};
diff --git a/lib/webpack/prod.js b/lib/webpack/server.js
similarity index 59%
rename from lib/webpack/prod.js
rename to lib/webpack/server.js
index 506be0d81f..a562199727 100644
--- a/lib/webpack/prod.js
+++ b/lib/webpack/server.js
@@ -1,15 +1,16 @@
const path = require('path');
-const fs = require('fs');
-const ejs = require('ejs');
const staticSiteGenerator = require('static-site-generator-webpack-plugin');
const webpackNiceLog = require('webpack-nicelog');
const createBaseConfig = require('./base');
module.exports = function createProdConfig(props) {
- const config = createBaseConfig(props);
+ const config = createBaseConfig(props, true);
- config.entry('main').add(path.resolve(__dirname, '../core/prodEntry.js'));
- config.output.libraryTarget('umd');
+ config.entry('main').add(path.resolve(__dirname, '../core/serverEntry.js'));
+
+ config.target('node');
+
+ config.output.filename('server.bundle.js').libraryTarget('commonjs2');
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
config.output.globalObject('this');
@@ -18,25 +19,19 @@ module.exports = function createProdConfig(props) {
// static site generator webpack plugin
const paths = [...docsData, ...pagesData].map(data => data.path);
- const template = ejs.compile(
- fs.readFileSync(
- path.resolve(__dirname, '../core/prodTemplate.ejs'),
- 'utf-8'
- )
- );
config.plugin('siteGenerator').use(staticSiteGenerator, [
{
entry: 'main',
locals: {
- title: siteConfig.title || 'Munseo',
- baseUrl: siteConfig.baseUrl,
- template
+ baseUrl: siteConfig.baseUrl
},
paths
}
]);
// show compilation progress bar and build time
- config.plugin('niceLog').use(webpackNiceLog, [{name: 'Production'}]);
+ config
+ .plugin('niceLog')
+ .use(webpackNiceLog, [{name: 'Server', color: 'yellow'}]);
return config;
};
diff --git a/package.json b/package.json
index 879cbcf08c..6b2a272a39 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,8 @@
"dependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
+ "babel-plugin-dynamic-import-node": "^2.0.0",
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"chalk": "^2.4.1",
@@ -49,7 +51,6 @@
"commander": "^2.16.0",
"connect-history-api-fallback": "^1.5.0",
"css-loader": "^1.0.0",
- "ejs": "^2.6.1",
"front-matter": "^2.3.0",
"fs-extra": "^7.0.0",
"globby": "^8.0.1",
@@ -65,6 +66,8 @@
"prismjs": "^1.15.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
+ "react-helmet": "^5.2.0",
+ "react-loadable": "^5.5.0",
"react-router-config": "^1.0.0-beta.4",
"react-router-dom": "^4.3.1",
"remarkable": "^1.7.1",
@@ -74,7 +77,8 @@
"webpack": "^4.16.3",
"webpack-chain": "^4.8.0",
"webpack-nicelog": "^2.2.1",
- "webpack-serve": "^2.0.2"
+ "webpack-serve": "^2.0.2",
+ "webpack-stats-plugin": "^0.2.1"
},
"engines": {
"node": ">=8"
diff --git a/website/pages/index.js b/website/pages/index.js
index 2d89400073..5dd3022176 100644
--- a/website/pages/index.js
+++ b/website/pages/index.js
@@ -1,5 +1,5 @@
import React from 'react';
-import TicTacToe from './tictactoe';
+import Helmet from 'react-helmet';
import {Link} from 'react-router-dom';
export default class Home extends React.Component {
@@ -12,10 +12,9 @@ export default class Home extends React.Component {
));
return (
+
Available Urls
-
Play some TicTacToe
-
);
}
diff --git a/website/pages/tictactoe.js b/website/pages/tictactoe.js
index b102b7d1fe..e9c93dd8a2 100644
--- a/website/pages/tictactoe.js
+++ b/website/pages/tictactoe.js
@@ -1,4 +1,5 @@
import React from 'react';
+import Helmet from 'react-helmet';
import style from './tictactoe.css';
function Square(props) {
@@ -125,6 +126,7 @@ class Game extends React.Component {
return (
+
this.handleClick(i)} />
diff --git a/yarn.lock b/yarn.lock
index 9d3f1bf739..5492a2cc91 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -723,6 +723,13 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
+babel-plugin-dynamic-import-node@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.0.0.tgz#d6fc3f6c5e3bdc34e49c15faca7ce069755c0a57"
+ dependencies:
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ object.assign "^4.1.0"
+
babel-plugin-istanbul@^4.1.6:
version "4.1.6"
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45"
@@ -740,6 +747,10 @@ babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
+babel-plugin-syntax-dynamic-import@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
+
babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
@@ -1900,7 +1911,7 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
-deep-equal@~1.0.1:
+deep-equal@^1.0.1, deep-equal@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@@ -2136,10 +2147,6 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
-ejs@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0"
-
electron-to-chromium@^1.3.47:
version "1.3.52"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0"
@@ -2490,6 +2497,10 @@ execa@^0.8.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+exenv@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
+
exit@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -5401,7 +5412,7 @@ prompts@^0.1.9:
kleur "^2.0.1"
sisteransi "^0.1.1"
-prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
+prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
dependencies:
@@ -5547,6 +5558,21 @@ react-error-overlay@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
+react-helmet@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7"
+ dependencies:
+ deep-equal "^1.0.1"
+ object-assign "^4.1.1"
+ prop-types "^15.5.4"
+ react-side-effect "^1.1.0"
+
+react-loadable@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4"
+ dependencies:
+ prop-types "^15.5.0"
+
react-router-config@^1.0.0-beta.4:
version "1.0.0-beta.4"
resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-1.0.0-beta.4.tgz#d202496dd0eabdf06cf24eb0793031f6891eef01"
@@ -5574,6 +5600,13 @@ react-router@^4.3.1:
prop-types "^15.6.1"
warning "^4.0.1"
+react-side-effect@^1.1.0:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d"
+ dependencies:
+ exenv "^1.2.1"
+ shallowequal "^1.0.1"
+
react@^16.4.1:
version "16.4.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
@@ -6055,6 +6088,10 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
+shallowequal@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -6970,6 +7007,10 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
+webpack-stats-plugin@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/webpack-stats-plugin/-/webpack-stats-plugin-0.2.1.tgz#1f5bac13fc25d62cbb5fd0ff646757dc802b8595"
+
webpack@^4.16.3:
version "4.16.3"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525"