From a0189019cc8800a0f2c76b4e6bf5528fd4a198da Mon Sep 17 00:00:00 2001 From: hai-x <98948357+hai-x@users.noreply.github.com> Date: Mon, 4 Aug 2025 23:50:05 +0800 Subject: [PATCH] fix: tree-shakable module library should align preconditions of allowInlineStartup --- lib/Module.js | 3 +- lib/ModuleTemplate.js | 5 +- lib/javascript/JavascriptModulesPlugin.js | 132 ++++++++++++------ lib/library/AbstractLibraryPlugin.js | 27 ++++ lib/library/ModuleLibraryPlugin.js | 69 ++++----- lib/optimize/ConcatenatedModule.js | 52 +++---- .../ConfigCacheTestCases.longtest.js.snap | 92 ++++++++++++ .../ConfigTestCases.basictest.js.snap | 23 +++ .../0-create-library/webpack.config.js | 23 +++ .../library/1-use-library/webpack.config.js | 16 +++ .../foo.cjs | 0 .../index.mjs | 0 .../test.config.js | 0 .../test.js | 0 .../webpack.config.js | 0 types.d.ts | 126 +++++++++++++++-- 16 files changed, 451 insertions(+), 117 deletions(-) rename test/configCases/module/{iife-innter-strict => iife-inner-strict}/foo.cjs (100%) rename test/configCases/module/{iife-innter-strict => iife-inner-strict}/index.mjs (100%) rename test/configCases/module/{iife-innter-strict => iife-inner-strict}/test.config.js (100%) rename test/configCases/module/{iife-innter-strict => iife-inner-strict}/test.js (100%) rename test/configCases/module/{iife-innter-strict => iife-inner-strict}/webpack.config.js (100%) diff --git a/lib/Module.js b/lib/Module.js index 899b26a84..c5504fda6 100644 --- a/lib/Module.js +++ b/lib/Module.js @@ -115,9 +115,10 @@ const makeSerializable = require("./util/makeSerializable"); * @property {boolean=} strictHarmonyModule * @property {boolean=} async * @property {boolean=} sideEffectFree - * @property {Record=} exportsFinalName * @property {boolean=} isCSSModule * @property {Record=} jsIncompatibleExports + * @property {Record=} exportsFinalName + * @property {string=} factoryExportsBinding */ /** diff --git a/lib/ModuleTemplate.js b/lib/ModuleTemplate.js index d79802ece..4d2809307 100644 --- a/lib/ModuleTemplate.js +++ b/lib/ModuleTemplate.js @@ -18,6 +18,7 @@ const memoize = require("./util/memoize"); /** @typedef {import("./ModuleGraph")} ModuleGraph */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ /** @typedef {import("./javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */ +/** @typedef {import("./javascript/JavascriptModulesPlugin").ModuleRenderContext} ModuleRenderContext */ /** @typedef {import("./util/Hash")} Hash */ /** @@ -44,7 +45,7 @@ class ModuleTemplate { /** * @template AdditionalOptions * @param {string | Tap & IfSet} options options - * @param {(source: Source, module: Module, chunkRenderContext: ChunkRenderContext, dependencyTemplates: DependencyTemplates) => Source} fn fn + * @param {(source: Source, module: Module, moduleRenderContext: ModuleRenderContext, dependencyTemplates: DependencyTemplates) => Source} fn fn */ (options, fn) => { getJavascriptModulesPlugin() @@ -69,7 +70,7 @@ class ModuleTemplate { /** * @template AdditionalOptions * @param {string | Tap & IfSet} options options - * @param {(source: Source, module: Module, chunkRenderContext: ChunkRenderContext, dependencyTemplates: DependencyTemplates) => Source} fn fn + * @param {(source: Source, module: Module, moduleRenderContext: ModuleRenderContext, dependencyTemplates: DependencyTemplates) => Source} fn fn */ (options, fn) => { getJavascriptModulesPlugin() diff --git a/lib/javascript/JavascriptModulesPlugin.js b/lib/javascript/JavascriptModulesPlugin.js index 783e35183..86e421b22 100644 --- a/lib/javascript/JavascriptModulesPlugin.js +++ b/lib/javascript/JavascriptModulesPlugin.js @@ -173,13 +173,38 @@ const printGeneratedCodeForStack = (module, code) => { * @property {string} hash hash to be used for render call */ -/** @typedef {RenderContext & { inlined: boolean }} StartupRenderContext */ +/** + * @typedef {object} StartupRenderContext + * @property {Chunk} chunk the chunk + * @property {DependencyTemplates} dependencyTemplates the dependency templates + * @property {RuntimeTemplate} runtimeTemplate the runtime template + * @property {ModuleGraph} moduleGraph the module graph + * @property {ChunkGraph} chunkGraph the chunk graph + * @property {CodeGenerationResults} codeGenerationResults results of code generation + * @property {boolean | undefined} strictMode rendering in strict context + * @property {boolean } inlined inlined + * @property {boolean=} inlinedInIIFE the inlined entry module is wrapped in an IIFE + */ + +/** + * @typedef {object} ModuleRenderContext + * @property {Chunk} chunk the chunk + * @property {DependencyTemplates} dependencyTemplates the dependency templates + * @property {RuntimeTemplate} runtimeTemplate the runtime template + * @property {ModuleGraph} moduleGraph the module graph + * @property {ChunkGraph} chunkGraph the chunk graph + * @property {CodeGenerationResults} codeGenerationResults results of code generation + * @property {InitFragment[]} chunkInitFragments init fragments for the chunk + * @property {boolean | undefined} strictMode rendering in strict context + * @property {boolean} factory true: renders as factory method, false: pure module content + * @property {boolean=} inlinedInIIFE the inlined entry module is wrapped in an IIFE, existing only when `factory` is set to false + */ /** * @typedef {object} CompilationHooks - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContent - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContainer - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage + * @property {SyncWaterfallHook<[Source, Module, ModuleRenderContext]>} renderModuleContent + * @property {SyncWaterfallHook<[Source, Module, ModuleRenderContext]>} renderModuleContainer + * @property {SyncWaterfallHook<[Source, Module, ModuleRenderContext]>} renderModulePackage * @property {SyncWaterfallHook<[Source, RenderContext]>} renderChunk * @property {SyncWaterfallHook<[Source, RenderContext]>} renderMain * @property {SyncWaterfallHook<[Source, RenderContext]>} renderContent @@ -217,17 +242,17 @@ class JavascriptModulesPlugin { renderModuleContent: new SyncWaterfallHook([ "source", "module", - "renderContext" + "moduleRenderContext" ]), renderModuleContainer: new SyncWaterfallHook([ "source", "module", - "renderContext" + "moduleRenderContext" ]), renderModulePackage: new SyncWaterfallHook([ "source", "module", - "renderContext" + "moduleRenderContext" ]), render: new SyncWaterfallHook(["source", "renderContext"]), renderContent: new SyncWaterfallHook(["source", "renderContext"]), @@ -575,18 +600,18 @@ class JavascriptModulesPlugin { /** * @param {Module} module the rendered module - * @param {ChunkRenderContext} renderContext options object + * @param {ModuleRenderContext} renderContext options object * @param {CompilationHooks} hooks hooks - * @param {boolean} factory true: renders as factory method, false: pure module content * @returns {Source | null} the newly generated source from rendering */ - renderModule(module, renderContext, hooks, factory) { + renderModule(module, renderContext, hooks) { const { chunk, chunkGraph, runtimeTemplate, codeGenerationResults, - strictMode + strictMode, + factory } = renderContext; try { const codeGenResult = codeGenerationResults.get(module, chunk.runtime); @@ -729,7 +754,11 @@ class JavascriptModulesPlugin { }; const moduleSources = Template.renderChunkModules(chunkRenderContext, allModules, (module) => - this.renderModule(module, chunkRenderContext, hooks, true) + this.renderModule( + module, + { ...chunkRenderContext, factory: true }, + hooks + ) ) || new RawSource("{}"); let source = tryRunOrWebpackError( () => hooks.renderChunk.call(moduleSources, chunkRenderContext), @@ -841,7 +870,12 @@ class JavascriptModulesPlugin { (m) => !(/** @type {Set} */ (inlinedModules).has(m)) ) : allModules, - (module) => this.renderModule(module, chunkRenderContext, hooks, true), + (module) => + this.renderModule( + module, + { ...chunkRenderContext, factory: true }, + hooks + ), prefix ); if ( @@ -913,6 +947,8 @@ class JavascriptModulesPlugin { const avoidEntryIife = compilation.options.optimization.avoidEntryIife; /** @type {Map | false} */ let renamedInlinedModule = false; + let inlinedInIIFE = false; + if (avoidEntryIife) { renamedInlinedModule = this.getRenamedInlineModule( allModules, @@ -926,31 +962,46 @@ class JavascriptModulesPlugin { } for (const m of inlinedModules) { + const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements( + m, + chunk.runtime + ); + const exports = runtimeRequirements.has(RuntimeGlobals.exports); + const webpackExports = + exports && m.exportsArgument === RuntimeGlobals.exports; + + const innerStrict = + !allStrict && /** @type {BuildInfo} */ (m.buildInfo).strict; + + const iife = innerStrict + ? "it needs to be in strict mode." + : inlinedModules.size > 1 + ? // TODO check globals and top-level declarations of other entries and chunk modules + // to make a better decision + "it needs to be isolated against other entry modules." + : chunkModules && !renamedInlinedModule + ? "it needs to be isolated against other modules in the chunk." + : exports && !webpackExports + ? `it uses a non-standard name for the exports (${m.exportsArgument}).` + : hooks.embedInRuntimeBailout.call(m, renderContext); + + if (iife) { + inlinedInIIFE = true; + } + const renderedModule = renamedInlinedModule ? renamedInlinedModule.get(m) - : this.renderModule(m, chunkRenderContext, hooks, false); + : this.renderModule( + m, + { + ...chunkRenderContext, + factory: false, + inlinedInIIFE + }, + hooks + ); if (renderedModule) { - const innerStrict = - !allStrict && /** @type {BuildInfo} */ (m.buildInfo).strict; - const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements( - m, - chunk.runtime - ); - const exports = runtimeRequirements.has(RuntimeGlobals.exports); - const webpackExports = - exports && m.exportsArgument === RuntimeGlobals.exports; - const iife = innerStrict - ? "it needs to be in strict mode." - : inlinedModules.size > 1 - ? // TODO check globals and top-level declarations of other entries and chunk modules - // to make a better decision - "it needs to be isolated against other entry modules." - : chunkModules && !renamedInlinedModule - ? "it needs to be isolated against other modules in the chunk." - : exports && !webpackExports - ? `it uses a non-standard name for the exports (${m.exportsArgument}).` - : hooks.embedInRuntimeBailout.call(m, renderContext); let footer; if (iife !== undefined) { startupSource.add( @@ -989,7 +1040,8 @@ class JavascriptModulesPlugin { source.add( hooks.renderStartup.call(startupSource, lastInlinedModule, { ...renderContext, - inlined: true + inlined: true, + inlinedInIIFE }) ); if (bootstrap.afterStartup.length > 0) { @@ -1557,7 +1609,6 @@ class JavascriptModulesPlugin { allModules.every((m) => /** @type {BuildInfo} */ (m.buildInfo).strict); const isMultipleEntries = inlinedModules.size > 1; const singleEntryWithModules = inlinedModules.size === 1 && hasChunkModules; - // TODO: // This step is before the IIFE reason calculation. Ideally, it should only be executed when this function can optimize the // IIFE reason. Otherwise, it should directly return false. There are four reasons now, we have skipped two already, the left @@ -1581,9 +1632,12 @@ class JavascriptModulesPlugin { const isInlinedModule = inlinedModules && inlinedModules.has(m); const moduleSource = this.renderModule( m, - chunkRenderContext, - hooks, - !isInlinedModule + { + ...chunkRenderContext, + factory: !isInlinedModule, + inlinedInIIFE: false + }, + hooks ); if (!moduleSource) continue; diff --git a/lib/library/AbstractLibraryPlugin.js b/lib/library/AbstractLibraryPlugin.js index 1c0efeba9..b6a009068 100644 --- a/lib/library/AbstractLibraryPlugin.js +++ b/lib/library/AbstractLibraryPlugin.js @@ -19,6 +19,8 @@ const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin") /** @typedef {import("../Module")} Module */ /** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */ /** @typedef {import("../javascript/JavascriptModulesPlugin").StartupRenderContext} StartupRenderContext */ +/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */ +/** @typedef {import("../javascript/JavascriptModulesPlugin").ModuleRenderContext} ModuleRenderContext */ /** @typedef {import("../util/Hash")} Hash */ const COMMON_LIBRARY_NAME_MESSAGE = @@ -173,6 +175,20 @@ class AbstractLibraryPlugin { }); } + if ( + this.renderModuleContent !== + AbstractLibraryPlugin.prototype.renderModuleContent + ) { + hooks.renderModuleContent.tap( + _pluginName, + (source, module, renderContext) => + this.renderModuleContent(source, module, renderContext, { + compilation, + chunkGraph: compilation.chunkGraph + }) + ); + } + if ( this.renderStartup !== AbstractLibraryPlugin.prototype.renderStartup ) { @@ -288,6 +304,17 @@ class AbstractLibraryPlugin { return source; } + /** + * @param {Source} source source + * @param {Module} module module + * @param {ModuleRenderContext} renderContext render context + * @param {Omit, 'options'>} libraryContext context + * @returns {Source} source with library export + */ + renderModuleContent(source, module, renderContext, libraryContext) { + return source; + } + /** * @param {Chunk} chunk the chunk * @param {Hash} hash hash diff --git a/lib/library/ModuleLibraryPlugin.js b/lib/library/ModuleLibraryPlugin.js index 6fd9faa8c..2f2a5b4a3 100644 --- a/lib/library/ModuleLibraryPlugin.js +++ b/lib/library/ModuleLibraryPlugin.js @@ -8,7 +8,6 @@ const { ConcatSource } = require("webpack-sources"); const RuntimeGlobals = require("../RuntimeGlobals"); const Template = require("../Template"); -const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin"); const ConcatenatedModule = require("../optimize/ConcatenatedModule"); const propertyAccess = require("../util/propertyAccess"); const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); @@ -22,6 +21,7 @@ const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); /** @typedef {import("../Module")} Module */ /** @typedef {import("../Module").BuildMeta} BuildMeta */ /** @typedef {import("../javascript/JavascriptModulesPlugin").StartupRenderContext} StartupRenderContext */ +/** @typedef {import("../javascript/JavascriptModulesPlugin").ModuleRenderContext} ModuleRenderContext */ /** @typedef {import("../util/Hash")} Hash */ /** @@ -66,37 +66,9 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { super.apply(compiler); compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { - const { exportsDefinitions } = + const { onDemandExportsGeneration } = ConcatenatedModule.getCompilationHooks(compilation); - exportsDefinitions.tap(PLUGIN_NAME, (definitions, module) => { - const bailout = JavascriptModulesPlugin.getCompilationHooks( - compilation - ).inlineInRuntimeBailout.call(module, {}); - if (bailout) return false; - // If we have connections not all modules were concatenated, so we need the wrapper - const connections = - compilation.moduleGraph.getIncomingConnections(module); - - for (const connection of connections) { - if (connection.originModule) { - return false; - } - } - - // Runtime and splitting chunks now requires the wrapper too - for (const chunk of compilation.chunkGraph.getModuleChunksIterable( - module - )) { - if ( - !chunk.hasRuntime() || - compilation.chunkGraph.getNumberOfEntryModules(chunk) > 1 - ) { - return false; - } - } - - return true; - }); + onDemandExportsGeneration.tap(PLUGIN_NAME, (_module) => true); }); } @@ -128,7 +100,7 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { renderStartup( source, module, - { moduleGraph, chunk, codeGenerationResults }, + { moduleGraph, chunk, codeGenerationResults, inlined, inlinedInIIFE }, { options, compilation } ) { const result = new ConcatSource(source); @@ -141,8 +113,11 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { ] : moduleGraph.getExportsInfo(module).orderedExports; const definitions = - /** @type {BuildMeta} */ - (module.buildMeta).exportsFinalName || {}; + inlined && !inlinedInIIFE + ? (module.buildMeta && + /** @type {GenerationMeta} */ module.buildMeta.exportsFinalName) || + {} + : {}; /** @type {string[]} */ const shortHandedExports = []; /** @type {[string, string][]} */ @@ -241,6 +216,32 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { return result; } + + /** + * @param {Source} source source + * @param {Module} module module + * @param {ModuleRenderContext} renderContext render context + * @param {Omit, 'options'>} libraryContext context + * @returns {Source} source with library export + */ + renderModuleContent( + source, + module, + { factory, inlinedInIIFE }, + libraryContext + ) { + const result = new ConcatSource(source); + // Re-add `factoryExportsBinding` to the source + // when the module is rendered as a factory or treated as an inlined (startup) module but wrapped in an IIFE + if ( + (inlinedInIIFE || factory) && + module.buildMeta && + module.buildMeta.factoryExportsBinding + ) { + result.add(module.buildMeta.factoryExportsBinding); + } + return result; + } } module.exports = ModuleLibraryPlugin; diff --git a/lib/optimize/ConcatenatedModule.js b/lib/optimize/ConcatenatedModule.js index f1703343e..a8c2e761f 100644 --- a/lib/optimize/ConcatenatedModule.js +++ b/lib/optimize/ConcatenatedModule.js @@ -668,7 +668,7 @@ const getFinalName = ( /** * @typedef {object} ConcatenateModuleHooks - * @property {SyncBailHook<[Record, ConcatenatedModule], boolean | void>} exportsDefinitions + * @property {SyncBailHook<[ConcatenatedModule], boolean>} onDemandExportsGeneration * @property {SyncBailHook<[Partial, ConcatenatedModuleInfo], boolean | void>} concatenatedModuleInfo */ @@ -716,7 +716,7 @@ class ConcatenatedModule extends Module { let hooks = compilationHooksMap.get(compilation); if (hooks === undefined) { hooks = { - exportsDefinitions: new SyncBailHook(["definitions", "module"]), + onDemandExportsGeneration: new SyncBailHook(["module"]), concatenatedModuleInfo: new SyncBailHook([ "updatedInfo", "concatenatedModuleInfo" @@ -1692,11 +1692,6 @@ class ConcatenatedModule extends Module { // define exports if (exportsMap.size > 0) { - const { exportsDefinitions } = ConcatenatedModule.getCompilationHooks( - /** @type {Compilation} */ - (this.compilation) - ); - const definitions = []; for (const [key, value] of exportsMap) { definitions.push( @@ -1706,34 +1701,39 @@ class ConcatenatedModule extends Module { ); } - const shouldSkipRenderDefinitions = exportsDefinitions.call( - exportsFinalName, - this - ); + const { onDemandExportsGeneration } = + ConcatenatedModule.getCompilationHooks( + /** @type {Compilation} */ + (this.compilation) + ); - if (!shouldSkipRenderDefinitions) { - runtimeRequirements.add(RuntimeGlobals.exports); - runtimeRequirements.add(RuntimeGlobals.definePropertyGetters); + runtimeRequirements.add(RuntimeGlobals.exports); + runtimeRequirements.add(RuntimeGlobals.definePropertyGetters); - if (shouldAddHarmonyFlag) { - result.add("// ESM COMPAT FLAG\n"); - result.add( - runtimeTemplate.defineEsModuleFlagStatement({ - exportsArgument: this.exportsArgument, - runtimeRequirements - }) - ); - } + if (shouldAddHarmonyFlag) { + result.add("// ESM COMPAT FLAG\n"); + result.add( + runtimeTemplate.defineEsModuleFlagStatement({ + exportsArgument: this.exportsArgument, + runtimeRequirements + }) + ); + } + if (onDemandExportsGeneration.call(this)) { + /** @type {BuildMeta} */ (this.buildMeta).factoryExportsBinding = + `${RuntimeGlobals.definePropertyGetters}(${ + this.exportsArgument + }, {${definitions.join(",")}\n});\n`; + /** @type {BuildMeta} */ (this.buildMeta).exportsFinalName = + exportsFinalName; + } else { result.add("\n// EXPORTS\n"); result.add( `${RuntimeGlobals.definePropertyGetters}(${ this.exportsArgument }, {${definitions.join(",")}\n});\n` ); - } else { - /** @type {BuildMeta} */ - (this.buildMeta).exportsFinalName = exportsFinalName; } } diff --git a/test/__snapshots__/ConfigCacheTestCases.longtest.js.snap b/test/__snapshots__/ConfigCacheTestCases.longtest.js.snap index 2d22d508f..de8c7bcf1 100644 --- a/test/__snapshots__/ConfigCacheTestCases.longtest.js.snap +++ b/test/__snapshots__/ConfigCacheTestCases.longtest.js.snap @@ -10155,6 +10155,29 @@ import { HomeLayout as HomeLayout_0, a as a_0 } from \\"externals1\\"; import { default as default_0 } from \\"externals2\\"; import * as __WEBPACK_EXTERNAL_MODULE_externals3__ from \\"externals3\\"; import \\"externals4\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; /*!*****************************!*\\\\ !*** ./test.js + 6 modules ***! \\\\*****************************/ @@ -10229,6 +10252,29 @@ import { HomeLayout as HomeLayout_0, a as a_0 } from \\"externals1\\"; import { default as default_0 } from \\"externals2\\"; import * as __WEBPACK_EXTERNAL_MODULE_externals3__ from \\"externals3\\"; import \\"externals4\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; /*!*****************************!*\\\\ !*** ./test.js + 6 modules ***! \\\\*****************************/ @@ -10303,6 +10349,29 @@ import { HomeLayout as HomeLayout_0, a as a_0 } from \\"externals1\\"; import { default as default_0 } from \\"externals2\\"; import * as __WEBPACK_EXTERNAL_MODULE_externals3__ from \\"externals3\\"; import \\"externals4\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; /*!*****************************!*\\\\ !*** ./test.js + 6 modules ***! \\\\*****************************/ @@ -10377,6 +10446,29 @@ import { HomeLayout as HomeLayout_0, a as a_0 } from \\"externals1\\"; import { default as default_0 } from \\"externals2\\"; import * as __WEBPACK_EXTERNAL_MODULE_externals3__ from \\"externals3\\"; import \\"externals4\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; /*!*****************************!*\\\\ !*** ./test.js + 6 modules ***! \\\\*****************************/ diff --git a/test/__snapshots__/ConfigTestCases.basictest.js.snap b/test/__snapshots__/ConfigTestCases.basictest.js.snap index c281a612f..157b853e4 100644 --- a/test/__snapshots__/ConfigTestCases.basictest.js.snap +++ b/test/__snapshots__/ConfigTestCases.basictest.js.snap @@ -10155,6 +10155,29 @@ import { HomeLayout as HomeLayout_0, a as a_0 } from \\"externals1\\"; import { default as default_0 } from \\"externals2\\"; import * as __WEBPACK_EXTERNAL_MODULE_externals3__ from \\"externals3\\"; import \\"externals4\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; /*!*****************************!*\\\\ !*** ./test.js + 6 modules ***! \\\\*****************************/ diff --git a/test/configCases/library/0-create-library/webpack.config.js b/test/configCases/library/0-create-library/webpack.config.js index e406cdc41..43b742e49 100644 --- a/test/configCases/library/0-create-library/webpack.config.js +++ b/test/configCases/library/0-create-library/webpack.config.js @@ -64,6 +64,29 @@ module.exports = (env, { testPath }) => [ outputModule: true } }, + { + entry: "./esm-with-commonjs.js", + output: { + uniqueName: "esm-with-commonjs", + filename: "esm-with-commonjs-avoid-entry-iife.js", + library: { + type: "module" + } + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + optimization: { + avoidEntryIife: false + }, + experiments: { + outputModule: true + } + }, { output: { uniqueName: "esm-export", diff --git a/test/configCases/library/1-use-library/webpack.config.js b/test/configCases/library/1-use-library/webpack.config.js index a54358c14..534364ec7 100644 --- a/test/configCases/library/1-use-library/webpack.config.js +++ b/test/configCases/library/1-use-library/webpack.config.js @@ -76,6 +76,22 @@ module.exports = (env, { testPath }) => [ }) ] }, + { + entry: "./esm-with-commonjs", + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-with-commonjs-avoid-entry-iife.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-with-commonjs") + }) + ] + }, { entry: "./module-export-test.js", resolve: { diff --git a/test/configCases/module/iife-innter-strict/foo.cjs b/test/configCases/module/iife-inner-strict/foo.cjs similarity index 100% rename from test/configCases/module/iife-innter-strict/foo.cjs rename to test/configCases/module/iife-inner-strict/foo.cjs diff --git a/test/configCases/module/iife-innter-strict/index.mjs b/test/configCases/module/iife-inner-strict/index.mjs similarity index 100% rename from test/configCases/module/iife-innter-strict/index.mjs rename to test/configCases/module/iife-inner-strict/index.mjs diff --git a/test/configCases/module/iife-innter-strict/test.config.js b/test/configCases/module/iife-inner-strict/test.config.js similarity index 100% rename from test/configCases/module/iife-innter-strict/test.config.js rename to test/configCases/module/iife-inner-strict/test.config.js diff --git a/test/configCases/module/iife-innter-strict/test.js b/test/configCases/module/iife-inner-strict/test.js similarity index 100% rename from test/configCases/module/iife-innter-strict/test.js rename to test/configCases/module/iife-inner-strict/test.js diff --git a/test/configCases/module/iife-innter-strict/webpack.config.js b/test/configCases/module/iife-inner-strict/webpack.config.js similarity index 100% rename from test/configCases/module/iife-innter-strict/webpack.config.js rename to test/configCases/module/iife-inner-strict/webpack.config.js diff --git a/types.d.ts b/types.d.ts index 8fa5306f2..851c9ab59 100644 --- a/types.d.ts +++ b/types.d.ts @@ -160,6 +160,12 @@ declare class AbstractLibraryPlugin { renderContext: StartupRenderContext, libraryContext: LibraryContext ): Source; + renderModuleContent( + source: Source, + module: Module, + renderContext: ModuleRenderContext, + libraryContext: Omit, "options"> + ): Source; chunkHash( chunk: Chunk, hash: Hash, @@ -2549,15 +2555,11 @@ declare interface CompilationHooksCssModulesPlugin { chunkHash: SyncHook<[Chunk, Hash, ChunkHashContext]>; } declare interface CompilationHooksJavascriptModulesPlugin { - renderModuleContent: SyncWaterfallHook< - [Source, Module, ChunkRenderContextJavascriptModulesPlugin] - >; + renderModuleContent: SyncWaterfallHook<[Source, Module, ModuleRenderContext]>; renderModuleContainer: SyncWaterfallHook< - [Source, Module, ChunkRenderContextJavascriptModulesPlugin] - >; - renderModulePackage: SyncWaterfallHook< - [Source, Module, ChunkRenderContextJavascriptModulesPlugin] + [Source, Module, ModuleRenderContext] >; + renderModulePackage: SyncWaterfallHook<[Source, Module, ModuleRenderContext]>; renderChunk: SyncWaterfallHook< [Source, RenderContextJavascriptModulesPlugin] >; @@ -6461,9 +6463,8 @@ declare class JavascriptModulesPlugin { apply(compiler: Compiler): void; renderModule( module: Module, - renderContext: ChunkRenderContextJavascriptModulesPlugin, - hooks: CompilationHooksJavascriptModulesPlugin, - factory: boolean + renderContext: ModuleRenderContext, + hooks: CompilationHooksJavascriptModulesPlugin ): null | Source; renderChunk( renderContext: RenderContextJavascriptModulesPlugin, @@ -8355,9 +8356,10 @@ declare interface KnownBuildMeta { strictHarmonyModule?: boolean; async?: boolean; sideEffectFree?: boolean; - exportsFinalName?: Record; isCSSModule?: boolean; jsIncompatibleExports?: Record; + exportsFinalName?: Record; + factoryExportsBinding?: string; } declare interface KnownCreateStatsOptionsContext { forToString?: boolean; @@ -10355,6 +10357,57 @@ declare interface ModuleReferenceOptions { */ asiSafe?: boolean; } +declare interface ModuleRenderContext { + /** + * the chunk + */ + chunk: Chunk; + + /** + * the dependency templates + */ + dependencyTemplates: DependencyTemplates; + + /** + * the runtime template + */ + runtimeTemplate: RuntimeTemplate; + + /** + * the module graph + */ + moduleGraph: ModuleGraph; + + /** + * the chunk graph + */ + chunkGraph: ChunkGraph; + + /** + * results of code generation + */ + codeGenerationResults: CodeGenerationResults; + + /** + * init fragments for the chunk + */ + chunkInitFragments: InitFragment[]; + + /** + * rendering in strict context + */ + strictMode?: boolean; + + /** + * true: renders as factory method, false: pure module content + */ + factory: boolean; + + /** + * the inlined entry module is wrapped in an IIFE, existing only when `factory` is set to false + */ + inlinedInIIFE?: boolean; +} declare interface ModuleResult { client: string; data: string; @@ -10402,7 +10455,7 @@ declare abstract class ModuleTemplate { fn: ( source: Source, module: Module, - chunkRenderContext: ChunkRenderContextJavascriptModulesPlugin, + moduleRenderContext: ModuleRenderContext, dependencyTemplates: DependencyTemplates ) => Source ) => void; @@ -10415,7 +10468,7 @@ declare abstract class ModuleTemplate { fn: ( source: Source, module: Module, - chunkRenderContext: ChunkRenderContextJavascriptModulesPlugin, + moduleRenderContext: ModuleRenderContext, dependencyTemplates: DependencyTemplates ) => Source ) => void; @@ -15976,9 +16029,52 @@ declare abstract class StackedMap { get size(): number; createChild(): StackedMap; } -type StartupRenderContext = RenderContextJavascriptModulesPlugin & { +declare interface StartupRenderContext { + /** + * the chunk + */ + chunk: Chunk; + + /** + * the dependency templates + */ + dependencyTemplates: DependencyTemplates; + + /** + * the runtime template + */ + runtimeTemplate: RuntimeTemplate; + + /** + * the module graph + */ + moduleGraph: ModuleGraph; + + /** + * the chunk graph + */ + chunkGraph: ChunkGraph; + + /** + * results of code generation + */ + codeGenerationResults: CodeGenerationResults; + + /** + * rendering in strict context + */ + strictMode?: boolean; + + /** + * inlined + */ inlined: boolean; -}; + + /** + * the inlined entry module is wrapped in an IIFE + */ + inlinedInIIFE?: boolean; +} declare interface StatFs { ( path: PathLikeFs,