fix null module externals

This commit is contained in:
Tobias Koppers 2021-09-02 17:23:02 +02:00
parent 684e22ec4d
commit 4e8a621bfa
11 changed files with 113 additions and 38 deletions

View File

@ -13,6 +13,7 @@ const Module = require("./Module");
const RuntimeGlobals = require("./RuntimeGlobals");
const Template = require("./Template");
const StaticExportsDependency = require("./dependencies/StaticExportsDependency");
const createHash = require("./util/createHash");
const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
const makeSerializable = require("./util/makeSerializable");
const propertyAccess = require("./util/propertyAccess");
@ -159,18 +160,25 @@ const getSourceForImportExternal = (moduleAndSpecifiers, runtimeTemplate) => {
};
class ModuleExternalInitFragment extends InitFragment {
constructor(id, request) {
const identifier = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
`${id}`
)}__`;
constructor(request, ident) {
if (ident === undefined) {
ident = Template.toIdentifier(request);
if (ident !== request) {
ident += `_${createHash("md4")
.update(request)
.digest("hex")
.slice(0, 8)}`;
}
}
const identifier = `__WEBPACK_EXTERNAL_MODULE_${ident}__`;
super(
`import * as ${identifier} from ${JSON.stringify(request)};\n`,
InitFragment.STAGE_HARMONY_IMPORTS,
0,
`external module import ${id}`
`external module import ${ident}`
);
this._ident = ident;
this._identifier = identifier;
this._id = id;
this._request = request;
}
@ -185,8 +193,8 @@ register(
"ModuleExternalInitFragment",
{
serialize(obj, { write }) {
write(obj._id);
write(obj._request);
write(obj._ident);
},
deserialize({ read }) {
return new ModuleExternalInitFragment(read(), read());
@ -236,10 +244,7 @@ const getSourceForModuleExternal = (
) => {
if (!Array.isArray(moduleAndSpecifiers))
moduleAndSpecifiers = [moduleAndSpecifiers];
const initFragment = new ModuleExternalInitFragment(
id,
moduleAndSpecifiers[0]
);
const initFragment = new ModuleExternalInitFragment(moduleAndSpecifiers[0]);
const baseAccess = `${initFragment.getNamespaceIdentifier()}${propertyAccess(
moduleAndSpecifiers,
1
@ -400,7 +405,7 @@ class ExternalModule extends Module {
* @returns {string} a unique identifier of the module
*/
identifier() {
return "external " + JSON.stringify(this.request);
return `external ${this.externalType} ${JSON.stringify(this.request)}`;
}
/**
@ -531,18 +536,20 @@ class ExternalModule extends Module {
case "umd":
case "umd2":
case "system":
case "jsonp":
case "jsonp": {
const id = chunkGraph.getModuleId(this);
return getSourceForAmdOrUmdExternal(
chunkGraph.getModuleId(this),
id !== null ? id : this.identifier(),
this.isOptional(moduleGraph),
request,
runtimeTemplate
);
}
case "import":
return getSourceForImportExternal(request, runtimeTemplate);
case "script":
return getSourceForScriptExternal(request, runtimeTemplate);
case "module":
case "module": {
if (!this.buildInfo.module) {
if (!runtimeTemplate.supportsDynamicImport()) {
throw new Error(
@ -559,12 +566,14 @@ class ExternalModule extends Module {
"The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
);
}
const id = chunkGraph.getModuleId(this);
return getSourceForModuleExternal(
chunkGraph.getModuleId(this),
id !== null ? id : this.identifier(),
request,
moduleGraph.getExportsInfo(this),
runtime
);
}
case "var":
case "promise":
case "const":

View File

@ -6,6 +6,7 @@
"use strict";
const { ConcatSource } = require("webpack-sources");
const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./Generator").GenerateContext} GenerateContext */
@ -123,8 +124,30 @@ class InitFragment {
return source;
}
}
serialize(context) {
const { write } = context;
write(this.content);
write(this.stage);
write(this.position);
write(this.key);
write(this.endContent);
}
deserialize(context) {
const { read } = context;
this.content = read();
this.stage = read();
this.position = read();
this.key = read();
this.endContent = read();
}
}
makeSerializable(InitFragment, "webpack/lib/InitFragment");
InitFragment.prototype.merge = undefined;
InitFragment.STAGE_CONSTANTS = 10;

View File

@ -164,6 +164,7 @@ module.exports = {
DllModule: () => require("../DllModule"),
ExternalModule: () => require("../ExternalModule"),
FileSystemInfo: () => require("../FileSystemInfo"),
InitFragment: () => require("../InitFragment"),
InvalidDependenciesModuleWarning: () =>
require("../InvalidDependenciesModuleWarning"),
Module: () => require("../Module"),

View File

@ -486,7 +486,7 @@ const describeCases = config => {
"unlinked",
referencingModule
),
module.context,
referencingModule.context,
true
);
}

View File

@ -29,14 +29,14 @@ exports[`ConfigCacheTestCases records issue-2991 exported tests should write rel
\\"modules\\": {
\\"byIdentifier\\": {
\\"./test.js\\": 393,
\\"external \\\\\\"fs\\\\\\"\\": 747,
\\"external \\\\\\"path\\\\\\"\\": 622,
\\"external node-commonjs \\\\\\"fs\\\\\\"\\": 147,
\\"external node-commonjs \\\\\\"path\\\\\\"\\": 17,
\\"ignored|./.|pkgs/somepackage/foo\\": 802
},
\\"usedIds\\": [
17,
147,
393,
622,
747,
802
]
}
@ -62,16 +62,16 @@ exports[`ConfigCacheTestCases records issue-7339 exported tests should write rel
\\"./dependencies/foo.js\\": 117,
\\"./dependencies|sync|/^\\\\\\\\.\\\\\\\\/.*$/\\": 412,
\\"./test.js\\": 393,
\\"external \\\\\\"fs\\\\\\"\\": 747,
\\"external \\\\\\"path\\\\\\"\\": 622
\\"external node-commonjs \\\\\\"fs\\\\\\"\\": 147,
\\"external node-commonjs \\\\\\"path\\\\\\"\\": 17
},
\\"usedIds\\": [
17,
117,
147,
379,
393,
412,
622,
747
412
]
}
}"

View File

@ -29,14 +29,14 @@ exports[`ConfigTestCases records issue-2991 exported tests should write relative
\\"modules\\": {
\\"byIdentifier\\": {
\\"./test.js\\": 393,
\\"external \\\\\\"fs\\\\\\"\\": 747,
\\"external \\\\\\"path\\\\\\"\\": 622,
\\"external node-commonjs \\\\\\"fs\\\\\\"\\": 147,
\\"external node-commonjs \\\\\\"path\\\\\\"\\": 17,
\\"ignored|./.|pkgs/somepackage/foo\\": 802
},
\\"usedIds\\": [
17,
147,
393,
622,
747,
802
]
}
@ -62,16 +62,16 @@ exports[`ConfigTestCases records issue-7339 exported tests should write relative
\\"./dependencies/foo.js\\": 117,
\\"./dependencies|sync|/^\\\\\\\\.\\\\\\\\/.*$/\\": 412,
\\"./test.js\\": 393,
\\"external \\\\\\"fs\\\\\\"\\": 747,
\\"external \\\\\\"path\\\\\\"\\": 622
\\"external node-commonjs \\\\\\"fs\\\\\\"\\": 147,
\\"external node-commonjs \\\\\\"path\\\\\\"\\": 17
},
\\"usedIds\\": [
17,
117,
147,
379,
393,
412,
622,
747
412
]
}
}"

View File

@ -0,0 +1,12 @@
import fs1 from "fs";
import fs2 from "module-fs";
import fsPromises1 from "fs-promises";
import fsPromises2 from "module-fs-promises";
import path1 from "path";
import path2 from "module-path";
it("should be possible to import multiple module externals", () => {
expect(fs2).toBe(fs1);
expect(path2).toBe(path1);
expect(fsPromises2).toBe(fsPromises1);
});

View File

@ -0,0 +1,3 @@
module.exports = () => {
return !process.version.startsWith("v10.");
};

View File

@ -0,0 +1,25 @@
/** @type {(variant: boolean) => import("../../../../").Configuration} */
const config = o => ({
externals: {
"module-fs": o ? "module fs" : "module fs/promises",
fs: o ? "node-commonjs fs" : "node-commonjs fs/promises",
"module-fs-promises": o ? ["module fs", "promises"] : "module fs/promises",
"fs-promises": o
? ["node-commonjs fs", "promises"]
: "node-commonjs fs/promises",
"module-path": "module path",
path: "node-commonjs path"
},
optimization: {
concatenateModules: true,
usedExports: true,
providedExports: true,
mangleExports: true
},
target: "node14",
experiments: {
outputModule: true
}
});
module.exports = [config(false), config(true)];

View File

@ -14,9 +14,9 @@ module.exports = async (something, context, unlinked) => {
const code = [...new Set(["default", ...Object.keys(something)])]
.map(
name =>
`const _${name} = ${SYNTHETIC_MODULES_STORE}[${i}][${JSON.stringify(
name
)}]; export { _${name} as ${name}};`
`const _${name} = ${SYNTHETIC_MODULES_STORE}[${i}]${
name === "default" ? "" : `[${JSON.stringify(name)}]`
}; export { _${name} as ${name}};`
)
.join("\n");
const m = new vm.SourceTextModule(code, {

2
types.d.ts vendored
View File

@ -4517,6 +4517,8 @@ declare abstract class InitFragment<Context> {
endContent?: string | Source;
getContent(context: Context): string | Source;
getEndContent(context: Context): undefined | string | Source;
serialize(context?: any): void;
deserialize(context?: any): void;
merge: any;
}
declare interface InputFileSystem {