Skip to content

Commit 45b040d

Browse files
refactor: loading packages (#2718)
1 parent 21bbab5 commit 45b040d

File tree

3 files changed

+88
-55
lines changed

3 files changed

+88
-55
lines changed

packages/serve/src/startDevServer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default async function startDevServer(
2727
// eslint-disable-next-line node/no-extraneous-require
2828
devServerVersion = require("webpack-dev-server/package.json").version;
2929
// eslint-disable-next-line node/no-extraneous-require
30-
Server = require("webpack-dev-server/lib/Server");
30+
Server = require("webpack-dev-server");
3131
} catch (err) {
3232
logger.error(
3333
`You need to install 'webpack-dev-server' for running 'webpack serve'.\n${err}`,

packages/webpack-cli/lib/webpack-cli.js

+84-53
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,70 @@ class WebpackCLI {
2525
});
2626
}
2727

28+
async tryRequireThenImport(module, handleError = true) {
29+
let result;
30+
31+
try {
32+
result = require(module);
33+
} catch (error) {
34+
let previousModuleCompile;
35+
36+
// TODO Workaround https://github.com/zertosh/v8-compile-cache/issues/30
37+
if (this._originalModuleCompile) {
38+
previousModuleCompile = Module.prototype._compile;
39+
40+
Module.prototype._compile = this._originalModuleCompile;
41+
}
42+
43+
const dynamicImportLoader = this.utils.dynamicImportLoader();
44+
45+
if (this._originalModuleCompile) {
46+
Module.prototype._compile = previousModuleCompile;
47+
}
48+
49+
if (
50+
(error.code === "ERR_REQUIRE_ESM" ||
51+
process.env.WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG) &&
52+
pathToFileURL &&
53+
dynamicImportLoader
54+
) {
55+
const urlForConfig = pathToFileURL(module);
56+
57+
result = await dynamicImportLoader(urlForConfig);
58+
result = result.default;
59+
60+
return result;
61+
}
62+
63+
if (handleError) {
64+
this.logger.error(error);
65+
process.exit(2);
66+
} else {
67+
throw error;
68+
}
69+
}
70+
71+
// For babel/typescript
72+
if (result.default) {
73+
result = result.default;
74+
}
75+
76+
return result;
77+
}
78+
79+
loadJSONFile(pathToFile) {
80+
let result;
81+
82+
try {
83+
result = require(pathToFile);
84+
} catch (error) {
85+
this.logger.error(error);
86+
process.exit(2);
87+
}
88+
89+
return result;
90+
}
91+
2892
async makeCommand(commandOptions, options, action) {
2993
const alreadyLoaded = this.program.commands.find(
3094
(command) =>
@@ -828,17 +892,13 @@ class WebpackCLI {
828892
let loadedCommand;
829893

830894
try {
831-
loadedCommand = require(pkg);
895+
loadedCommand = await this.tryRequireThenImport(pkg, false);
832896
} catch (error) {
833897
// Ignore, command is not installed
834898

835899
return;
836900
}
837901

838-
if (loadedCommand.default) {
839-
loadedCommand = loadedCommand.default;
840-
}
841-
842902
let command;
843903

844904
try {
@@ -974,7 +1034,9 @@ class WebpackCLI {
9741034
}
9751035

9761036
try {
977-
const { name, version } = require(`${foundCommand.pkg}/package.json`);
1037+
const { name, version } = this.loadJSONFile(
1038+
`${foundCommand.pkg}/package.json`,
1039+
);
9781040

9791041
this.logger.raw(`${name} ${version}`);
9801042
} catch (e) {
@@ -986,14 +1048,14 @@ class WebpackCLI {
9861048
}
9871049
}
9881050

989-
const pkgJSON = require("../package.json");
1051+
const pkgJSON = this.loadJSONFile("../package.json");
9901052

9911053
this.logger.raw(`webpack ${this.webpack.version}`);
9921054
this.logger.raw(`webpack-cli ${pkgJSON.version}`);
9931055

9941056
if (this.utils.packageExists("webpack-dev-server")) {
9951057
// eslint-disable-next-line
996-
const { version } = require("webpack-dev-server/package.json");
1058+
const { version } = this.loadJSONFile("webpack-dev-server/package.json");
9971059

9981060
this.logger.raw(`webpack-dev-server ${version}`);
9991061
}
@@ -1472,40 +1534,7 @@ class WebpackCLI {
14721534
let options;
14731535

14741536
try {
1475-
try {
1476-
options = require(configPath);
1477-
} catch (error) {
1478-
let previousModuleCompile;
1479-
1480-
// TODO Workaround https://github.com/zertosh/v8-compile-cache/issues/30
1481-
if (this._originalModuleCompile) {
1482-
previousModuleCompile = Module.prototype._compile;
1483-
1484-
Module.prototype._compile = this._originalModuleCompile;
1485-
}
1486-
1487-
const dynamicImportLoader = this.utils.dynamicImportLoader();
1488-
1489-
if (this._originalModuleCompile) {
1490-
Module.prototype._compile = previousModuleCompile;
1491-
}
1492-
1493-
if (
1494-
(error.code === "ERR_REQUIRE_ESM" ||
1495-
process.env.WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG) &&
1496-
pathToFileURL &&
1497-
dynamicImportLoader
1498-
) {
1499-
const urlForConfig = pathToFileURL(configPath);
1500-
1501-
options = await dynamicImportLoader(urlForConfig);
1502-
options = options.default;
1503-
1504-
return { options, path: configPath };
1505-
}
1506-
1507-
throw error;
1508-
}
1537+
options = await this.tryRequireThenImport(configPath, false);
15091538
} catch (error) {
15101539
this.logger.error(`Failed to load '${configPath}' config`);
15111540

@@ -1518,10 +1547,6 @@ class WebpackCLI {
15181547
process.exit(2);
15191548
}
15201549

1521-
if (options.default) {
1522-
options = options.default;
1523-
}
1524-
15251550
return { options, path: configPath };
15261551
};
15271552

@@ -1660,7 +1685,7 @@ class WebpackCLI {
16601685
}
16611686

16621687
if (options.merge) {
1663-
const { merge } = require("webpack-merge");
1688+
const merge = await this.tryRequireThenImport("webpack-merge");
16641689

16651690
// we can only merge when there are multiple configurations
16661691
// either by passing multiple configs by flags or passing a
@@ -1968,13 +1993,13 @@ class WebpackCLI {
19681993
}
19691994

19701995
async applyCLIPlugin(config, cliOptions) {
1996+
const CLIPlugin = await this.tryRequireThenImport("./plugins/CLIPlugin");
1997+
19711998
const addCLIPlugin = (configOptions) => {
19721999
if (!configOptions.plugins) {
19732000
configOptions.plugins = [];
19742001
}
19752002

1976-
const CLIPlugin = require("./plugins/CLIPlugin");
1977-
19782003
configOptions.plugins.unshift(
19792004
new CLIPlugin({
19802005
configPath: config.path.get(configOptions),
@@ -1988,6 +2013,7 @@ class WebpackCLI {
19882013

19892014
return configOptions;
19902015
};
2016+
19912017
config.options = Array.isArray(config.options)
19922018
? config.options.map((options) => addCLIPlugin(options))
19932019
: addCLIPlugin(config.options);
@@ -2059,6 +2085,14 @@ class WebpackCLI {
20592085
async buildCommand(options, isWatchCommand) {
20602086
let compiler;
20612087

2088+
let createJsonStringifyStream;
2089+
2090+
if (options.json) {
2091+
const jsonExt = await this.tryRequireThenImport("@discoveryjs/json-ext");
2092+
2093+
createJsonStringifyStream = jsonExt.stringifyStream;
2094+
}
2095+
20622096
const callback = (error, stats) => {
20632097
if (error) {
20642098
this.logger.error(error);
@@ -2090,10 +2124,7 @@ class WebpackCLI {
20902124
statsOptions.colors = statsOptions.children.some((child) => child.colors);
20912125
}
20922126

2093-
if (options.json) {
2094-
const {
2095-
stringifyStream: createJsonStringifyStream,
2096-
} = require("@discoveryjs/json-ext");
2127+
if (options.json && createJsonStringifyStream) {
20972128
const handleWriteError = (error) => {
20982129
this.logger.error(error);
20992130
process.exit(2);

test/plugin/plugin.test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ const dataForTests = (rootAssetsPath) => ({
2020

2121
describe("plugin command", () => {
2222
it("should ask the plugin name when invoked", async () => {
23-
const { stdout, stderr } = await runPromptWithAnswers(__dirname, ["plugin"]);
23+
const assetsPath = await uniqueDirectoryForTest();
24+
const { stdout, stderr } = await runPromptWithAnswers(assetsPath, ["plugin"]);
25+
2426
expect(stdout).toBeTruthy();
2527
expect(stderr).toBeFalsy();
2628
expect(normalizeStdout(stdout)).toContain(firstPrompt);

0 commit comments

Comments
 (0)