You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
7.0 KiB
233 lines
7.0 KiB
/* |
|
MIT License http://www.opensource.org/licenses/mit-license.php |
|
Author Joel Denning @joeldenning |
|
*/ |
|
|
|
"use strict"; |
|
|
|
const { ConcatSource } = require("webpack-sources"); |
|
const { UsageState } = require("../ExportsInfo"); |
|
const ExternalModule = require("../ExternalModule"); |
|
const Template = require("../Template"); |
|
const propertyAccess = require("../util/propertyAccess"); |
|
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("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */ |
|
/** @typedef {import("../util/Hash")} Hash */ |
|
/** @template T @typedef {import("./AbstractLibraryPlugin").LibraryContext<T>} LibraryContext<T> */ |
|
|
|
/** |
|
* @typedef {Object} SystemLibraryPluginOptions |
|
* @property {LibraryType} type |
|
*/ |
|
|
|
/** |
|
* @typedef {Object} SystemLibraryPluginParsed |
|
* @property {string} name |
|
*/ |
|
|
|
/** |
|
* @typedef {SystemLibraryPluginParsed} T |
|
* @extends {AbstractLibraryPlugin<SystemLibraryPluginParsed>} |
|
*/ |
|
class SystemLibraryPlugin extends AbstractLibraryPlugin { |
|
/** |
|
* @param {SystemLibraryPluginOptions} options the plugin options |
|
*/ |
|
constructor(options) { |
|
super({ |
|
pluginName: "SystemLibraryPlugin", |
|
type: options.type |
|
}); |
|
} |
|
|
|
/** |
|
* @param {LibraryOptions} library normalized library option |
|
* @returns {T | false} preprocess as needed by overriding |
|
*/ |
|
parseOptions(library) { |
|
const { name } = library; |
|
if (name && typeof name !== "string") { |
|
throw new Error( |
|
`System.js library name must be a simple string or unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}` |
|
); |
|
} |
|
return { |
|
name: /** @type {string=} */ (name) |
|
}; |
|
} |
|
|
|
/** |
|
* @param {Source} source source |
|
* @param {RenderContext} renderContext render context |
|
* @param {LibraryContext<T>} libraryContext context |
|
* @returns {Source} source with library export |
|
*/ |
|
render(source, { chunkGraph, moduleGraph, chunk }, { options, compilation }) { |
|
const modules = chunkGraph |
|
.getChunkModules(chunk) |
|
.filter(m => m instanceof ExternalModule && m.externalType === "system"); |
|
const externals = /** @type {ExternalModule[]} */ (modules); |
|
|
|
// The name this bundle should be registered as with System |
|
const name = options.name |
|
? `${JSON.stringify(compilation.getPath(options.name, { chunk }))}, ` |
|
: ""; |
|
|
|
// The array of dependencies that are external to webpack and will be provided by System |
|
const systemDependencies = JSON.stringify( |
|
externals.map(m => |
|
typeof m.request === "object" && !Array.isArray(m.request) |
|
? m.request.amd |
|
: m.request |
|
) |
|
); |
|
|
|
// The name of the variable provided by System for exporting |
|
const dynamicExport = "__WEBPACK_DYNAMIC_EXPORT__"; |
|
|
|
// An array of the internal variable names for the webpack externals |
|
const externalWebpackNames = externals.map( |
|
m => |
|
`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier( |
|
`${chunkGraph.getModuleId(m)}` |
|
)}__` |
|
); |
|
|
|
// Declaring variables for the internal variable names for the webpack externals |
|
const externalVarDeclarations = externalWebpackNames |
|
.map(name => `var ${name} = {};`) |
|
.join("\n"); |
|
|
|
// Define __esModule flag on all internal variables and helpers |
|
const externalVarInitialization = []; |
|
|
|
// The system.register format requires an array of setter functions for externals. |
|
const setters = |
|
externalWebpackNames.length === 0 |
|
? "" |
|
: Template.asString([ |
|
"setters: [", |
|
Template.indent( |
|
externals |
|
.map((module, i) => { |
|
const external = externalWebpackNames[i]; |
|
const exportsInfo = moduleGraph.getExportsInfo(module); |
|
const otherUnused = |
|
exportsInfo.otherExportsInfo.getUsed(chunk.runtime) === |
|
UsageState.Unused; |
|
const instructions = []; |
|
const handledNames = []; |
|
for (const exportInfo of exportsInfo.orderedExports) { |
|
const used = exportInfo.getUsedName( |
|
undefined, |
|
chunk.runtime |
|
); |
|
if (used) { |
|
if (otherUnused || used !== exportInfo.name) { |
|
instructions.push( |
|
`${external}${propertyAccess([ |
|
used |
|
])} = module${propertyAccess([exportInfo.name])};` |
|
); |
|
handledNames.push(exportInfo.name); |
|
} |
|
} else { |
|
handledNames.push(exportInfo.name); |
|
} |
|
} |
|
if (!otherUnused) { |
|
if ( |
|
!Array.isArray(module.request) || |
|
module.request.length === 1 |
|
) { |
|
externalVarInitialization.push( |
|
`Object.defineProperty(${external}, "__esModule", { value: true });` |
|
); |
|
} |
|
if (handledNames.length > 0) { |
|
const name = `${external}handledNames`; |
|
externalVarInitialization.push( |
|
`var ${name} = ${JSON.stringify(handledNames)};` |
|
); |
|
instructions.push( |
|
Template.asString([ |
|
"Object.keys(module).forEach(function(key) {", |
|
Template.indent([ |
|
`if(${name}.indexOf(key) >= 0)`, |
|
Template.indent(`${external}[key] = module[key];`) |
|
]), |
|
"});" |
|
]) |
|
); |
|
} else { |
|
instructions.push( |
|
Template.asString([ |
|
"Object.keys(module).forEach(function(key) {", |
|
Template.indent([`${external}[key] = module[key];`]), |
|
"});" |
|
]) |
|
); |
|
} |
|
} |
|
if (instructions.length === 0) return "function() {}"; |
|
return Template.asString([ |
|
"function(module) {", |
|
Template.indent(instructions), |
|
"}" |
|
]); |
|
}) |
|
.join(",\n") |
|
), |
|
"]," |
|
]); |
|
|
|
return new ConcatSource( |
|
Template.asString([ |
|
`System.register(${name}${systemDependencies}, function(${dynamicExport}, __system_context__) {`, |
|
Template.indent([ |
|
externalVarDeclarations, |
|
Template.asString(externalVarInitialization), |
|
"return {", |
|
Template.indent([ |
|
setters, |
|
"execute: function() {", |
|
Template.indent(`${dynamicExport}(`) |
|
]) |
|
]), |
|
"" |
|
]), |
|
source, |
|
Template.asString([ |
|
"", |
|
Template.indent([ |
|
Template.indent([Template.indent([");"]), "}"]), |
|
"};" |
|
]), |
|
"})" |
|
]) |
|
); |
|
} |
|
|
|
/** |
|
* @param {Chunk} chunk the chunk |
|
* @param {Hash} hash hash |
|
* @param {ChunkHashContext} chunkHashContext chunk hash context |
|
* @param {LibraryContext<T>} libraryContext context |
|
* @returns {void} |
|
*/ |
|
chunkHash(chunk, hash, chunkHashContext, { options, compilation }) { |
|
hash.update("SystemLibraryPlugin"); |
|
if (options.name) { |
|
hash.update(compilation.getPath(options.name, { chunk })); |
|
} |
|
} |
|
} |
|
|
|
module.exports = SystemLibraryPlugin;
|
|
|