diff --git a/lib/config/normalization.js b/lib/config/normalization.js index 3cfdfea70..3002f0811 100644 --- a/lib/config/normalization.js +++ b/lib/config/normalization.js @@ -346,6 +346,7 @@ const getNormalizedWebpackOptions = config => ({ importFunctionName: output.importFunctionName, importMetaName: output.importMetaName, scriptType: output.scriptType, + // TODO webpack6 remove `libraryTarget`/`auxiliaryComment`/`amdContainer`/etc in favor of the `library` option library: libraryBase && { type: output.libraryTarget !== undefined diff --git a/lib/library/EnableLibraryPlugin.js b/lib/library/EnableLibraryPlugin.js index 2c7ae3415..74edc396b 100644 --- a/lib/library/EnableLibraryPlugin.js +++ b/lib/library/EnableLibraryPlugin.js @@ -80,7 +80,8 @@ class EnableLibraryPlugin { new ExportPropertyTemplatePlugin({ type, nsObjectUsed: !["module", "modern-module"].includes(type), - runtimeExportsUsed: type !== "modern-module" + runtimeExportsUsed: !["module", "modern-module"].includes(type), + renderStartupUsed: !["module", "modern-module"].includes(type) }).apply(compiler); }; switch (type) { @@ -252,7 +253,8 @@ class EnableLibraryPlugin { }).apply(compiler); break; } - case "module": { + case "module": + case "modern-module": { enableExportProperty(); const ModuleLibraryPlugin = require("./ModuleLibraryPlugin"); new ModuleLibraryPlugin({ @@ -260,14 +262,6 @@ class EnableLibraryPlugin { }).apply(compiler); break; } - case "modern-module": { - enableExportProperty(); - const ModernModuleLibraryPlugin = require("./ModernModuleLibraryPlugin"); - new ModernModuleLibraryPlugin({ - type - }).apply(compiler); - break; - } default: throw new Error(`Unsupported library type ${type}. Plugins which provide custom library types must call EnableLibraryPlugin.setEnabled(compiler, type) to disable this error.`); diff --git a/lib/library/ExportPropertyLibraryPlugin.js b/lib/library/ExportPropertyLibraryPlugin.js index 72b92f724..8825bc089 100644 --- a/lib/library/ExportPropertyLibraryPlugin.js +++ b/lib/library/ExportPropertyLibraryPlugin.js @@ -31,6 +31,7 @@ const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); * @property {LibraryType} type * @property {boolean} nsObjectUsed the namespace object is used * @property {boolean} runtimeExportsUsed runtime exports are used + * @property {boolean} renderStartupUsed render startup is used */ /** * @typedef {ExportPropertyLibraryPluginParsed} T @@ -40,13 +41,14 @@ class ExportPropertyLibraryPlugin extends AbstractLibraryPlugin { /** * @param {ExportPropertyLibraryPluginOptions} options options */ - constructor({ type, nsObjectUsed, runtimeExportsUsed }) { + constructor({ type, nsObjectUsed, runtimeExportsUsed, renderStartupUsed }) { super({ pluginName: "ExportPropertyLibraryPlugin", type }); this.nsObjectUsed = nsObjectUsed; this.runtimeExportsUsed = runtimeExportsUsed; + this.renderStartupUsed = renderStartupUsed; } /** @@ -109,6 +111,7 @@ class ExportPropertyLibraryPlugin extends AbstractLibraryPlugin { * @returns {Source} source with library export */ renderStartup(source, module, renderContext, { options }) { + if (!this.renderStartupUsed) return source; if (!options.export) return source; const postfix = `${RuntimeGlobals.exports} = ${ RuntimeGlobals.exports diff --git a/lib/library/ModernModuleLibraryPlugin.js b/lib/library/ModernModuleLibraryPlugin.js deleted file mode 100644 index fe0d66d40..000000000 --- a/lib/library/ModernModuleLibraryPlugin.js +++ /dev/null @@ -1,157 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const { ConcatSource } = require("webpack-sources"); -const ConcatenatedModule = require("../optimize/ConcatenatedModule"); -const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); - -/** @typedef {import("webpack-sources").Source} Source */ -/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */ -/** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */ -/** @typedef {import("../Chunk")} Chunk */ -/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */ -/** @typedef {import("../Compiler")} Compiler */ -/** @typedef {import("../Module")} Module */ -/** @typedef {import("../Module").BuildMeta} BuildMeta */ -/** @typedef {import("../javascript/JavascriptModulesPlugin").StartupRenderContext} StartupRenderContext */ -/** @typedef {import("../util/Hash")} Hash */ -/** @template T @typedef {import("./AbstractLibraryPlugin").LibraryContext} LibraryContext */ - -/** - * @typedef {object} ModernModuleLibraryPluginOptions - * @property {LibraryType} type - */ - -/** - * @typedef {object} ModernModuleLibraryPluginParsed - * @property {string} name - */ - -/** - * @typedef {ModernModuleLibraryPluginParsed} T - * @extends {AbstractLibraryPlugin} - */ -class ModernModuleLibraryPlugin extends AbstractLibraryPlugin { - /** - * Apply the plugin - * @param {Compiler} compiler the compiler instance - * @returns {void} - */ - apply(compiler) { - super.apply(compiler); - - compiler.hooks.compilation.tap("ModernModuleLibraryPlugin", compilation => { - const { exportsDefinitions } = - ConcatenatedModule.getCompilationHooks(compilation); - exportsDefinitions.tap("ModernModuleLibraryPlugin", () => true); - }); - } - - /** - * @param {ModernModuleLibraryPluginOptions} options the plugin options - */ - constructor(options) { - super({ - pluginName: "ModernModuleLibraryPlugin", - type: options.type - }); - } - - /** - * @param {LibraryOptions} library normalized library option - * @returns {T | false} preprocess as needed by overriding - */ - parseOptions(library) { - const { name } = library; - if (name) { - throw new Error( - `Library name must be unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}` - ); - } - const _name = /** @type {string} */ (name); - return { - name: _name - }; - } - - /** - * @param {Source} source source - * @param {Module} module module - * @param {StartupRenderContext} renderContext render context - * @param {LibraryContext} libraryContext context - * @returns {Source} source with library export - */ - renderStartup( - source, - module, - { moduleGraph, chunk }, - { options, compilation } - ) { - const result = new ConcatSource(source); - const exportsInfo = moduleGraph.getExportsInfo(module); - const definitions = - /** @type {BuildMeta} */ - (module.buildMeta).exportsFinalName; - const shortHandedExports = []; - const exports = []; - - for (const exportInfo of exportsInfo.orderedExports) { - let shouldContinue = false; - const reexport = exportInfo.findTarget(moduleGraph, _m => true); - - if (reexport) { - const exp = moduleGraph.getExportsInfo(reexport.module); - - for (const reexportInfo of exp.orderedExports) { - if ( - reexportInfo.provided === false && - reexportInfo.name === /** @type {string[]} */ (reexport.export)[0] - ) { - shouldContinue = true; - } - } - } - - if (shouldContinue) continue; - - const webpackExportsProperty = exportInfo.getUsedName( - exportInfo.name, - chunk.runtime - ); - const finalName = - definitions && - definitions[ - /** @type {string} */ - (webpackExportsProperty) - ]; - - if (finalName && (finalName.includes(".") || finalName.includes("["))) { - exports.push([exportInfo.name, finalName]); - } else { - shortHandedExports.push( - finalName === exportInfo.name - ? finalName - : `${finalName} as ${exportInfo.name}` - ); - } - } - - if (shortHandedExports.length > 0) { - result.add(`export { ${shortHandedExports.join(", ")} };\n`); - } - - for (const [exportName, final] of exports) { - result.add( - `export ${compilation.outputOptions.environment.const ? "const" : "var"} ${exportName} = ${final};\n` - ); - } - - return result; - } -} - -module.exports = ModernModuleLibraryPlugin; diff --git a/lib/library/ModuleLibraryPlugin.js b/lib/library/ModuleLibraryPlugin.js index 57afdc3e1..b57fa1c3a 100644 --- a/lib/library/ModuleLibraryPlugin.js +++ b/lib/library/ModuleLibraryPlugin.js @@ -8,6 +8,7 @@ const { ConcatSource } = require("webpack-sources"); const RuntimeGlobals = require("../RuntimeGlobals"); const Template = require("../Template"); +const ConcatenatedModule = require("../optimize/ConcatenatedModule"); const propertyAccess = require("../util/propertyAccess"); const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); @@ -18,9 +19,14 @@ const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); /** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */ /** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Module")} Module */ +/** @typedef {import("../Module").BuildMeta} BuildMeta */ /** @typedef {import("../javascript/JavascriptModulesPlugin").StartupRenderContext} StartupRenderContext */ /** @typedef {import("../util/Hash")} Hash */ -/** @template T @typedef {import("./AbstractLibraryPlugin").LibraryContext} LibraryContext */ + +/** + * @template T + * @typedef {import("./AbstractLibraryPlugin").LibraryContext} LibraryContext + */ /** * @typedef {object} ModuleLibraryPluginOptions @@ -30,6 +36,7 @@ const AbstractLibraryPlugin = require("./AbstractLibraryPlugin"); /** * @typedef {object} ModuleLibraryPluginParsed * @property {string} name + * @property {string | string[]=} export */ /** @@ -47,6 +54,45 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { }); } + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + super.apply(compiler); + + compiler.hooks.compilation.tap("ModernModuleLibraryPlugin", compilation => { + const { exportsDefinitions } = + ConcatenatedModule.getCompilationHooks(compilation); + exportsDefinitions.tap( + "ModernModuleLibraryPlugin", + (definitions, module) => { + // 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()) { + return false; + } + } + + return true; + } + ); + }); + } + /** * @param {LibraryOptions} library normalized library option * @returns {T | false} preprocess as needed by overriding @@ -60,7 +106,8 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { } const _name = /** @type {string} */ (name); return { - name: _name + name: _name, + export: library.export }; } @@ -78,30 +125,89 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin { { options, compilation } ) { const result = new ConcatSource(source); - const exportsInfo = moduleGraph.getExportsInfo(module); + const exportsInfos = options.export + ? [ + moduleGraph.getExportInfo( + module, + Array.isArray(options.export) ? options.export[0] : options.export + ) + ] + : moduleGraph.getExportsInfo(module).orderedExports; + const definitions = + /** @type {BuildMeta} */ + (module.buildMeta).exportsFinalName || {}; + const shortHandedExports = []; const exports = []; const isAsync = moduleGraph.isAsync(module); + if (isAsync) { result.add( `${RuntimeGlobals.exports} = await ${RuntimeGlobals.exports};\n` ); } - for (const exportInfo of exportsInfo.orderedExports) { + + for (const exportInfo of exportsInfos) { if (!exportInfo.provided) continue; - const varName = `${RuntimeGlobals.exports}${Template.toIdentifier( - exportInfo.name - )}`; - result.add( - `var ${varName} = ${RuntimeGlobals.exports}${propertyAccess([ - /** @type {string} */ - (exportInfo.getUsedName(exportInfo.name, chunk.runtime)) - ])};\n` + + let shouldContinue = false; + + const reexport = exportInfo.findTarget(moduleGraph, _m => true); + + if (reexport) { + const exp = moduleGraph.getExportsInfo(reexport.module); + + for (const reexportInfo of exp.orderedExports) { + if ( + reexportInfo.provided === false && + reexportInfo.name === /** @type {string[]} */ (reexport.export)[0] + ) { + shouldContinue = true; + } + } + } + + if (shouldContinue) continue; + + const webpackExportsProperty = exportInfo.getUsedName( + exportInfo.name, + chunk.runtime ); - exports.push(`${varName} as ${exportInfo.name}`); + const definition = + definitions[/** @type {string} */ (webpackExportsProperty)]; + const finalName = + definition || + `${RuntimeGlobals.exports}${Template.toIdentifier(exportInfo.name)}`; + + if (!definition) { + result.add( + `var ${finalName} = ${RuntimeGlobals.exports}${propertyAccess([ + /** @type {string} */ + (exportInfo.getUsedName(exportInfo.name, chunk.runtime)) + ])}\n` + ); + } + + if (finalName && (finalName.includes(".") || finalName.includes("["))) { + exports.push([exportInfo.name, finalName]); + } else { + shortHandedExports.push( + definition && finalName === exportInfo.name + ? finalName + : `${finalName} as ${exportInfo.name}` + ); + } } - if (exports.length > 0) { - result.add(`export { ${exports.join(", ")} };\n`); + + if (shortHandedExports.length > 0) { + result.add(`export { ${shortHandedExports.join(", ")} };\n`); } + + for (const [exportName, final] of exports) { + result.add( + `export ${compilation.outputOptions.environment.const ? "const" : "var"} ${exportName} = ${final};\n` + ); + } + return result; } } diff --git a/lib/optimize/ConcatenatedModule.js b/lib/optimize/ConcatenatedModule.js index a15dd929b..374a732ec 100644 --- a/lib/optimize/ConcatenatedModule.js +++ b/lib/optimize/ConcatenatedModule.js @@ -603,7 +603,7 @@ const getFinalName = ( /** * @typedef {object} ConcatenateModuleHooks - * @property {SyncBailHook<[Record], boolean | void>} exportsDefinitions + * @property {SyncBailHook<[Record, ConcatenatedModule], boolean | void>} exportsDefinitions */ /** @type {WeakMap} */ @@ -650,7 +650,7 @@ class ConcatenatedModule extends Module { let hooks = compilationHooksMap.get(compilation); if (hooks === undefined) { hooks = { - exportsDefinitions: new SyncBailHook(["definitions"]) + exportsDefinitions: new SyncBailHook(["definitions", "module"]) }; compilationHooksMap.set(compilation, hooks); } @@ -1488,7 +1488,8 @@ class ConcatenatedModule extends Module { // define exports if (exportsMap.size > 0) { const { exportsDefinitions } = ConcatenatedModule.getCompilationHooks( - /** @type {Compilation} */ (this.compilation) + /** @type {Compilation} */ + (this.compilation) ); const definitions = []; @@ -1499,8 +1500,11 @@ class ConcatenatedModule extends Module { )}` ); } - const shouldSkipRenderDefinitions = - exportsDefinitions.call(exportsFinalName); + + const shouldSkipRenderDefinitions = exportsDefinitions.call( + exportsFinalName, + this + ); if (!shouldSkipRenderDefinitions) { runtimeRequirements.add(RuntimeGlobals.exports); diff --git a/test/configCases/library/0-create-library/index-async.js b/test/configCases/library/0-create-library/index-async.js new file mode 100644 index 000000000..a0e48d70e --- /dev/null +++ b/test/configCases/library/0-create-library/index-async.js @@ -0,0 +1,14 @@ +export * from "./a"; +export default "default-value"; +export var b = "b"; +export { default as external } from "external"; +export * from "external-named"; + +const test = await 1; + +var module = "should not conflict", + define = "should not conflict", + require = "should not conflict", + exports = "should not conflict", + globalName = "should not conflict"; +console.log.bind(console, module, define, require, exports, globalName); diff --git a/test/configCases/library/0-create-library/webpack.config.js b/test/configCases/library/0-create-library/webpack.config.js index fcdb6bab4..48db10242 100644 --- a/test/configCases/library/0-create-library/webpack.config.js +++ b/test/configCases/library/0-create-library/webpack.config.js @@ -1,13 +1,16 @@ const path = require("path"); const webpack = require("../../../../"); +const supportsAsync = require("../../../helpers/supportsAsync"); /** @type {(env: any, options: any) => import("../../../../").Configuration[]} */ module.exports = (env, { testPath }) => [ { output: { - uniqueName: "esm", - filename: "esm.js", - libraryTarget: "module" + uniqueName: "modern-module", + filename: "modern-module.js", + library: { + type: "modern-module" + } }, target: "node14", resolve: { @@ -22,9 +25,11 @@ module.exports = (env, { testPath }) => [ }, { output: { - uniqueName: "modern-module", - filename: "modern-module.js", - libraryTarget: "modern-module" + uniqueName: "esm", + filename: "esm.js", + library: { + type: "module" + } }, target: "node14", resolve: { @@ -37,11 +42,105 @@ module.exports = (env, { testPath }) => [ outputModule: true } }, + { + output: { + uniqueName: "esm-export", + filename: "esm-export.js", + library: { + type: "module", + export: ["a"] + } + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + experiments: { + outputModule: true + } + }, + ...(supportsAsync() + ? [ + { + entry: "./index-async.js", + output: { + uniqueName: "esm-async", + filename: "esm-async.js", + library: { + type: "module" + } + }, + optimization: { + concatenateModules: true + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + experiments: { + outputModule: true + } + }, + { + entry: "./index-async.js", + output: { + uniqueName: "esm-async-no-concatenate-modules", + filename: "esm-async-no-concatenate-modules.js", + library: { + type: "module" + } + }, + optimization: { + concatenateModules: false + }, + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + experiments: { + outputModule: true + } + } + ] + : []), + { + output: { + uniqueName: "esm-export-no-concatenate-modules", + filename: "esm-export-no-concatenate-modules.js", + library: { + type: "module", + export: ["a"] + } + }, + target: "node14", + optimization: { + concatenateModules: false + }, + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + experiments: { + outputModule: true + } + }, { output: { uniqueName: "esm-runtimeChunk", filename: "esm-runtimeChunk/[name].js", - libraryTarget: "module" + library: { + type: "module" + } }, target: "node14", resolve: { @@ -57,11 +156,92 @@ module.exports = (env, { testPath }) => [ outputModule: true } }, + { + output: { + uniqueName: "esm-runtimeChunk-concatenateModules", + filename: "esm-runtimeChunk-concatenateModules/[name].js", + library: { + type: "module" + } + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + optimization: { + runtimeChunk: "single", + concatenateModules: true + }, + experiments: { + outputModule: true + } + }, + { + output: { + uniqueName: "esm-runtimeChunk-no-concatenateModules", + filename: "esm-runtimeChunk-no-concatenateModules/[name].js", + library: { + type: "module" + } + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + optimization: { + runtimeChunk: "single", + concatenateModules: false + }, + experiments: { + outputModule: true + } + }, + { + output: { + uniqueName: "esm-runtimeChunk-concatenateModules-splitChunks", + filename: "esm-runtimeChunk-concatenateModules-splitChunks/[name].js", + library: { + type: "module" + } + }, + target: "node14", + resolve: { + alias: { + external: "./non-external", + "external-named": "./non-external-named" + } + }, + optimization: { + runtimeChunk: "single", + concatenateModules: true, + splitChunks: { + cacheGroups: { + module: { + test: /a\.js$/, + chunks: "all", + enforce: true, + reuseExistingChunk: true + } + } + } + }, + experiments: { + outputModule: true + } + }, { output: { uniqueName: "commonjs", filename: "commonjs.js", - libraryTarget: "commonjs", + library: { + type: "commonjs" + }, iife: false }, resolve: { @@ -75,7 +255,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs-iife", filename: "commonjs-iife.js", - libraryTarget: "commonjs", + library: { + type: "commonjs" + }, iife: true }, resolve: { @@ -89,7 +271,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "amd", filename: "amd.js", - libraryTarget: "amd", + library: { + type: "amd" + }, iife: false }, resolve: { @@ -103,7 +287,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "amd-iife", filename: "amd-iife.js", - libraryTarget: "amd", + library: { + type: "amd" + }, iife: true }, resolve: { @@ -117,7 +303,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "amd-runtimeChunk", filename: "amd-runtimeChunk/[name].js", - libraryTarget: "amd", + library: { + type: "amd" + }, globalObject: "global", iife: false }, @@ -136,7 +324,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "amd-iife-runtimeChunk", filename: "amd-iife-runtimeChunk/[name].js", - libraryTarget: "amd", + library: { + type: "amd" + }, globalObject: "global", iife: true }, @@ -155,7 +345,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "umd", filename: "umd.js", - libraryTarget: "umd" + library: { + type: "umd" + } }, resolve: { alias: { @@ -218,8 +410,10 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "umd-default", filename: "umd-default.js", - libraryTarget: "umd", - libraryExport: "default" + library: { + type: "umd", + export: "default" + } }, resolve: { alias: { @@ -232,7 +426,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "this", filename: "this.js", - libraryTarget: "this", + library: { + type: "this" + }, iife: false }, resolve: { @@ -246,7 +442,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "this-iife", filename: "this-iife.js", - libraryTarget: "this", + library: { + type: "this" + }, iife: true }, resolve: { @@ -301,8 +499,10 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs-nested", filename: "commonjs-nested.js", - libraryTarget: "commonjs", - libraryExport: "NS", + library: { + type: "commonjs", + export: "NS" + }, iife: false }, resolve: { @@ -317,8 +517,10 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs-nested-iife", filename: "commonjs-nested-iife.js", - libraryTarget: "commonjs", - libraryExport: "NS", + library: { + type: "commonjs", + export: "NS" + }, iife: true }, resolve: { @@ -332,7 +534,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-external", filename: "commonjs2-external.js", - libraryTarget: "commonjs2", + library: { + type: "commonjs2" + }, iife: false }, externals: ["external", "external-named"] @@ -341,7 +545,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-external-no-concat", filename: "commonjs2-external-no-concat.js", - libraryTarget: "commonjs2", + library: { + type: "commonjs2" + }, iife: false }, optimization: { @@ -353,7 +559,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-iife-external", filename: "commonjs2-iife-external.js", - libraryTarget: "commonjs2", + library: { + type: "commonjs2" + }, iife: true }, externals: ["external", "external-named"] @@ -363,7 +571,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-external-eval", filename: "commonjs2-external-eval.js", - libraryTarget: "commonjs2" + library: { + type: "commonjs2" + } }, externals: ["external", "external-named"] }, @@ -372,7 +582,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-external-eval-source-map", filename: "commonjs2-external-eval-source-map.js", - libraryTarget: "commonjs2" + library: { + type: "commonjs2" + } }, devtool: "eval-source-map", externals: ["external", "external-named"] @@ -381,7 +593,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs-static-external", filename: "commonjs-static-external.js", - libraryTarget: "commonjs-static", + library: { + type: "commonjs-static" + }, iife: false }, externals: ["external", "external-named"] @@ -391,7 +605,9 @@ module.exports = (env, { testPath }) => [ uniqueName: "index", filename: "index.js", path: path.resolve(testPath, "commonjs2-split-chunks"), - libraryTarget: "commonjs2" + library: { + type: "commonjs2" + } }, target: "node", optimization: { @@ -417,7 +633,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-runtimeChunk", filename: "commonjs2-runtimeChunk/[name].js", - libraryTarget: "commonjs2", + library: { + type: "commonjs2" + }, iife: false }, resolve: { @@ -434,7 +652,9 @@ module.exports = (env, { testPath }) => [ output: { uniqueName: "commonjs2-iife-runtimeChunk", filename: "commonjs2-iife-runtimeChunk/[name].js", - libraryTarget: "commonjs2", + library: { + type: "commonjs2" + }, iife: true }, resolve: { diff --git a/test/configCases/library/1-use-library/module-export-test.js b/test/configCases/library/1-use-library/module-export-test.js new file mode 100644 index 000000000..0f1e4cb4d --- /dev/null +++ b/test/configCases/library/1-use-library/module-export-test.js @@ -0,0 +1,5 @@ +import * as mod from "library"; + +it("should tree-shake other exports from library (" + NAME + ") and export only 'a'", function() { + expect(mod).toMatchObject({ a: "a" }); +}); diff --git a/test/configCases/library/1-use-library/webpack.config.js b/test/configCases/library/1-use-library/webpack.config.js index 6865d7fee..c9ed1d553 100644 --- a/test/configCases/library/1-use-library/webpack.config.js +++ b/test/configCases/library/1-use-library/webpack.config.js @@ -3,21 +3,10 @@ const webpack = require("../../../../"); const path = require("path"); +const supportsAsync = require("../../../helpers/supportsAsync"); /** @type {(env: any, options: any) => import("../../../../").Configuration[]} */ module.exports = (env, { testPath }) => [ - { - resolve: { - alias: { - library: path.resolve(testPath, "../0-create-library/esm.js") - } - }, - plugins: [ - new webpack.DefinePlugin({ - NAME: JSON.stringify("esm") - }) - ] - }, { entry: "./default-test-modern-module.js", optimization: { @@ -57,6 +46,81 @@ module.exports = (env, { testPath }) => [ } ] }, + { + resolve: { + alias: { + library: path.resolve(testPath, "../0-create-library/esm.js") + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm") + }) + ] + }, + { + entry: "./module-export-test.js", + resolve: { + alias: { + library: path.resolve(testPath, "../0-create-library/esm-export.js") + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-export") + }) + ] + }, + { + entry: "./module-export-test.js", + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-export-no-concatenate-modules.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-export-no-concatenate-modules.js") + }) + ] + }, + ...(supportsAsync() + ? [ + { + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-async.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-async") + }) + ] + }, + { + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-async-no-concatenate-modules.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-async-no-concatenate-modules") + }) + ] + } + ] + : []), { resolve: { alias: { @@ -72,6 +136,51 @@ module.exports = (env, { testPath }) => [ }) ] }, + { + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-runtimeChunk-concatenateModules/main.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-runtimeChunk-concatenateModules") + }) + ] + }, + { + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-runtimeChunk-no-concatenateModules/main.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-runtimeChunk-no-concatenateModules") + }) + ] + }, + { + resolve: { + alias: { + library: path.resolve( + testPath, + "../0-create-library/esm-runtimeChunk-concatenateModules-splitChunks/main.js" + ) + } + }, + plugins: [ + new webpack.DefinePlugin({ + NAME: JSON.stringify("esm-runtimeChunk-concatenateModules-splitChunks") + }) + ] + }, { resolve: { alias: { diff --git a/test/helpers/supportsAsync.js b/test/helpers/supportsAsync.js new file mode 100644 index 000000000..ea517ad37 --- /dev/null +++ b/test/helpers/supportsAsync.js @@ -0,0 +1,15 @@ +module.exports = function supportsAsync() { + // Node.js@10 has a bug with nested async/await + if (process.version.startsWith("v10.")) { + return false; + } + + try { + eval("async () => {}"); + return true; + } catch (_err) { + // Ignore + } + + return false; +};