Skip to content

Commit

Permalink
feat: add new external type "module-import"
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework committed Aug 5, 2024
1 parent 4047985 commit ce24bb0
Show file tree
Hide file tree
Showing 19 changed files with 194 additions and 4 deletions.
1 change: 1 addition & 0 deletions declarations/WebpackOptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export type ExternalsType =
| "system"
| "promise"
| "import"
| "module-import"
| "script"
| "node-commonjs";
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type ExternalsType =
| "system"
| "promise"
| "import"
| "module-import"
| "script"
| "node-commonjs";
/**
Expand Down
1 change: 1 addition & 0 deletions declarations/plugins/container/ModuleFederationPlugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export type ExternalsType =
| "system"
| "promise"
| "import"
| "module-import"
| "script"
| "node-commonjs";
/**
Expand Down
10 changes: 10 additions & 0 deletions lib/ExternalModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,8 @@ class ExternalModule extends Module {
"external promise"
);
break;
case "module-import":
break;
case "import":
this.buildMeta.async = true;
EnvironmentNotSupportAsyncWarning.check(
Expand Down Expand Up @@ -718,6 +720,7 @@ class ExternalModule extends Module {
runtimeTemplate
);
}
case "module-import":
case "import":
return getSourceForImportExternal(
request,
Expand Down Expand Up @@ -819,6 +822,13 @@ class ExternalModule extends Module {
runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS
};
}
case "module-import": {
const sources = new Map();
return {
sources,
runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS
};
}
default: {
const sourceData = this._getSourceData(
request,
Expand Down
57 changes: 57 additions & 0 deletions lib/ExternalsPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

"use strict";

const ExternalModule = require("./ExternalModule");
const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin");
const ExternalModuleImportDependency = require("./dependencies/ExternalModuleImportDependency");
const ModuleImportDependency = require("./dependencies/ExternalModuleImportDependency");
const ImportDependency = require("./dependencies/ImportDependency");

/** @typedef {import("../declarations/WebpackOptions").Externals} Externals */
/** @typedef {import("./Compiler")} Compiler */
Expand All @@ -31,6 +35,59 @@ class ExternalsPlugin {
normalModuleFactory
);
});

compiler.hooks.compilation.tap(
"ExternalsPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyTemplates.set(
ModuleImportDependency,
new ModuleImportDependency.Template()
);

compilation.hooks.finishModules.tap("ExternalsPlugin", modules => {
/** @type {ExternalModule} */
for (const module of modules) {
if (!(module instanceof ExternalModule)) {
continue;
}

const { request, externalType } =
module._getRequestAndExternalType();

if (externalType === "module-import") {
const moduleGraph = compilation.moduleGraph;
const connections = moduleGraph.getIncomingConnections(module);
for (const connection of connections) {
const originalModule = connection.originModule;
const connectionDep = connection.dependency;
if (connectionDep instanceof ImportDependency) {
const userRequest = connectionDep.userRequest;
originalModule.blocks.forEach(block => {
for (const dep of block.dependencies) {
if (
dep instanceof ImportDependency &&
userRequest === dep.request
) {
const moduleImportDep =
new ExternalModuleImportDependency(
userRequest,
request,
dep.range
);
originalModule.addPresentationalDependency(
moduleImportDep
);
block.removeDependency(dep);
}
}
});
}
}
}
}
});
}
);
}
}

Expand Down
78 changes: 78 additions & 0 deletions lib/dependencies/ExternalModuleImportDependency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/

"use strict";

const makeSerializable = require("../util/makeSerializable");
const CachedConstDependency = require("./CachedConstDependency");
const ModuleDependency = require("./ModuleDependency");

/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../util/Hash")} Hash */

class ExternalModuleImportDependency extends ModuleDependency {
/**
* @param {string} request the request
* @param {string| string[]} targetRequest the original request
* @param {Range} range expression range
*/
constructor(request, targetRequest, range) {
super(request);
this.targetRequest = targetRequest;
this.range = range;
}

get type() {
return "external module-import";
}

/**
* @param {ObjectSerializerContext} context context
*/
serialize(context) {
const { write } = context;
write(this.targetRequest);
super.serialize(context);
}

/**
* @param {ObjectDeserializerContext} context context
*/
deserialize(context) {
const { read } = context;
this.targetRequest = read();
super.deserialize(context);
}
}

makeSerializable(
ExternalModuleImportDependency,
"webpack/lib/dependencies/ExternalModuleImportDependency"
);

ExternalModuleImportDependency.Template = class ExternalModuleImportDependencyTemplate extends (
CachedConstDependency.Template
) {
/**
* @param {Dependency} dependency the dependency for which the template should be applied
* @param {ReplaceSource} source the current replace source which can be modified
* @param {DependencyTemplateContext} templateContext the context object
* @returns {void}
*/
apply(dependency, source, templateContext) {
const dep = /** @type {ExternalModuleImportDependency} */ (dependency);
const content = JSON.stringify(dep.targetRequest);
source.replace(dep.range[0], dep.range[1] - 1, `import(${content})`);
}
};

module.exports = ExternalModuleImportDependency;
2 changes: 2 additions & 0 deletions lib/util/internalSerializables.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ module.exports = {
require("../dependencies/CachedConstDependency"),
"dependencies/ExternalModuleDependency": () =>
require("../dependencies/ExternalModuleDependency"),
"dependencies/ExternalModuleImportDependency": () =>
require("../dependencies/ExternalModuleImportDependency"),
"dependencies/ExternalModuleInitFragment": () =>
require("../dependencies/ExternalModuleInitFragment"),
"dependencies/CreateScriptUrlDependency": () =>
Expand Down
2 changes: 1 addition & 1 deletion schemas/WebpackOptions.check.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions schemas/WebpackOptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,7 @@
"system",
"promise",
"import",
"module-import",
"script",
"node-commonjs"
]
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions schemas/plugins/container/ContainerReferencePlugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"system",
"promise",
"import",
"module-import",
"script",
"node-commonjs"
]
Expand Down
2 changes: 1 addition & 1 deletion schemas/plugins/container/ExternalsType.check.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
* DO NOT MODIFY BY HAND.
* Run `yarn special-lint-fix` to update
*/
"use strict";function o(r,{instancePath:s="",parentData:m,parentDataProperty:t,rootData:e=r}={}){return"var"!==r&&"module"!==r&&"assign"!==r&&"this"!==r&&"window"!==r&&"self"!==r&&"global"!==r&&"commonjs"!==r&&"commonjs2"!==r&&"commonjs-module"!==r&&"commonjs-static"!==r&&"amd"!==r&&"amd-require"!==r&&"umd"!==r&&"umd2"!==r&&"jsonp"!==r&&"system"!==r&&"promise"!==r&&"import"!==r&&"script"!==r&&"node-commonjs"!==r?(o.errors=[{params:{}}],!1):(o.errors=null,!0)}module.exports=o,module.exports.default=o;
"use strict";function o(m,{instancePath:r="",parentData:s,parentDataProperty:t,rootData:e=m}={}){return"var"!==m&&"module"!==m&&"assign"!==m&&"this"!==m&&"window"!==m&&"self"!==m&&"global"!==m&&"commonjs"!==m&&"commonjs2"!==m&&"commonjs-module"!==m&&"commonjs-static"!==m&&"amd"!==m&&"amd-require"!==m&&"umd"!==m&&"umd2"!==m&&"jsonp"!==m&&"system"!==m&&"promise"!==m&&"import"!==m&&"module-import"!==m&&"script"!==m&&"node-commonjs"!==m?(o.errors=[{params:{}}],!1):(o.errors=null,!0)}module.exports=o,module.exports.default=o;
2 changes: 1 addition & 1 deletion schemas/plugins/container/ModuleFederationPlugin.check.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions schemas/plugins/container/ModuleFederationPlugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
"system",
"promise",
"import",
"module-import",
"script",
"node-commonjs"
]
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/Cli.basictest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,7 @@ Object {
"system",
"promise",
"import",
"module-import",
"script",
"node-commonjs",
],
Expand Down
8 changes: 8 additions & 0 deletions test/configCases/externals/module-import/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
it("should allow async externals", async () => {
const fs1 = await import("fs");
const fs2 = await import("node:fs");
const fs3 = await import("node-fs");

expect(fs1).toStrictEqual(fs2);
expect(fs1).toStrictEqual(fs3);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 42;
23 changes: 23 additions & 0 deletions test/configCases/externals/module-import/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = {
externals: {
fs: "module-import fs",
"node:fs": "module-import node:fs",
"node-fs": "module-import fs"
},
output: {
module: true,
library: {
type: "module"
}
},
target: ["es2020"],
experiments: {
outputModule: true
},
optimization: {
concatenateModules: true,
usedExports: true,
providedExports: true,
mangleExports: true
}
};
Loading

0 comments on commit ce24bb0

Please sign in to comment.