add library option to entry description

This commit is contained in:
Tobias Koppers 2020-02-26 12:34:57 +01:00
parent 39e407e927
commit 88e6c5e2a7
10 changed files with 252 additions and 127 deletions

View File

@ -65,6 +65,46 @@ export type Filename =
pathData: import("../lib/Compilation").PathData,
assetInfo?: import("../lib/Compilation").AssetInfo
) => string);
/**
* Add a comment in the UMD wrapper.
*/
export type AuxiliaryComment = string | LibraryCustomUmdCommentObject;
/**
* Specify which export should be exposed as library
*/
export type LibraryExport = string | ArrayOfStringValues;
/**
* Array of strings
*/
export type ArrayOfStringValues = string[];
/**
* The name of the library (some types allow unnamed libraries too)
*/
export type LibraryName = string | string[] | LibraryCustomUmdObject;
/**
* Type of library
*/
export type LibraryType =
| "var"
| "module"
| "assign"
| "this"
| "window"
| "self"
| "global"
| "commonjs"
| "commonjs2"
| "commonjs-module"
| "amd"
| "amd-require"
| "umd"
| "umd2"
| "jsonp"
| "system";
/**
* If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
*/
export type UmdNamedDefine = boolean;
/**
* An entry point without name.
*/
@ -105,10 +145,6 @@ export type ExternalItem =
| boolean;
}
| RegExp;
/**
* Array of strings
*/
export type ArrayOfStringValues = string[];
/**
* Specifies the default type of externals ('amd*', 'umd*', 'system' and 'jsonp' depend on output.libraryTarget set to the same value)
*/
@ -330,10 +366,6 @@ export type AssetModuleFilename =
pathData: import("../lib/Compilation").PathData,
assetInfo?: import("../lib/Compilation").AssetInfo
) => string);
/**
* Add a comment in the UMD wrapper.
*/
export type AuxiliaryComment = string | LibraryCustomUmdCommentObject;
/**
* The callback function name used by webpack for loading of chunks in WebWorkers.
*/
@ -370,26 +402,6 @@ export type DevtoolNamespace = string;
* The maximum EcmaScript version of the webpack generated code (doesn't include input source code from modules).
*/
export type EcmaVersion = number | 2009;
/**
* Type of library
*/
export type LibraryType =
| "var"
| "module"
| "assign"
| "this"
| "window"
| "self"
| "global"
| "commonjs"
| "commonjs2"
| "commonjs-module"
| "amd"
| "amd-require"
| "umd"
| "umd2"
| "jsonp"
| "system";
/**
* List of library types enabled for use by entry points
*/
@ -442,18 +454,6 @@ export type JsonpScriptType = false | "text/javascript" | "module";
* Make the output files a library, exporting the exports of the entry point
*/
export type Library = LibraryName | LibraryOptions;
/**
* The name of the library (some types allow unnamed libraries too)
*/
export type LibraryName = string | string[] | LibraryCustomUmdObject;
/**
* Specify which export should be exposed as library
*/
export type LibraryExport = string | ArrayOfStringValues;
/**
* If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
*/
export type UmdNamedDefine = boolean;
/**
* Output javascript files as module source type.
*/
@ -824,6 +824,73 @@ export interface EntryDescription {
* Module(s) that are loaded upon startup
*/
import: EntryItem;
/**
* Options for library
*/
library?: LibraryOptions;
}
/**
* Options for library
*/
export interface LibraryOptions {
/**
* Add a comment in the UMD wrapper.
*/
auxiliaryComment?: AuxiliaryComment;
/**
* Specify which export should be exposed as library
*/
export?: LibraryExport;
/**
* The name of the library (some types allow unnamed libraries too)
*/
name?: LibraryName;
/**
* Type of library
*/
type: LibraryType;
/**
* If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
*/
umdNamedDefine?: UmdNamedDefine;
}
/**
* Set explicit comments for `commonjs`, `commonjs2`, `amd`, and `root`.
*/
export interface LibraryCustomUmdCommentObject {
/**
* Set comment for `amd` section in UMD
*/
amd?: string;
/**
* Set comment for `commonjs` (exports) section in UMD
*/
commonjs?: string;
/**
* Set comment for `commonjs2` (module.exports) section in UMD
*/
commonjs2?: string;
/**
* Set comment for `root` (global variable) section in UMD
*/
root?: string;
}
/**
* Description object for all UMD variants of the library name
*/
export interface LibraryCustomUmdObject {
/**
* Name of the exposed AMD library in the UMD
*/
amd?: string;
/**
* Name of the exposed commonjs export in the UMD
*/
commonjs?: string;
/**
* Name of the property exposed globally by a UMD library
*/
root?: string | ArrayOfStringValues;
}
/**
* Enables/Disables experiments (experiemental features with relax SemVer compatibility)
@ -1615,69 +1682,6 @@ export interface Output {
*/
webassemblyModuleFilename?: WebassemblyModuleFilename;
}
/**
* Set explicit comments for `commonjs`, `commonjs2`, `amd`, and `root`.
*/
export interface LibraryCustomUmdCommentObject {
/**
* Set comment for `amd` section in UMD
*/
amd?: string;
/**
* Set comment for `commonjs` (exports) section in UMD
*/
commonjs?: string;
/**
* Set comment for `commonjs2` (module.exports) section in UMD
*/
commonjs2?: string;
/**
* Set comment for `root` (global variable) section in UMD
*/
root?: string;
}
/**
* Description object for all UMD variants of the library name
*/
export interface LibraryCustomUmdObject {
/**
* Name of the exposed AMD library in the UMD
*/
amd?: string;
/**
* Name of the exposed commonjs export in the UMD
*/
commonjs?: string;
/**
* Name of the property exposed globally by a UMD library
*/
root?: string | ArrayOfStringValues;
}
/**
* Options for library
*/
export interface LibraryOptions {
/**
* Add a comment in the UMD wrapper.
*/
auxiliaryComment?: AuxiliaryComment;
/**
* Specify which export should be exposed as library
*/
export?: LibraryExport;
/**
* The name of the library (some types allow unnamed libraries too)
*/
name?: LibraryName;
/**
* Type of library
*/
type: LibraryType;
/**
* If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
*/
umdNamedDefine?: UmdNamedDefine;
}
/**
* Configuration object for web performance recommendations
*/
@ -1972,6 +1976,10 @@ export interface EntryDescriptionNormalized {
* Module(s) that are loaded upon startup. The last one is exported.
*/
import: NonEmptyArrayOfUniqueStringValues;
/**
* Options for library
*/
library?: LibraryOptions;
}
/**
* Multiple entry bundles are created. The key is the entry name. The value is an entry description object.

View File

@ -48,6 +48,7 @@ class DynamicEntryPlugin {
for (const name of Object.keys(entry)) {
const desc = entry[name];
const options = EntryOptionPlugin.entryDescriptionToOptions(
compiler,
name,
desc
);

View File

@ -24,6 +24,7 @@ class EntryOptionPlugin {
for (const name of Object.keys(entry)) {
const desc = entry[name];
const options = EntryOptionPlugin.entryDescriptionToOptions(
compiler,
name,
desc
);
@ -37,17 +38,23 @@ class EntryOptionPlugin {
}
/**
* @param {Compiler} compiler the compiler
* @param {string} name entry name
* @param {EntryDescription} desc entry description
* @returns {EntryOptions} options for the entry
*/
static entryDescriptionToOptions(name, desc) {
static entryDescriptionToOptions(compiler, name, desc) {
/** @type {EntryOptions} */
const options = {
name,
filename: desc.filename,
dependOn: desc.dependOn
dependOn: desc.dependOn,
library: desc.library
};
if (desc.library) {
const EnableLibraryPlugin = require("./library/EnableLibraryPlugin");
EnableLibraryPlugin.checkEnabled(compiler, desc.library.type);
}
return options;
}
}

View File

@ -124,6 +124,12 @@ const applyWebpackOptionsDefaults = options => {
if (options.output.library) {
options.output.enabledLibraryTypes.push(options.output.library.type);
}
for (const name of Object.keys(options.entry)) {
const desc = options.entry[name];
if (desc.library) {
options.output.enabledLibraryTypes.push(desc.library.type);
}
}
F(options, "externalsType", () =>
options.output.library

View File

@ -325,7 +325,8 @@ const getNormalizedEntryStatic = entry => {
filename: value.filename,
dependOn:
value.dependOn &&
(Array.isArray(value.dependOn) ? value.dependOn : [value.dependOn])
(Array.isArray(value.dependOn) ? value.dependOn : [value.dependOn]),
library: value.library
};
}
}

View File

@ -49,11 +49,14 @@ class AbstractLibraryPlugin {
const { _pluginName } = this;
compiler.hooks.thisCompilation.tap(_pluginName, compilation => {
compilation.hooks.finishModules.tap(_pluginName, () => {
const options = this._parseOptionsCached(
compilation.outputOptions.library
);
if (options !== false) {
for (const { dependencies: deps } of compilation.entries.values()) {
for (const {
dependencies: deps,
options: { library }
} of compilation.entries.values()) {
const options = this._parseOptionsCached(
library !== undefined ? library : compilation.outputOptions.library
);
if (options !== false) {
const dep = deps[deps.length - 1];
if (dep) {
const module = compilation.moduleGraph.getModule(dep);
@ -65,14 +68,20 @@ class AbstractLibraryPlugin {
}
});
const getOptionsForChunk = chunk => {
if (compilation.chunkGraph.getNumberOfEntryModules(chunk) === 0)
return false;
const entry = compilation.entries.get(chunk.name);
const library = entry && entry.options.library;
return this._parseOptionsCached(
library !== undefined ? library : compilation.outputOptions.library
);
};
compilation.hooks.additionalChunkRuntimeRequirements.tap(
_pluginName,
(chunk, set) => {
if (compilation.chunkGraph.getNumberOfEntryModules(chunk) === 0)
return;
const options = this._parseOptionsCached(
compilation.outputOptions.library
);
const options = getOptionsForChunk(chunk);
if (options !== false) {
this.runtimeRequirements(chunk, set, { options, compilation });
}
@ -82,21 +91,13 @@ class AbstractLibraryPlugin {
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
hooks.render.tap(_pluginName, (source, renderContext) => {
const { chunk, chunkGraph } = renderContext;
if (chunkGraph.getNumberOfEntryModules(chunk) === 0) return source;
const options = this._parseOptionsCached(
compilation.outputOptions.library
);
const options = getOptionsForChunk(renderContext.chunk);
if (options === false) return source;
return this.render(source, renderContext, { options, compilation });
});
hooks.chunkHash.tap(_pluginName, (chunk, hash, context) => {
const { chunkGraph } = context;
if (chunkGraph.getNumberOfEntryModules(chunk) === 0) return;
const options = this._parseOptionsCached(
compilation.outputOptions.library
);
const options = getOptionsForChunk(chunk);
if (options === false) return;
this.chunkHash(chunk, hash, context, { options, compilation });
});

View File

@ -29,6 +29,23 @@ class EnableLibraryPlugin {
this.type = type;
}
/**
* @param {Compiler} compiler the compiler instance
* @param {LibraryType} type type of library
* @returns {void}
*/
static checkEnabled(compiler, type) {
if (!getEnabledTypes(compiler).has(type)) {
throw new Error(
`Library type "${type}" is not enabled. ` +
"EnableLibraryPlugin need to be used to enable this type of library. " +
'This usually happens through the "output.enabledLibraryTypes" option. ' +
'If you are using a function as entry which sets "library", you need to add all potential library types to "output.enabledLibraryTypes". ' +
Array.from(getEnabledTypes(compiler)).join(", ")
);
}
}
/**
* @param {Compiler} compiler the compiler instance
* @returns {void}
@ -37,7 +54,9 @@ class EnableLibraryPlugin {
const { type } = this;
// Only enable once
if (getEnabledTypes(compiler).has(type)) return;
const enabled = getEnabledTypes(compiler);
if (enabled.has(type)) return;
enabled.add(type);
if (typeof type === "string") {
const ExportPropertyTemplatePlugin = require("./ExportPropertyLibraryPlugin");

View File

@ -251,6 +251,9 @@
},
"import": {
"$ref": "#/definitions/EntryItem"
},
"library": {
"$ref": "#/definitions/LibraryOptions"
}
},
"required": ["import"]
@ -278,6 +281,9 @@
"$ref": "#/definitions/NonEmptyArrayOfUniqueStringValues"
}
]
},
"library": {
"$ref": "#/definitions/LibraryOptions"
}
},
"required": ["import"]

View File

@ -97,5 +97,36 @@ module.exports = [
external: "./non-external"
}
}
},
{
entry: {
entryA: {
import: "./index"
},
entryB: {
import: "./index",
library: {
type: "umd",
name: "umd"
}
},
entryC: {
import: "./index",
library: {
type: "amd"
}
}
},
output: {
library: {
type: "commonjs-module"
},
filename: "[name].js"
},
resolve: {
alias: {
external: "./non-external"
}
}
}
];

View File

@ -111,5 +111,50 @@ module.exports = [
NAME: JSON.stringify("default")
})
]
},
{
resolve: {
alias: {
library: path.resolve(
__dirname,
"../../../js/config/library/0-create-library/entryA.js"
)
}
},
plugins: [
new webpack.DefinePlugin({
NAME: JSON.stringify("entryA")
})
]
},
{
resolve: {
alias: {
library: path.resolve(
__dirname,
"../../../js/config/library/0-create-library/entryB.js"
)
}
},
plugins: [
new webpack.DefinePlugin({
NAME: JSON.stringify("entryB")
})
]
},
{
resolve: {
alias: {
library: path.resolve(
__dirname,
"../../../js/config/library/0-create-library/entryC.js"
)
}
},
plugins: [
new webpack.DefinePlugin({
NAME: JSON.stringify("entryC")
})
]
}
];