mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 02:37:59 +02:00
feat(core): upgrade to webpack-dev-server@4 (#5420)
Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
1ce6253cc1
commit
96da25e422
17 changed files with 437 additions and 1081 deletions
|
@ -86,7 +86,7 @@
|
||||||
"@types/semver": "^7.1.0",
|
"@types/semver": "^7.1.0",
|
||||||
"@types/shelljs": "^0.8.6",
|
"@types/shelljs": "^0.8.6",
|
||||||
"@types/wait-on": "^5.2.0",
|
"@types/wait-on": "^5.2.0",
|
||||||
"@types/webpack-dev-server": "^3.11.1",
|
"@types/webpack-dev-server": "^4.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||||
"@typescript-eslint/parser": "^4.18.0",
|
"@typescript-eslint/parser": "^4.18.0",
|
||||||
"concurrently": "^6.2.1",
|
"concurrently": "^6.2.1",
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
"stringify-object": "^3.3.0",
|
"stringify-object": "^3.3.0",
|
||||||
"unist-util-visit": "^2.0.2",
|
"unist-util-visit": "^2.0.2",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^5.40.0"
|
"webpack": "^5.60.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.8",
|
"@docusaurus/types": "2.0.0-beta.8",
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.40.0"
|
"webpack": "^5.60.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.40.0"
|
"webpack": "^5.60.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"webpack": "^5.40.0"
|
"webpack": "^5.60.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"react-waypoint": "^10.1.0",
|
"react-waypoint": "^10.1.0",
|
||||||
"sharp": "^0.29.1",
|
"sharp": "^0.29.1",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"webpack": "^5.40.0"
|
"webpack": "^5.60.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"core-js": "^2.6.5",
|
"core-js": "^2.6.5",
|
||||||
"terser-webpack-plugin": "^5.2.4",
|
"terser-webpack-plugin": "^5.2.4",
|
||||||
"webpack": "^5.40.0",
|
"webpack": "^5.60.0",
|
||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
"workbox-build": "^6.1.1",
|
"workbox-build": "^6.1.1",
|
||||||
"workbox-precaching": "^6.1.1",
|
"workbox-precaching": "^6.1.1",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"joi": "^17.4.2",
|
"joi": "^17.4.2",
|
||||||
"querystring": "0.2.0",
|
"querystring": "0.2.0",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.40.0",
|
"webpack": "^5.60.0",
|
||||||
"webpack-merge": "^5.8.0"
|
"webpack-merge": "^5.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,6 @@
|
||||||
"detect-port": "^1.3.0",
|
"detect-port": "^1.3.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"eta": "^1.12.3",
|
"eta": "^1.12.3",
|
||||||
"express": "^4.17.1",
|
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"github-slugger": "^1.4.0",
|
"github-slugger": "^1.4.0",
|
||||||
|
@ -98,7 +97,7 @@
|
||||||
"postcss": "^8.3.7",
|
"postcss": "^8.3.7",
|
||||||
"postcss-loader": "^6.1.1",
|
"postcss-loader": "^6.1.1",
|
||||||
"prompts": "^2.4.1",
|
"prompts": "^2.4.1",
|
||||||
"react-dev-utils": "^11.0.1",
|
"react-dev-utils": "12.0.0-next.47",
|
||||||
"react-error-overlay": "^6.0.9",
|
"react-error-overlay": "^6.0.9",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-loadable": "^5.5.0",
|
"react-loadable": "^5.5.0",
|
||||||
|
@ -119,9 +118,9 @@
|
||||||
"update-notifier": "^5.1.0",
|
"update-notifier": "^5.1.0",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"wait-on": "^6.0.0",
|
"wait-on": "^6.0.0",
|
||||||
"webpack": "^5.40.0",
|
"webpack": "^5.60.0",
|
||||||
"webpack-bundle-analyzer": "^4.4.2",
|
"webpack-bundle-analyzer": "^4.4.2",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^4.4.0",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"webpackbar": "^5.0.0-3"
|
"webpackbar": "^5.0.0-3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,19 +8,16 @@
|
||||||
import {normalizeUrl, posixPath} from '@docusaurus/utils';
|
import {normalizeUrl, posixPath} from '@docusaurus/utils';
|
||||||
import chalk = require('chalk');
|
import chalk = require('chalk');
|
||||||
import chokidar from 'chokidar';
|
import chokidar from 'chokidar';
|
||||||
import express from 'express';
|
|
||||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {debounce} from 'lodash';
|
import {debounce} from 'lodash';
|
||||||
import openBrowser from 'react-dev-utils/openBrowser';
|
import openBrowser from 'react-dev-utils/openBrowser';
|
||||||
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
|
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
|
||||||
import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';
|
import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
|
||||||
// import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
|
|
||||||
import evalSourceMapMiddleware from '../webpack/react-dev-utils-webpack5/evalSourceMapMiddleware';
|
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import WebpackDevServer from 'webpack-dev-server';
|
import WebpackDevServer from 'webpack-dev-server';
|
||||||
import merge from 'webpack-merge';
|
import merge from 'webpack-merge';
|
||||||
import HotModuleReplacementPlugin from 'webpack/lib/HotModuleReplacementPlugin';
|
|
||||||
import {load} from '../server';
|
import {load} from '../server';
|
||||||
import {StartCLIOptions} from '@docusaurus/types';
|
import {StartCLIOptions} from '@docusaurus/types';
|
||||||
import {STATIC_DIR_NAME} from '../constants';
|
import {STATIC_DIR_NAME} from '../constants';
|
||||||
|
@ -126,6 +123,10 @@ export default async function start(
|
||||||
);
|
);
|
||||||
|
|
||||||
let config: webpack.Configuration = merge(createClientConfig(props), {
|
let config: webpack.Configuration = merge(createClientConfig(props), {
|
||||||
|
infrastructureLogging: {
|
||||||
|
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
|
||||||
|
level: 'warn',
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// Generates an `index.html` file with the <script> injected.
|
// Generates an `index.html` file with the <script> injected.
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
|
@ -141,8 +142,6 @@ export default async function start(
|
||||||
preBodyTags,
|
preBodyTags,
|
||||||
postBodyTags,
|
postBodyTags,
|
||||||
}),
|
}),
|
||||||
// This is necessary to emit hot updates for webpack-dev-server.
|
|
||||||
new HotModuleReplacementPlugin(),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,50 +166,52 @@ export default async function start(
|
||||||
|
|
||||||
// https://webpack.js.org/configuration/dev-server
|
// https://webpack.js.org/configuration/dev-server
|
||||||
const devServerConfig: WebpackDevServer.Configuration = {
|
const devServerConfig: WebpackDevServer.Configuration = {
|
||||||
...{
|
|
||||||
compress: true,
|
compress: true,
|
||||||
clientLogLevel: 'error',
|
hot: cliOptions.hotOnly ? 'only' : true,
|
||||||
hot: true,
|
client: {
|
||||||
hotOnly: cliOptions.hotOnly,
|
progress: true,
|
||||||
// Use 'ws' instead of 'sockjs-node' on server since we're using native
|
overlay: {
|
||||||
// websockets in `webpackHotDevClient`.
|
warnings: false,
|
||||||
transportMode: 'ws',
|
errors: true,
|
||||||
// Prevent a WS client from getting injected as we're already including
|
},
|
||||||
// `webpackHotDevClient`.
|
},
|
||||||
injectClient: false,
|
|
||||||
quiet: true,
|
|
||||||
https: getHttpsConfig(),
|
https: getHttpsConfig(),
|
||||||
headers: {
|
headers: {
|
||||||
'access-control-allow-origin': '*',
|
'access-control-allow-origin': '*',
|
||||||
},
|
},
|
||||||
|
devMiddleware: {
|
||||||
publicPath: baseUrl,
|
publicPath: baseUrl,
|
||||||
watchOptions: {
|
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
|
||||||
poll: cliOptions.poll,
|
stats: 'errors-warnings',
|
||||||
|
},
|
||||||
|
static: {
|
||||||
|
directory: path.resolve(siteDir, STATIC_DIR_NAME),
|
||||||
|
watch: {
|
||||||
|
usePolling: !!cliOptions.poll,
|
||||||
|
|
||||||
// Useful options for our own monorepo using symlinks!
|
// Useful options for our own monorepo using symlinks!
|
||||||
// See https://github.com/webpack/webpack/issues/11612#issuecomment-879259806
|
// See https://github.com/webpack/webpack/issues/11612#issuecomment-879259806
|
||||||
followSymlinks: true,
|
followSymlinks: true,
|
||||||
ignored: /node_modules\/(?!@docusaurus)/,
|
ignored: /node_modules\/(?!@docusaurus)/,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
rewrites: [{from: /\/*/, to: baseUrl}],
|
rewrites: [{from: /\/*/, to: baseUrl}],
|
||||||
},
|
},
|
||||||
disableHostCheck: true,
|
allowedHosts: 'all',
|
||||||
// Disable overlay on browser since we use CRA's overlay error reporting.
|
|
||||||
overlay: false,
|
|
||||||
host,
|
host,
|
||||||
before: (app, server) => {
|
port,
|
||||||
app.use(
|
onBeforeSetupMiddleware: (devServer) => {
|
||||||
baseUrl,
|
|
||||||
express.static(path.resolve(siteDir, STATIC_DIR_NAME)),
|
|
||||||
);
|
|
||||||
// This lets us fetch source contents from webpack for the error overlay.
|
// This lets us fetch source contents from webpack for the error overlay.
|
||||||
app.use(evalSourceMapMiddleware(server));
|
devServer.app.use(
|
||||||
// This lets us open files from the runtime error overlay.
|
evalSourceMapMiddleware(
|
||||||
app.use(errorOverlayMiddleware());
|
// @ts-expect-error: bad types
|
||||||
},
|
devServer,
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const compiler = webpack(config);
|
const compiler = webpack(config);
|
||||||
if (process.env.E2E_TEST) {
|
if (process.env.E2E_TEST) {
|
||||||
compiler.hooks.done.tap('done', (stats) => {
|
compiler.hooks.done.tap('done', (stats) => {
|
||||||
|
@ -223,15 +224,13 @@ export default async function start(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const devServer = new WebpackDevServer(compiler, devServerConfig);
|
const devServer = new WebpackDevServer(devServerConfig, compiler);
|
||||||
devServer.listen(port, host, (err) => {
|
devServer.startCallback(() => {
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
if (cliOptions.open) {
|
if (cliOptions.open) {
|
||||||
openBrowser(openUrl);
|
openBrowser(openUrl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
||||||
process.on(sig as NodeJS.Signals, () => {
|
process.on(sig as NodeJS.Signals, () => {
|
||||||
devServer.close();
|
devServer.close();
|
||||||
|
|
|
@ -19,21 +19,12 @@ export default function createClientConfig(
|
||||||
props: Props,
|
props: Props,
|
||||||
minify: boolean = true,
|
minify: boolean = true,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
|
||||||
const isBuilding = process.argv[2] === 'build';
|
const isBuilding = process.argv[2] === 'build';
|
||||||
const config = createBaseConfig(props, false, minify);
|
const config = createBaseConfig(props, false, minify);
|
||||||
|
|
||||||
const clientConfig = merge(config, {
|
const clientConfig = merge(config, {
|
||||||
// target: 'browserslist', // useless, disabled on purpose (errors on existing sites with no browserslist cfg)
|
// target: 'browserslist', // useless, disabled on purpose (errors on existing sites with no browserslist cfg)
|
||||||
entry: [
|
entry: path.resolve(__dirname, '../client/clientEntry.js'),
|
||||||
// Instead of the default WebpackDevServer client, we use a custom one
|
|
||||||
// like CRA to bring better experience.
|
|
||||||
// note: the one in ./dev is modified to work with Docusaurus
|
|
||||||
// !isProd && require.resolve('react-dev-utils/hotDevServer.js'),
|
|
||||||
!isProd &&
|
|
||||||
require.resolve('./react-dev-utils-webpack5/webpackHotDevClient.js'),
|
|
||||||
path.resolve(__dirname, '../client/clientEntry.js'),
|
|
||||||
].filter(Boolean) as string[],
|
|
||||||
optimization: {
|
optimization: {
|
||||||
// Keep the runtime chunk separated to enable long term caching
|
// Keep the runtime chunk separated to enable long term caching
|
||||||
// https://twitter.com/wSokra/status/969679223278505985
|
// https://twitter.com/wSokra/status/969679223278505985
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
*/
|
*/
|
||||||
import WebpackBar from 'webpackbar';
|
import WebpackBar from 'webpackbar';
|
||||||
import {Compiler} from 'webpack';
|
import {Compiler} from 'webpack';
|
||||||
// import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
|
import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
|
||||||
import formatWebpackMessages from '../react-dev-utils-webpack5/formatWebpackMessages';
|
|
||||||
|
|
||||||
function showError(arr: string[]) {
|
function showError(arr: string[]) {
|
||||||
console.log(`\n\n${arr.join('\n')}`);
|
console.log(`\n\n${arr.join('\n')}`);
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
This is a temporary copy of
|
|
||||||
|
|
||||||
CRA / react-dev-utils does not support Webpack 5 yet
|
|
||||||
|
|
||||||
https://github.com/facebook/create-react-app/issues/9994
|
|
||||||
|
|
||||||
This folder is a temporary copy of some react-dev-utils code to which we made some changes to support Webpack 5 without warnings
|
|
||||||
|
|
||||||
TODO remove this folder once Webpack 5 is supported (https://github.com/facebook/create-react-app/issues/9994)
|
|
||||||
|
|
||||||
The comment `// modified for Docusaurus` is added near the modified elements
|
|
|
@ -1,57 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
/* eslint-disable */
|
|
||||||
/*
|
|
||||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
|
||||||
* the above copyright header must be preserved for license compliance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Implementation based on comment: https://github.com/facebook/create-react-app/issues/9994#issuecomment-811289191
|
|
||||||
*/
|
|
||||||
|
|
||||||
function base64SourceMap(source) {
|
|
||||||
const base64 = Buffer.from(JSON.stringify(source.map()), 'utf8').toString(
|
|
||||||
'base64',
|
|
||||||
);
|
|
||||||
return `data:application/json;charset=utf-8;base64,${base64}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// modified for Docusaurus => remove webpack 5 deprecation warnings
|
|
||||||
// See https://github.com/facebook/create-react-app/issues/9994#issuecomment-811289191
|
|
||||||
function getSourceById(server, id) {
|
|
||||||
const module = Array.from(server._stats.compilation.modules).find(
|
|
||||||
(m) => server._stats.compilation.chunkGraph.getModuleId(m) == id,
|
|
||||||
);
|
|
||||||
return module.originalSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Middleware responsible for retrieving a generated source
|
|
||||||
* Receives a webpack internal url: "webpack-internal:///<module-id>"
|
|
||||||
* Returns a generated source: "<source-text><sourceMappingURL><sourceURL>"
|
|
||||||
*
|
|
||||||
* Based on EvalSourceMapDevToolModuleTemplatePlugin.js
|
|
||||||
*/
|
|
||||||
module.exports = function createEvalSourceMapMiddleware(server) {
|
|
||||||
return function handleWebpackInternalMiddleware(req, res, next) {
|
|
||||||
if (req.url.startsWith('/__get-internal-source')) {
|
|
||||||
const fileName = req.query.fileName;
|
|
||||||
const id = fileName.match(/webpack-internal:\/\/\/(.+)/)[1];
|
|
||||||
if (!id || !server._stats) {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = getSourceById(server, id);
|
|
||||||
const sourceMapURL = `//# sourceMappingURL=${base64SourceMap(source)}`;
|
|
||||||
const sourceURL = `//# sourceURL=webpack-internal:///${module.id}`;
|
|
||||||
res.end(`${source.source()}\n${sourceMapURL}\n${sourceURL}`);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,138 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
/* eslint-disable */
|
|
||||||
/*
|
|
||||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
|
||||||
* the above copyright header must be preserved for license compliance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Implementation has been copied from https://github.com/facebook/create-react-app/pull/10656
|
|
||||||
*/
|
|
||||||
|
|
||||||
const friendlySyntaxErrorLabel = 'Syntax error:';
|
|
||||||
|
|
||||||
function isLikelyASyntaxError(message) {
|
|
||||||
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleans up webpack error messages.
|
|
||||||
function formatMessage(message) {
|
|
||||||
let lines = [];
|
|
||||||
|
|
||||||
// modified for Docusaurus => see https://github.com/facebook/create-react-app/pull/10656
|
|
||||||
if (typeof message === 'string') {
|
|
||||||
lines = message.split('\n');
|
|
||||||
} else if ('message' in message) {
|
|
||||||
lines = message['message'].split('\n');
|
|
||||||
} else if (Array.isArray(message)) {
|
|
||||||
message.forEach((message) => {
|
|
||||||
if ('message' in message) {
|
|
||||||
lines = message['message'].split('\n');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip webpack-added headers off errors/warnings
|
|
||||||
// https://github.com/webpack/webpack/blob/main/lib/ModuleError.js
|
|
||||||
lines = lines.filter((line) => !/Module [A-z ]+\(from/.test(line));
|
|
||||||
|
|
||||||
// Transform parsing error into syntax error
|
|
||||||
// TODO: move this to our ESLint formatter?
|
|
||||||
lines = lines.map((line) => {
|
|
||||||
const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec(
|
|
||||||
line,
|
|
||||||
);
|
|
||||||
if (!parsingError) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
const [, errorLine, errorColumn, errorMessage] = parsingError;
|
|
||||||
return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;
|
|
||||||
});
|
|
||||||
|
|
||||||
message = lines.join('\n');
|
|
||||||
// Smoosh syntax errors (commonly found in CSS)
|
|
||||||
message = message.replace(
|
|
||||||
/SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g,
|
|
||||||
`${friendlySyntaxErrorLabel} $3 ($1:$2)\n`,
|
|
||||||
);
|
|
||||||
// Clean up export errors
|
|
||||||
message = message.replace(
|
|
||||||
/^.*export '(.+?)' was not found in '(.+?)'.*$/gm,
|
|
||||||
`Attempted import error: '$1' is not exported from '$2'.`,
|
|
||||||
);
|
|
||||||
message = message.replace(
|
|
||||||
/^.*export 'default' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
|
|
||||||
`Attempted import error: '$2' does not contain a default export (imported as '$1').`,
|
|
||||||
);
|
|
||||||
message = message.replace(
|
|
||||||
/^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
|
|
||||||
`Attempted import error: '$1' is not exported from '$3' (imported as '$2').`,
|
|
||||||
);
|
|
||||||
lines = message.split('\n');
|
|
||||||
|
|
||||||
// Remove leading newline
|
|
||||||
if (lines.length > 2 && lines[1].trim() === '') {
|
|
||||||
lines.splice(1, 1);
|
|
||||||
}
|
|
||||||
// Clean up file name
|
|
||||||
lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1');
|
|
||||||
|
|
||||||
// Cleans up verbose "module not found" messages for files and packages.
|
|
||||||
if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
|
|
||||||
lines = [
|
|
||||||
lines[0],
|
|
||||||
lines[1]
|
|
||||||
.replace('Error: ', '')
|
|
||||||
.replace('Module not found: Cannot find file:', 'Cannot find file:'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add helpful message for users trying to use Sass for the first time
|
|
||||||
if (lines[1] && lines[1].match(/Cannot find module.+node-sass/)) {
|
|
||||||
lines[1] = 'To import Sass files, you first need to install node-sass.\n';
|
|
||||||
lines[1] +=
|
|
||||||
'Run `npm install node-sass` or `yarn add node-sass` inside your workspace.';
|
|
||||||
}
|
|
||||||
|
|
||||||
message = lines.join('\n');
|
|
||||||
// Internal stacks are generally useless so we strip them... with the
|
|
||||||
// exception of stacks containing `webpack:` because they're normally
|
|
||||||
// from user code generated by webpack. For more information see
|
|
||||||
// https://github.com/facebook/create-react-app/pull/1050
|
|
||||||
message = message.replace(
|
|
||||||
/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm,
|
|
||||||
'',
|
|
||||||
); // at ... ...:x:y
|
|
||||||
message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ''); // at <anonymous>
|
|
||||||
lines = message.split('\n');
|
|
||||||
|
|
||||||
// Remove duplicated newlines
|
|
||||||
lines = lines.filter(
|
|
||||||
(line, index, arr) =>
|
|
||||||
index === 0 ||
|
|
||||||
line.trim() !== '' ||
|
|
||||||
line.trim() !== arr[index - 1].trim(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Reassemble the message
|
|
||||||
message = lines.join('\n');
|
|
||||||
return message.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatWebpackMessages(json) {
|
|
||||||
const formattedErrors = json.errors.map(formatMessage);
|
|
||||||
const formattedWarnings = json.warnings.map(formatMessage);
|
|
||||||
const result = {errors: formattedErrors, warnings: formattedWarnings};
|
|
||||||
if (result.errors.some(isLikelyASyntaxError)) {
|
|
||||||
// If there are any syntax errors, show just them.
|
|
||||||
result.errors = result.errors.filter(isLikelyASyntaxError);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = formatWebpackMessages;
|
|
|
@ -1,285 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
/* eslint-disable */
|
|
||||||
/*
|
|
||||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
|
||||||
* the above copyright header must be preserved for license compliance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This alternative WebpackDevServer combines the functionality of:
|
|
||||||
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
|
|
||||||
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
|
|
||||||
|
|
||||||
// It only supports their simplest configuration (hot updates on same server).
|
|
||||||
// It makes some opinionated choices on top, like adding a syntax error overlay
|
|
||||||
// that looks similar to our console output. The error overlay is inspired by:
|
|
||||||
// https://github.com/glenjamin/webpack-hot-middleware
|
|
||||||
|
|
||||||
var stripAnsi = require('strip-ansi');
|
|
||||||
var url = require('url');
|
|
||||||
var launchEditorEndpoint = require('react-dev-utils/launchEditorEndpoint'); // modified for Docusaurus
|
|
||||||
var formatWebpackMessages = require('./formatWebpackMessages');
|
|
||||||
var ErrorOverlay = require('react-error-overlay');
|
|
||||||
|
|
||||||
ErrorOverlay.setEditorHandler(function editorHandler(errorLocation) {
|
|
||||||
// Keep this sync with errorOverlayMiddleware.js
|
|
||||||
fetch(
|
|
||||||
launchEditorEndpoint +
|
|
||||||
'?fileName=' +
|
|
||||||
window.encodeURIComponent(errorLocation.fileName) +
|
|
||||||
'&lineNumber=' +
|
|
||||||
window.encodeURIComponent(errorLocation.lineNumber || 1) +
|
|
||||||
'&colNumber=' +
|
|
||||||
window.encodeURIComponent(errorLocation.colNumber || 1),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// We need to keep track of if there has been a runtime error.
|
|
||||||
// Essentially, we cannot guarantee application state was not corrupted by the
|
|
||||||
// runtime error. To prevent confusing behavior, we forcibly reload the entire
|
|
||||||
// application. This is handled below when we are notified of a compile (code
|
|
||||||
// change).
|
|
||||||
// See https://github.com/facebook/create-react-app/issues/3096
|
|
||||||
var hadRuntimeError = false;
|
|
||||||
ErrorOverlay.startReportingRuntimeErrors({
|
|
||||||
onError: function () {
|
|
||||||
hadRuntimeError = true;
|
|
||||||
},
|
|
||||||
filename: '/static/js/bundle.js',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (module.hot && typeof module.hot.dispose === 'function') {
|
|
||||||
module.hot.dispose(function () {
|
|
||||||
// TODO: why do we need this?
|
|
||||||
ErrorOverlay.stopReportingRuntimeErrors();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to WebpackDevServer via a socket.
|
|
||||||
var connection = new WebSocket(
|
|
||||||
url.format({
|
|
||||||
protocol: window.location.protocol === 'https:' ? 'wss' : 'ws',
|
|
||||||
// modified for Docusaurus => avoid "ReferenceError: process is not defined"
|
|
||||||
hostname: window.location.hostname,
|
|
||||||
port: window.location.port,
|
|
||||||
// Hardcoded in WebpackDevServer
|
|
||||||
pathname: '/sockjs-node',
|
|
||||||
slashes: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Unlike WebpackDevServer client, we won't try to reconnect
|
|
||||||
// to avoid spamming the console. Disconnect usually happens
|
|
||||||
// when developer stops the server.
|
|
||||||
connection.onclose = function () {
|
|
||||||
if (typeof console !== 'undefined' && typeof console.info === 'function') {
|
|
||||||
console.info(
|
|
||||||
'The development server has disconnected.\nRefresh the page if necessary.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remember some state related to hot module replacement.
|
|
||||||
var isFirstCompilation = true;
|
|
||||||
var mostRecentCompilationHash = null;
|
|
||||||
var hasCompileErrors = false;
|
|
||||||
|
|
||||||
function clearOutdatedErrors() {
|
|
||||||
// Clean up outdated compile errors, if any.
|
|
||||||
if (typeof console !== 'undefined' && typeof console.clear === 'function') {
|
|
||||||
if (hasCompileErrors) {
|
|
||||||
console.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Successful compilation.
|
|
||||||
function handleSuccess() {
|
|
||||||
clearOutdatedErrors();
|
|
||||||
|
|
||||||
var isHotUpdate = !isFirstCompilation;
|
|
||||||
isFirstCompilation = false;
|
|
||||||
hasCompileErrors = false;
|
|
||||||
|
|
||||||
// Attempt to apply hot updates or reload.
|
|
||||||
if (isHotUpdate) {
|
|
||||||
tryApplyUpdates(function onHotUpdateSuccess() {
|
|
||||||
// Only dismiss it when we're sure it's a hot update.
|
|
||||||
// Otherwise it would flicker right before the reload.
|
|
||||||
tryDismissErrorOverlay();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compilation with warnings (e.g. ESLint).
|
|
||||||
function handleWarnings(warnings) {
|
|
||||||
clearOutdatedErrors();
|
|
||||||
|
|
||||||
var isHotUpdate = !isFirstCompilation;
|
|
||||||
isFirstCompilation = false;
|
|
||||||
hasCompileErrors = false;
|
|
||||||
|
|
||||||
function printWarnings() {
|
|
||||||
// Print warnings to the console.
|
|
||||||
var formatted = formatWebpackMessages({
|
|
||||||
warnings: warnings,
|
|
||||||
errors: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
|
||||||
for (var i = 0; i < formatted.warnings.length; i++) {
|
|
||||||
if (i === 5) {
|
|
||||||
console.warn(
|
|
||||||
'There were more warnings in other files.\n' +
|
|
||||||
'You can find a complete log in the terminal.',
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
console.warn(stripAnsi(formatted.warnings[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printWarnings();
|
|
||||||
|
|
||||||
// Attempt to apply hot updates or reload.
|
|
||||||
if (isHotUpdate) {
|
|
||||||
tryApplyUpdates(function onSuccessfulHotUpdate() {
|
|
||||||
// Only dismiss it when we're sure it's a hot update.
|
|
||||||
// Otherwise it would flicker right before the reload.
|
|
||||||
tryDismissErrorOverlay();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compilation with errors (e.g. syntax error or missing modules).
|
|
||||||
function handleErrors(errors) {
|
|
||||||
clearOutdatedErrors();
|
|
||||||
|
|
||||||
isFirstCompilation = false;
|
|
||||||
hasCompileErrors = true;
|
|
||||||
|
|
||||||
// "Massage" webpack messages.
|
|
||||||
var formatted = formatWebpackMessages({
|
|
||||||
errors: errors,
|
|
||||||
warnings: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only show the first error.
|
|
||||||
ErrorOverlay.reportBuildError(formatted.errors[0]);
|
|
||||||
|
|
||||||
// Also log them to the console.
|
|
||||||
if (typeof console !== 'undefined' && typeof console.error === 'function') {
|
|
||||||
for (var i = 0; i < formatted.errors.length; i++) {
|
|
||||||
console.error(stripAnsi(formatted.errors[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not attempt to reload now.
|
|
||||||
// We will reload on next success instead.
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryDismissErrorOverlay() {
|
|
||||||
if (!hasCompileErrors) {
|
|
||||||
ErrorOverlay.dismissBuildError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is a newer version of the code available.
|
|
||||||
function handleAvailableHash(hash) {
|
|
||||||
// Update last known compilation hash.
|
|
||||||
mostRecentCompilationHash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle messages from the server.
|
|
||||||
connection.onmessage = function (e) {
|
|
||||||
var message = JSON.parse(e.data);
|
|
||||||
switch (message.type) {
|
|
||||||
case 'hash':
|
|
||||||
handleAvailableHash(message.data);
|
|
||||||
break;
|
|
||||||
case 'still-ok':
|
|
||||||
case 'ok':
|
|
||||||
handleSuccess();
|
|
||||||
break;
|
|
||||||
case 'content-changed':
|
|
||||||
// Triggered when a file from `contentBase` changed.
|
|
||||||
window.location.reload();
|
|
||||||
break;
|
|
||||||
case 'warnings':
|
|
||||||
handleWarnings(message.data);
|
|
||||||
break;
|
|
||||||
case 'errors':
|
|
||||||
handleErrors(message.data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Is there a newer version of this code available?
|
|
||||||
function isUpdateAvailable() {
|
|
||||||
/* globals __webpack_hash__ */
|
|
||||||
// __webpack_hash__ is the hash of the current compilation.
|
|
||||||
// It's a global variable injected by webpack.
|
|
||||||
return mostRecentCompilationHash !== __webpack_hash__;
|
|
||||||
}
|
|
||||||
|
|
||||||
// webpack disallows updates in other states.
|
|
||||||
function canApplyUpdates() {
|
|
||||||
return module.hot.status() === 'idle';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to update code on the fly, fall back to a hard reload.
|
|
||||||
function tryApplyUpdates(onHotUpdateSuccess) {
|
|
||||||
if (!module.hot) {
|
|
||||||
// HotModuleReplacementPlugin is not in webpack configuration.
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isUpdateAvailable() || !canApplyUpdates()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleApplyUpdates(err, updatedModules) {
|
|
||||||
// NOTE: This var is injected by Webpack's DefinePlugin, and is a boolean instead of string.
|
|
||||||
// const hasReactRefresh = process.env.FAST_REFRESH;
|
|
||||||
const hasReactRefresh = true; // modified for Docusaurus => avoid "ReferenceError: process is not defined"
|
|
||||||
const wantsForcedReload = err || !updatedModules || hadRuntimeError;
|
|
||||||
// React refresh can handle hot-reloading over errors.
|
|
||||||
if (!hasReactRefresh && wantsForcedReload) {
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof onHotUpdateSuccess === 'function') {
|
|
||||||
// Maybe we want to do something.
|
|
||||||
onHotUpdateSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUpdateAvailable()) {
|
|
||||||
// While we were updating, there was a new update! Do it again.
|
|
||||||
tryApplyUpdates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://webpack.github.io/docs/hot-module-replacement.html#check
|
|
||||||
var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);
|
|
||||||
|
|
||||||
// // webpack 2 returns a Promise instead of invoking a callback
|
|
||||||
if (result && result.then) {
|
|
||||||
result.then(
|
|
||||||
function (updatedModules) {
|
|
||||||
handleApplyUpdates(null, updatedModules);
|
|
||||||
},
|
|
||||||
function (err) {
|
|
||||||
handleApplyUpdates(err, null);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue