fix: properly handle external presets for universal target

This commit is contained in:
Alexander Akait 2025-11-12 09:43:04 +03:00 committed by GitHub
parent 3cd6b975c9
commit 1328dcb024
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 64 additions and 18 deletions

View File

@ -110,7 +110,15 @@ class WebpackOptionsApply extends OptionsApply {
if (options.externalsPresets.node) {
const NodeTargetPlugin = require("./node/NodeTargetPlugin");
new NodeTargetPlugin().apply(compiler);
// Some older versions of Node.js don't support all built-in modules via import, only via `require`,
// but шt seems like there shouldn't be a warning here since these versions are rarely used in real applications
new NodeTargetPlugin(
options.output.module &&
compiler.platform.node === null &&
compiler.platform.web === null
? "module-import"
: "node-commonjs"
).apply(compiler);
// Handle external CSS `@import` and `url()`
if (options.experiments.css) {

View File

@ -411,7 +411,10 @@ const applyWebpackOptionsDefaults = (options, compilerIndex) => {
applyExternalsPresetsDefaults(options.externalsPresets, {
targetProperties,
buildHttp: Boolean(options.experiments.buildHttp)
buildHttp: Boolean(options.experiments.buildHttp),
outputModule:
/** @type {NonNullable<WebpackOptionsNormalized["output"]["module"]>} */
(options.output.module)
});
applyLoaderDefaults(
@ -1551,35 +1554,47 @@ const applyOutputDefaults = (
* @param {object} options options
* @param {TargetProperties | false} options.targetProperties target properties
* @param {boolean} options.buildHttp buildHttp experiment enabled
* @param {boolean} options.outputModule is output type is module
* @returns {void}
*/
const applyExternalsPresetsDefaults = (
externalsPresets,
{ targetProperties, buildHttp }
{ targetProperties, buildHttp, outputModule }
) => {
/**
* @param {keyof TargetProperties} key a key
* @returns {boolean} true when target is universal, otherwise false
*/
const isUniversal = (key) =>
Boolean(outputModule && targetProperties && targetProperties[key] === null);
D(
externalsPresets,
"web",
/** @type {boolean | undefined} */
(!buildHttp && targetProperties && targetProperties.web)
(
!buildHttp &&
targetProperties &&
(targetProperties.web || isUniversal("node"))
)
);
D(
externalsPresets,
"node",
/** @type {boolean | undefined} */
(targetProperties && targetProperties.node)
(targetProperties && (targetProperties.node || isUniversal("node")))
);
D(
externalsPresets,
"nwjs",
/** @type {boolean | undefined} */
(targetProperties && targetProperties.nwjs)
(targetProperties && (targetProperties.nwjs || isUniversal("nwjs")))
);
D(
externalsPresets,
"electron",
/** @type {boolean | undefined} */
(targetProperties && targetProperties.electron)
((targetProperties && targetProperties.electron) || isUniversal("electron"))
);
D(
externalsPresets,
@ -1588,7 +1603,7 @@ const applyExternalsPresetsDefaults = (
(
targetProperties &&
targetProperties.electron &&
targetProperties.electronMain
(targetProperties.electronMain || isUniversal("electronMain"))
)
);
D(
@ -1598,7 +1613,7 @@ const applyExternalsPresetsDefaults = (
(
targetProperties &&
targetProperties.electron &&
targetProperties.electronPreload
(targetProperties.electronPreload || isUniversal("electronPreload"))
)
);
D(
@ -1608,7 +1623,7 @@ const applyExternalsPresetsDefaults = (
(
targetProperties &&
targetProperties.electron &&
targetProperties.electronRenderer
(targetProperties.electronRenderer || isUniversal("electronRenderer"))
)
);
};

View File

@ -7,6 +7,7 @@
const ExternalsPlugin = require("../ExternalsPlugin");
/** @typedef {import("../../declarations/WebpackOptions").ExternalsType} ExternalsType */
/** @typedef {import("../Compiler")} Compiler */
const builtins = [
@ -72,13 +73,20 @@ const builtins = [
];
class NodeTargetPlugin {
/**
* @param {ExternalsType} type default external type
*/
constructor(type = "node-commonjs") {
this.type = type;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
new ExternalsPlugin("node-commonjs", builtins).apply(compiler);
new ExternalsPlugin(this.type, builtins).apply(compiler);
}
}

View File

@ -1820,10 +1820,7 @@ describe("snapshots", () => {
+ "outputModule": true,
@@ ... @@
- "node": false,
+ "node": null,
@@ ... @@
- "web": true,
+ "web": null,
+ "node": true,
@@ ... @@
- "externalsType": "var",
+ "externalsType": "module-import",

View File

@ -1,6 +1,14 @@
import value from "./separate";
import { test as t } from "external-self";
function isBrowser() {
return typeof globalThis.window !== 'undefined' && typeof globalThis.document !== 'undefined';
}
it("should compile check", () => {
expect(isBrowser() ? "web" : "node").toBe(!isBrowser() ? "node" : "web");
});
it("should compile", () => {
expect(value).toBe(42);
});
@ -15,6 +23,10 @@ it("work with URL", () => {
expect(/[a-f0-9]{20}\.png/.test(url)).toBe(true);
});
it("work with node.js modules", async () => {
expect(typeof (isBrowser() ? URL : (await import("url")).URL)).toBe("function");
});
function test() {
return 42;
}

View File

@ -0,0 +1,5 @@
"use strict";
const supportsGlobalThis = require("../../../helpers/supportsGlobalThis");
module.exports = () => supportsGlobalThis();

View File

@ -15,7 +15,7 @@ module.exports = [
outputModule: true
},
optimization: {
minimize: true,
minimize: false,
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
@ -45,7 +45,7 @@ module.exports = [
outputModule: true
},
optimization: {
minimize: true,
minimize: false,
runtimeChunk: "single",
splitChunks: {
cacheGroups: {

3
types.d.ts vendored
View File

@ -11429,7 +11429,8 @@ declare class NodeSourcePlugin {
apply(compiler: Compiler): void;
}
declare class NodeTargetPlugin {
constructor();
constructor(type?: ExternalsType);
type: ExternalsType;
/**
* Apply the plugin