Skip to content

Commit

Permalink
fix(externals): distinguish “module” and “import” in “module-import”
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Sep 25, 2024
2 parents dae16ad + c1a0a46 commit 90dec30
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 100 deletions.
172 changes: 79 additions & 93 deletions lib/ExternalModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ class ExternalModule extends Module {
* @returns {string} a unique identifier of the module
*/
identifier() {
return `external ${this.externalType} ${JSON.stringify(this.request)}`;
return `external ${this._resolveExternalType(this.externalType)} ${JSON.stringify(this.request)}`;
}

/**
Expand All @@ -546,25 +546,6 @@ class ExternalModule extends Module {
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 {Compilation} compilation the compilation
Expand Down Expand Up @@ -597,6 +578,25 @@ class ExternalModule extends Module {
canMangle = true;
}
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":
this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check(
Expand All @@ -613,45 +613,18 @@ class ExternalModule extends Module {
"external promise"
);
break;
case "module":
case "import":
case "module-import": {
const type = this.getModuleImportType(externalType);
if (type === "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;
}
}
}

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;
}
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;
}
}
this.addDependency(new StaticExportsDependency(true, canMangle));
callback();
Expand Down Expand Up @@ -687,9 +660,31 @@ class ExternalModule extends Module {
let { request, externalType } = this;
if (typeof request === "object" && !Array.isArray(request))
request = request[externalType];
externalType = this._resolveExternalType(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
* @param {string | string[]} request request
Expand Down Expand Up @@ -749,52 +744,43 @@ class ExternalModule extends Module {
runtimeTemplate
);
}
case "import":
return getSourceForImportExternal(
request,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
case "script":
return getSourceForScriptExternal(request, runtimeTemplate);
case "module":
case "import":
case "module-import": {
const type = this.getModuleImportType(externalType);
if (type === "import") {
return getSourceForImportExternal(
request,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
}

if (type === "module") {
if (!(/** @type {BuildInfo} */ (this.buildInfo).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()) {
case "module": {
if (!(/** @type {BuildInfo} */ (this.buildInfo).module)) {
if (!runtimeTemplate.supportsDynamicImport()) {
throw new Error(
"The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
`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 getSourceForModuleExternal(
return getSourceForImportExternal(
request,
moduleGraph.getExportsInfo(this),
runtime,
runtimeTemplate,
/** @type {ImportDependencyMeta} */ (dependencyMeta)
);
}

break;
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)
);
}
case "var":
case "promise":
Expand Down Expand Up @@ -939,7 +925,7 @@ class ExternalModule extends Module {
updateHash(hash, context) {
const { chunkGraph } = context;
hash.update(
`${this.externalType}${JSON.stringify(this.request)}${this.isOptional(
`${this._resolveExternalType(this.externalType)}${JSON.stringify(this.request)}${this.isOptional(
chunkGraph.moduleGraph
)}`
);
Expand Down
5 changes: 3 additions & 2 deletions test/configCases/externals/module-import/a.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import external0 from "external0"; // module
const external1 = require("external1"); // module
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);
9 changes: 5 additions & 4 deletions test/configCases/externals/module-import/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const path = require("path");

it("module-import should correctly get fallback type", function() {
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_external1__ from "external1";`); // module
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_external0__ from "external0"`); // 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(`import * as __WEBPACK_EXTERNAL_MODULE_external3__ from "external3"`); // module
expect(content).toContain(`const external3_2 = Promise.resolve(/*! import() */).then`); // import
});
1 change: 0 additions & 1 deletion types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4582,7 +4582,6 @@ declare class ExternalModule extends Module {
externalType: string;
userRequest: string;
dependencyMeta?: ImportDependencyMeta | CssImportDependencyMeta;
getModuleImportType(externalType: string): string;

/**
* restore unsafe cache data
Expand Down

0 comments on commit 90dec30

Please sign in to comment.