simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

SystemLibraryPlugin.js (7165B)


      1 /*
      2 	MIT License http://www.opensource.org/licenses/mit-license.php
      3 	Author Joel Denning @joeldenning
      4 */
      5 
      6 "use strict";
      7 
      8 const { ConcatSource } = require("webpack-sources");
      9 const { UsageState } = require("../ExportsInfo");
     10 const ExternalModule = require("../ExternalModule");
     11 const Template = require("../Template");
     12 const propertyAccess = require("../util/propertyAccess");
     13 const AbstractLibraryPlugin = require("./AbstractLibraryPlugin");
     14 
     15 /** @typedef {import("webpack-sources").Source} Source */
     16 /** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
     17 /** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */
     18 /** @typedef {import("../Chunk")} Chunk */
     19 /** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
     20 /** @typedef {import("../Compiler")} Compiler */
     21 /** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */
     22 /** @typedef {import("../util/Hash")} Hash */
     23 /** @template T @typedef {import("./AbstractLibraryPlugin").LibraryContext<T>} LibraryContext<T> */
     24 
     25 /**
     26  * @typedef {Object} SystemLibraryPluginOptions
     27  * @property {LibraryType} type
     28  */
     29 
     30 /**
     31  * @typedef {Object} SystemLibraryPluginParsed
     32  * @property {string} name
     33  */
     34 
     35 /**
     36  * @typedef {SystemLibraryPluginParsed} T
     37  * @extends {AbstractLibraryPlugin<SystemLibraryPluginParsed>}
     38  */
     39 class SystemLibraryPlugin extends AbstractLibraryPlugin {
     40 	/**
     41 	 * @param {SystemLibraryPluginOptions} options the plugin options
     42 	 */
     43 	constructor(options) {
     44 		super({
     45 			pluginName: "SystemLibraryPlugin",
     46 			type: options.type
     47 		});
     48 	}
     49 
     50 	/**
     51 	 * @param {LibraryOptions} library normalized library option
     52 	 * @returns {T | false} preprocess as needed by overriding
     53 	 */
     54 	parseOptions(library) {
     55 		const { name } = library;
     56 		if (name && typeof name !== "string") {
     57 			throw new Error(
     58 				`System.js library name must be a simple string or unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}`
     59 			);
     60 		}
     61 		return {
     62 			name: /** @type {string=} */ (name)
     63 		};
     64 	}
     65 
     66 	/**
     67 	 * @param {Source} source source
     68 	 * @param {RenderContext} renderContext render context
     69 	 * @param {LibraryContext<T>} libraryContext context
     70 	 * @returns {Source} source with library export
     71 	 */
     72 	render(source, { chunkGraph, moduleGraph, chunk }, { options, compilation }) {
     73 		const modules = chunkGraph
     74 			.getChunkModules(chunk)
     75 			.filter(m => m instanceof ExternalModule && m.externalType === "system");
     76 		const externals = /** @type {ExternalModule[]} */ (modules);
     77 
     78 		// The name this bundle should be registered as with System
     79 		const name = options.name
     80 			? `${JSON.stringify(compilation.getPath(options.name, { chunk }))}, `
     81 			: "";
     82 
     83 		// The array of dependencies that are external to webpack and will be provided by System
     84 		const systemDependencies = JSON.stringify(
     85 			externals.map(m =>
     86 				typeof m.request === "object" && !Array.isArray(m.request)
     87 					? m.request.amd
     88 					: m.request
     89 			)
     90 		);
     91 
     92 		// The name of the variable provided by System for exporting
     93 		const dynamicExport = "__WEBPACK_DYNAMIC_EXPORT__";
     94 
     95 		// An array of the internal variable names for the webpack externals
     96 		const externalWebpackNames = externals.map(
     97 			m =>
     98 				`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
     99 					`${chunkGraph.getModuleId(m)}`
    100 				)}__`
    101 		);
    102 
    103 		// Declaring variables for the internal variable names for the webpack externals
    104 		const externalVarDeclarations = externalWebpackNames
    105 			.map(name => `var ${name} = {};`)
    106 			.join("\n");
    107 
    108 		// Define __esModule flag on all internal variables and helpers
    109 		const externalVarInitialization = [];
    110 
    111 		// The system.register format requires an array of setter functions for externals.
    112 		const setters =
    113 			externalWebpackNames.length === 0
    114 				? ""
    115 				: Template.asString([
    116 						"setters: [",
    117 						Template.indent(
    118 							externals
    119 								.map((module, i) => {
    120 									const external = externalWebpackNames[i];
    121 									const exportsInfo = moduleGraph.getExportsInfo(module);
    122 									const otherUnused =
    123 										exportsInfo.otherExportsInfo.getUsed(chunk.runtime) ===
    124 										UsageState.Unused;
    125 									const instructions = [];
    126 									const handledNames = [];
    127 									for (const exportInfo of exportsInfo.orderedExports) {
    128 										const used = exportInfo.getUsedName(
    129 											undefined,
    130 											chunk.runtime
    131 										);
    132 										if (used) {
    133 											if (otherUnused || used !== exportInfo.name) {
    134 												instructions.push(
    135 													`${external}${propertyAccess([
    136 														used
    137 													])} = module${propertyAccess([exportInfo.name])};`
    138 												);
    139 												handledNames.push(exportInfo.name);
    140 											}
    141 										} else {
    142 											handledNames.push(exportInfo.name);
    143 										}
    144 									}
    145 									if (!otherUnused) {
    146 										if (
    147 											!Array.isArray(module.request) ||
    148 											module.request.length === 1
    149 										) {
    150 											externalVarInitialization.push(
    151 												`Object.defineProperty(${external}, "__esModule", { value: true });`
    152 											);
    153 										}
    154 										if (handledNames.length > 0) {
    155 											const name = `${external}handledNames`;
    156 											externalVarInitialization.push(
    157 												`var ${name} = ${JSON.stringify(handledNames)};`
    158 											);
    159 											instructions.push(
    160 												Template.asString([
    161 													"Object.keys(module).forEach(function(key) {",
    162 													Template.indent([
    163 														`if(${name}.indexOf(key) >= 0)`,
    164 														Template.indent(`${external}[key] = module[key];`)
    165 													]),
    166 													"});"
    167 												])
    168 											);
    169 										} else {
    170 											instructions.push(
    171 												Template.asString([
    172 													"Object.keys(module).forEach(function(key) {",
    173 													Template.indent([`${external}[key] = module[key];`]),
    174 													"});"
    175 												])
    176 											);
    177 										}
    178 									}
    179 									if (instructions.length === 0) return "function() {}";
    180 									return Template.asString([
    181 										"function(module) {",
    182 										Template.indent(instructions),
    183 										"}"
    184 									]);
    185 								})
    186 								.join(",\n")
    187 						),
    188 						"],"
    189 				  ]);
    190 
    191 		return new ConcatSource(
    192 			Template.asString([
    193 				`System.register(${name}${systemDependencies}, function(${dynamicExport}, __system_context__) {`,
    194 				Template.indent([
    195 					externalVarDeclarations,
    196 					Template.asString(externalVarInitialization),
    197 					"return {",
    198 					Template.indent([
    199 						setters,
    200 						"execute: function() {",
    201 						Template.indent(`${dynamicExport}(`)
    202 					])
    203 				]),
    204 				""
    205 			]),
    206 			source,
    207 			Template.asString([
    208 				"",
    209 				Template.indent([
    210 					Template.indent([Template.indent([");"]), "}"]),
    211 					"};"
    212 				]),
    213 				"})"
    214 			])
    215 		);
    216 	}
    217 
    218 	/**
    219 	 * @param {Chunk} chunk the chunk
    220 	 * @param {Hash} hash hash
    221 	 * @param {ChunkHashContext} chunkHashContext chunk hash context
    222 	 * @param {LibraryContext<T>} libraryContext context
    223 	 * @returns {void}
    224 	 */
    225 	chunkHash(chunk, hash, chunkHashContext, { options, compilation }) {
    226 		hash.update("SystemLibraryPlugin");
    227 		if (options.name) {
    228 			hash.update(compilation.getPath(options.name, { chunk }));
    229 		}
    230 	}
    231 }
    232 
    233 module.exports = SystemLibraryPlugin;