feat(core): upgrade to webpack-dev-server@4 (#5420)

Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
Avi Vahl 2021-10-28 19:06:20 +03:00 committed by GitHub
parent 1ce6253cc1
commit 96da25e422
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 437 additions and 1081 deletions

View file

@ -86,7 +86,7 @@
"@types/semver": "^7.1.0",
"@types/shelljs": "^0.8.6",
"@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/parser": "^4.18.0",
"concurrently": "^6.2.1",

View file

@ -35,7 +35,7 @@
"stringify-object": "^3.3.0",
"unist-util-visit": "^2.0.2",
"url-loader": "^4.1.1",
"webpack": "^5.40.0"
"webpack": "^5.60.0"
},
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.8",

View file

@ -35,7 +35,7 @@
"remark-admonitions": "^1.2.1",
"tslib": "^2.3.1",
"utility-types": "^3.10.0",
"webpack": "^5.40.0"
"webpack": "^5.60.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -45,7 +45,7 @@
"shelljs": "^0.8.4",
"tslib": "^2.3.1",
"utility-types": "^3.10.0",
"webpack": "^5.40.0"
"webpack": "^5.60.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -27,7 +27,7 @@
"lodash": "^4.17.20",
"remark-admonitions": "^1.2.1",
"tslib": "^2.3.1",
"webpack": "^5.40.0"
"webpack": "^5.60.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -29,7 +29,7 @@
"react-waypoint": "^10.1.0",
"sharp": "^0.29.1",
"tslib": "^2.3.1",
"webpack": "^5.40.0"
"webpack": "^5.60.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -24,7 +24,7 @@
"clsx": "^1.1.1",
"core-js": "^2.6.5",
"terser-webpack-plugin": "^5.2.4",
"webpack": "^5.40.0",
"webpack": "^5.60.0",
"webpack-merge": "^5.7.3",
"workbox-build": "^6.1.1",
"workbox-precaching": "^6.1.1",

View file

@ -20,7 +20,7 @@
"joi": "^17.4.2",
"querystring": "0.2.0",
"utility-types": "^3.10.0",
"webpack": "^5.40.0",
"webpack": "^5.60.0",
"webpack-merge": "^5.8.0"
}
}

View file

@ -80,7 +80,6 @@
"detect-port": "^1.3.0",
"escape-html": "^1.0.3",
"eta": "^1.12.3",
"express": "^4.17.1",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.0",
"github-slugger": "^1.4.0",
@ -98,7 +97,7 @@
"postcss": "^8.3.7",
"postcss-loader": "^6.1.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-helmet": "^6.1.0",
"react-loadable": "^5.5.0",
@ -119,9 +118,9 @@
"update-notifier": "^5.1.0",
"url-loader": "^4.1.1",
"wait-on": "^6.0.0",
"webpack": "^5.40.0",
"webpack": "^5.60.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-dev-server": "^3.11.2",
"webpack-dev-server": "^4.4.0",
"webpack-merge": "^5.8.0",
"webpackbar": "^5.0.0-3"
},

View file

@ -8,19 +8,16 @@
import {normalizeUrl, posixPath} from '@docusaurus/utils';
import chalk = require('chalk');
import chokidar from 'chokidar';
import express from 'express';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import path from 'path';
import {debounce} from 'lodash';
import openBrowser from 'react-dev-utils/openBrowser';
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';
// import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
import evalSourceMapMiddleware from '../webpack/react-dev-utils-webpack5/evalSourceMapMiddleware';
import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import merge from 'webpack-merge';
import HotModuleReplacementPlugin from 'webpack/lib/HotModuleReplacementPlugin';
import {load} from '../server';
import {StartCLIOptions} from '@docusaurus/types';
import {STATIC_DIR_NAME} from '../constants';
@ -126,6 +123,10 @@ export default async function start(
);
let config: webpack.Configuration = merge(createClientConfig(props), {
infrastructureLogging: {
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
level: 'warn',
},
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
@ -141,8 +142,6 @@ export default async function start(
preBodyTags,
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
const devServerConfig: WebpackDevServer.Configuration = {
...{
compress: true,
clientLogLevel: 'error',
hot: true,
hotOnly: cliOptions.hotOnly,
// Use 'ws' instead of 'sockjs-node' on server since we're using native
// websockets in `webpackHotDevClient`.
transportMode: 'ws',
// Prevent a WS client from getting injected as we're already including
// `webpackHotDevClient`.
injectClient: false,
quiet: true,
hot: cliOptions.hotOnly ? 'only' : true,
client: {
progress: true,
overlay: {
warnings: false,
errors: true,
},
},
https: getHttpsConfig(),
headers: {
'access-control-allow-origin': '*',
},
devMiddleware: {
publicPath: baseUrl,
watchOptions: {
poll: cliOptions.poll,
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
stats: 'errors-warnings',
},
static: {
directory: path.resolve(siteDir, STATIC_DIR_NAME),
watch: {
usePolling: !!cliOptions.poll,
// Useful options for our own monorepo using symlinks!
// See https://github.com/webpack/webpack/issues/11612#issuecomment-879259806
followSymlinks: true,
ignored: /node_modules\/(?!@docusaurus)/,
},
},
historyApiFallback: {
rewrites: [{from: /\/*/, to: baseUrl}],
},
disableHostCheck: true,
// Disable overlay on browser since we use CRA's overlay error reporting.
overlay: false,
allowedHosts: 'all',
host,
before: (app, server) => {
app.use(
baseUrl,
express.static(path.resolve(siteDir, STATIC_DIR_NAME)),
);
port,
onBeforeSetupMiddleware: (devServer) => {
// This lets us fetch source contents from webpack for the error overlay.
app.use(evalSourceMapMiddleware(server));
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
},
devServer.app.use(
evalSourceMapMiddleware(
// @ts-expect-error: bad types
devServer,
),
);
},
};
const compiler = webpack(config);
if (process.env.E2E_TEST) {
compiler.hooks.done.tap('done', (stats) => {
@ -223,15 +224,13 @@ export default async function start(
});
}
const devServer = new WebpackDevServer(compiler, devServerConfig);
devServer.listen(port, host, (err) => {
if (err) {
console.log(err);
}
const devServer = new WebpackDevServer(devServerConfig, compiler);
devServer.startCallback(() => {
if (cliOptions.open) {
openBrowser(openUrl);
}
});
['SIGINT', 'SIGTERM'].forEach((sig) => {
process.on(sig as NodeJS.Signals, () => {
devServer.close();

View file

@ -19,21 +19,12 @@ export default function createClientConfig(
props: Props,
minify: boolean = true,
): Configuration {
const isProd = process.env.NODE_ENV === 'production';
const isBuilding = process.argv[2] === 'build';
const config = createBaseConfig(props, false, minify);
const clientConfig = merge(config, {
// target: 'browserslist', // useless, disabled on purpose (errors on existing sites with no browserslist cfg)
entry: [
// 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[],
entry: path.resolve(__dirname, '../client/clientEntry.js'),
optimization: {
// Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985

View file

@ -6,8 +6,7 @@
*/
import WebpackBar from 'webpackbar';
import {Compiler} from 'webpack';
// import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
import formatWebpackMessages from '../react-dev-utils-webpack5/formatWebpackMessages';
import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
function showError(arr: string[]) {
console.log(`\n\n${arr.join('\n')}`);

View file

@ -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

View file

@ -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();
}
};
};

View file

@ -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;

View file

@ -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);
},
);
}
}

899
yarn.lock

File diff suppressed because it is too large Load diff