fix(externals): distinguish “module” and “import” in “module-import”

This commit is contained in:
fi3ework 2024-09-24 23:47:27 +08:00
parent dae16ad11e
commit c1a0a4666e
4 changed files with 87 additions and 100 deletions

View File

@ -526,7 +526,7 @@ class ExternalModule extends Module {
* @returns {string} a unique identifier of the module * @returns {string} a unique identifier of the module
*/ */
identifier() { identifier() {
return `external ${this.externalType} ${JSON.stringify(this.request)}`; return `external ${this._resolveExternalType(this.externalType)} ${JSON.stringify(this.request)}`;
} }
/** /**
@ -546,25 +546,6 @@ class ExternalModule extends Module {
return callback(null, !this.buildMeta); return callback(null, !this.buildMeta);
} }
/**
* @param {string} externalType raw external type
* @returns {string} resolved external type
*/
getModuleImportType(externalType) {
if (externalType === "module-import") {
if (
this.dependencyMeta &&
/** @type {ImportDependencyMeta} */ (this.dependencyMeta).externalType
) {
return /** @type {ImportDependencyMeta} */ (this.dependencyMeta)
.externalType;
}
return "module";
}
return externalType;
}
/** /**
* @param {WebpackOptions} options webpack options * @param {WebpackOptions} options webpack options
* @param {Compilation} compilation the compilation * @param {Compilation} compilation the compilation
@ -597,6 +578,25 @@ class ExternalModule extends Module {
canMangle = true; canMangle = true;
} }
break; break;
case "module":
if (this.buildInfo.module) {
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = true;
}
} else {
this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check(
this,
compilation.runtimeTemplate,
"external module"
);
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = false;
}
}
break;
case "script": case "script":
this.buildMeta.async = true; this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check( EnvironmentNotSupportAsyncWarning.check(
@ -613,45 +613,18 @@ class ExternalModule extends Module {
"external promise" "external promise"
); );
break; break;
case "module":
case "import": case "import":
case "module-import": { this.buildMeta.async = true;
const type = this.getModuleImportType(externalType); EnvironmentNotSupportAsyncWarning.check(
if (type === "module") { this,
if (this.buildInfo.module) { compilation.runtimeTemplate,
if (!Array.isArray(request) || request.length === 1) { "external import"
this.buildMeta.exportsType = "namespace"; );
canMangle = true; if (!Array.isArray(request) || request.length === 1) {
} this.buildMeta.exportsType = "namespace";
} else { canMangle = false;
this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check(
this,
compilation.runtimeTemplate,
"external module"
);
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = false;
}
}
} }
if (type === "import") {
this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check(
this,
compilation.runtimeTemplate,
"external import"
);
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = false;
}
}
break; break;
}
} }
this.addDependency(new StaticExportsDependency(true, canMangle)); this.addDependency(new StaticExportsDependency(true, canMangle));
callback(); callback();
@ -687,9 +660,31 @@ class ExternalModule extends Module {
let { request, externalType } = this; let { request, externalType } = this;
if (typeof request === "object" && !Array.isArray(request)) if (typeof request === "object" && !Array.isArray(request))
request = request[externalType]; request = request[externalType];
externalType = this._resolveExternalType(externalType);
return { request, externalType }; return { request, externalType };
} }
/**
* Resolve the detailed external type from the raw external type.
* e.g. resolve "module" or "import" from "module-import" type
* @param {string} externalType raw external type
* @returns {string} resolved external type
*/
_resolveExternalType(externalType) {
if (externalType === "module-import") {
if (
this.dependencyMeta &&
/** @type {ImportDependencyMeta} */ (this.dependencyMeta).externalType
) {
return /** @type {ImportDependencyMeta} */ (this.dependencyMeta)
.externalType;
}
return "module";
}
return externalType;
}
/** /**
* @private * @private
* @param {string | string[]} request request * @param {string | string[]} request request
@ -749,52 +744,43 @@ class ExternalModule extends Module {
runtimeTemplate runtimeTemplate
); );
} }
case "import":
return getSourceForImportExternal(
request,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
case "script": case "script":
return getSourceForScriptExternal(request, runtimeTemplate); return getSourceForScriptExternal(request, runtimeTemplate);
case "module": case "module": {
case "import": if (!(/** @type {BuildInfo} */ (this.buildInfo).module)) {
case "module-import": { if (!runtimeTemplate.supportsDynamicImport()) {
const type = this.getModuleImportType(externalType); throw new Error(
if (type === "import") { `The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script${
runtimeTemplate.supportsEcmaScriptModuleSyntax()
? "\nDid you mean to build a EcmaScript Module ('output.module: true')?"
: ""
}`
);
}
return getSourceForImportExternal( return getSourceForImportExternal(
request, request,
runtimeTemplate, runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta) /** @type {ImportDependencyMeta} */ (dependencyMeta)
); );
} }
if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) {
if (type === "module") { throw new Error(
if (!(/** @type {BuildInfo} */ (this.buildInfo).module)) { "The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
if (!runtimeTemplate.supportsDynamicImport()) {
throw new Error(
`The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script${
runtimeTemplate.supportsEcmaScriptModuleSyntax()
? "\nDid you mean to build a EcmaScript Module ('output.module: true')?"
: ""
}`
);
}
return getSourceForImportExternal(
request,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
}
if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) {
throw new Error(
"The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
);
}
return getSourceForModuleExternal(
request,
moduleGraph.getExportsInfo(this),
runtime,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
); );
} }
return getSourceForModuleExternal(
break; request,
moduleGraph.getExportsInfo(this),
runtime,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
} }
case "var": case "var":
case "promise": case "promise":
@ -939,7 +925,7 @@ class ExternalModule extends Module {
updateHash(hash, context) { updateHash(hash, context) {
const { chunkGraph } = context; const { chunkGraph } = context;
hash.update( hash.update(
`${this.externalType}${JSON.stringify(this.request)}${this.isOptional( `${this._resolveExternalType(this.externalType)}${JSON.stringify(this.request)}${this.isOptional(
chunkGraph.moduleGraph chunkGraph.moduleGraph
)}` )}`
); );

View File

@ -1,6 +1,7 @@
import external0 from "external0"; // module import external0 from "external0"; // module
const external1 = require("external1"); // module const external1 = require("external1"); // module
const external2 = require("external2"); // node-commonjs const external2 = require("external2"); // node-commonjs
const external3 = import("external3"); // import import external3_1 from "external3"; // module
const external3_2 = import("external3"); // import
console.log(external0, external1, external2, external3); console.log(external0, external1, external3_1, external3_2);

View File

@ -3,8 +3,9 @@ const path = require("path");
it("module-import should correctly get fallback type", function() { it("module-import should correctly get fallback type", function() {
const content = fs.readFileSync(path.resolve(__dirname, "a.js"), "utf-8"); const content = fs.readFileSync(path.resolve(__dirname, "a.js"), "utf-8");
expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external0__ from "external0";`); // module expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external0__ from "external0"`); // module
expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external1__ from "external1";`); // module expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external1__ from "external1"`); // module
expect(content).toContain(`module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("external2");`); // node-commonjs expect(content).toContain(`module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("external2")`); // node-commonjs
expect(content).toContain(`module.exports = import("external3");`); // import expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external3__ from "external3"`); // module
expect(content).toContain(`const external3_2 = Promise.resolve(/*! import() */).then`); // import
}); });

1
types.d.ts vendored
View File

@ -4582,7 +4582,6 @@ declare class ExternalModule extends Module {
externalType: string; externalType: string;
userRequest: string; userRequest: string;
dependencyMeta?: ImportDependencyMeta | CssImportDependencyMeta; dependencyMeta?: ImportDependencyMeta | CssImportDependencyMeta;
getModuleImportType(externalType: string): string;
/** /**
* restore unsafe cache data * restore unsafe cache data