Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #7251 from webpack/types/library_templates
Add typings for library template plugins
  • Loading branch information
sokra committed May 28, 2018
2 parents 3f183b5 + 91546a1 commit 5c51f0c
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 65 deletions.
10 changes: 10 additions & 0 deletions lib/AmdMainTemplatePlugin.js
Expand Up @@ -8,11 +8,21 @@
const { ConcatSource } = require("webpack-sources");
const Template = require("./Template");

/** @typedef {import("./Compilation")} Compilation */

class AmdMainTemplatePlugin {
/**
* @param {string} name the library name
*/
constructor(name) {
/** @type {string} */
this.name = name;
}

/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate } = compilation;

Expand Down
13 changes: 13 additions & 0 deletions lib/ExportPropertyMainTemplatePlugin.js
Expand Up @@ -6,15 +6,28 @@

const { ConcatSource } = require("webpack-sources");

/** @typedef {import("./Compilation")} Compilation */

/**
* @param {string[]} accessor the accessor to convert to path
* @returns {string} the path
*/
const accessorToObjectAccess = accessor => {
return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
};

class ExportPropertyMainTemplatePlugin {
/**
* @param {string|string[]} property the name of the property to export
*/
constructor(property) {
this.property = property;
}

/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate } = compilation;

Expand Down
99 changes: 66 additions & 33 deletions lib/LibraryTemplatePlugin.js
Expand Up @@ -6,30 +6,45 @@

const SetVarMainTemplatePlugin = require("./SetVarMainTemplatePlugin");

/** @typedef {import("./Compiler")} Compiler */

/**
* @param {string[]} accessor the accessor to convert to path
* @returns {string} the path
*/
const accessorToObjectAccess = accessor => {
return accessor
.map(a => {
return `[${JSON.stringify(a)}]`;
})
.join("");
return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
};

const accessorAccess = (base, accessor, joinWith) => {
accessor = [].concat(accessor);
return accessor
.map((a, idx) => {
a = base
? base + accessorToObjectAccess(accessor.slice(0, idx + 1))
: accessor[0] + accessorToObjectAccess(accessor.slice(1, idx + 1));
if (idx === accessor.length - 1) return a;
/**
* @param {string=} base the path prefix
* @param {string|string[]} accessor the accessor
* @param {string=} joinWith the element separator
* @returns {string} the path
*/
const accessorAccess = (base, accessor, joinWith = "; ") => {
const accessors = Array.isArray(accessor) ? accessor : [accessor];
return accessors
.map((_, idx) => {
const a = base
? base + accessorToObjectAccess(accessors.slice(0, idx + 1))
: accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1));
if (idx === accessors.length - 1) return a;
if (idx === 0 && typeof base === "undefined")
return `${a} = typeof ${a} === "object" ? ${a} : {}`;
return `${a} = ${a} || {}`;
})
.join(joinWith || "; ");
.join(joinWith);
};

class LibraryTemplatePlugin {
/**
* @param {string} name name of library
* @param {string} target type of library
* @param {boolean} umdNamedDefine setting this to true will name the UMD module
* @param {string|TODO} auxiliaryComment comment in the UMD wrapper
* @param {string|string[]} exportProperty which export should be exposed as library
*/
constructor(name, target, umdNamedDefine, auxiliaryComment, exportProperty) {
this.name = name;
this.target = target;
Expand All @@ -38,77 +53,95 @@ class LibraryTemplatePlugin {
this.exportProperty = exportProperty;
}

/**
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.thisCompilation.tap("LibraryTemplatePlugin", compilation => {
if (this.exportProperty) {
var ExportPropertyMainTemplatePlugin = require("./ExportPropertyMainTemplatePlugin");
const ExportPropertyMainTemplatePlugin = require("./ExportPropertyMainTemplatePlugin");
new ExportPropertyMainTemplatePlugin(this.exportProperty).apply(
compilation
);
}
switch (this.target) {
case "var":
new SetVarMainTemplatePlugin(
`var ${accessorAccess(false, this.name)}`
`var ${accessorAccess(undefined, this.name)}`,
false
).apply(compilation);
break;
case "assign":
new SetVarMainTemplatePlugin(
accessorAccess(undefined, this.name)
accessorAccess(undefined, this.name),
false
).apply(compilation);
break;
case "this":
case "self":
case "window":
if (this.name)
if (this.name) {
new SetVarMainTemplatePlugin(
accessorAccess(this.target, this.name)
accessorAccess(this.target, this.name),
false
).apply(compilation);
else
} else {
new SetVarMainTemplatePlugin(this.target, true).apply(compilation);
}
break;
case "global":
if (this.name)
if (this.name) {
new SetVarMainTemplatePlugin(
accessorAccess(
compilation.runtimeTemplate.outputOptions.globalObject,
this.name
)
),
false
).apply(compilation);
else
} else {
new SetVarMainTemplatePlugin(
compilation.runtimeTemplate.outputOptions.globalObject,
true
).apply(compilation);
}
break;
case "commonjs":
if (this.name)
if (this.name) {
new SetVarMainTemplatePlugin(
accessorAccess("exports", this.name)
accessorAccess("exports", this.name),
false
).apply(compilation);
else new SetVarMainTemplatePlugin("exports", true).apply(compilation);
} else {
new SetVarMainTemplatePlugin("exports", true).apply(compilation);
}
break;
case "commonjs2":
case "commonjs-module":
new SetVarMainTemplatePlugin("module.exports").apply(compilation);
new SetVarMainTemplatePlugin("module.exports", false).apply(
compilation
);
break;
case "amd":
var AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin");
case "amd": {
const AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin");
new AmdMainTemplatePlugin(this.name).apply(compilation);
break;
}
case "umd":
case "umd2":
var UmdMainTemplatePlugin = require("./UmdMainTemplatePlugin");
case "umd2": {
const UmdMainTemplatePlugin = require("./UmdMainTemplatePlugin");
new UmdMainTemplatePlugin(this.name, {
optionalAmdExternalAsGlobal: this.target === "umd2",
namedDefine: this.umdNamedDefine,
auxiliaryComment: this.auxiliaryComment
}).apply(compilation);
break;
case "jsonp":
var JsonpExportMainTemplatePlugin = require("./web/JsonpExportMainTemplatePlugin");
}
case "jsonp": {
const JsonpExportMainTemplatePlugin = require("./web/JsonpExportMainTemplatePlugin");
new JsonpExportMainTemplatePlugin(this.name).apply(compilation);
break;
}
default:
throw new Error(`${this.target} is not a valid Library target`);
}
Expand Down
12 changes: 12 additions & 0 deletions lib/SetVarMainTemplatePlugin.js
Expand Up @@ -6,12 +6,24 @@

const { ConcatSource } = require("webpack-sources");

/** @typedef {import("./Compilation")} Compilation */

class SetVarMainTemplatePlugin {
/**
* @param {string} varExpression the accessor where the library is exported
* @param {boolean} copyObject specify copying the exports
*/
constructor(varExpression, copyObject) {
/** @type {string} */
this.varExpression = varExpression;
/** @type {boolean} */
this.copyObject = copyObject;
}

/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate } = compilation;

Expand Down
99 changes: 67 additions & 32 deletions lib/UmdMainTemplatePlugin.js
Expand Up @@ -7,22 +7,59 @@
const { ConcatSource, OriginalSource } = require("webpack-sources");
const Template = require("./Template");

function accessorToObjectAccess(accessor) {
/** @typedef {import("./Compilation")} Compilation */

/**
* @param {string[]} accessor the accessor to convert to path
* @returns {string} the path
*/
const accessorToObjectAccess = accessor => {
return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
}
};

function accessorAccess(base, accessor) {
accessor = [].concat(accessor);
return accessor
.map((a, idx) => {
a = base + accessorToObjectAccess(accessor.slice(0, idx + 1));
if (idx === accessor.length - 1) return a;
/**
* @param {string=} base the path prefix
* @param {string|string[]} accessor the accessor
* @param {string=} joinWith the element separator
* @returns {string} the path
*/
const accessorAccess = (base, accessor, joinWith = ", ") => {
const accessors = Array.isArray(accessor) ? accessor : [accessor];
return accessors
.map((_, idx) => {
const a = base
? base + accessorToObjectAccess(accessors.slice(0, idx + 1))
: accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1));
if (idx === accessors.length - 1) return a;
if (idx === 0 && typeof base === "undefined")
return `${a} = typeof ${a} === "object" ? ${a} : {}`;
return `${a} = ${a} || {}`;
})
.join(", ");
}
.join(joinWith);
};

/** @typedef {string | string[] | Record<string, string | string[]>} UmdMainTemplatePluginName */

/**
* @typedef {Object} AuxiliaryCommentObject
* @property {string} root
* @property {string} commonjs
* @property {string} commonjs2
* @property {string} amd
*/

/**
* @typedef {Object} UmdMainTemplatePluginOption
* @property {boolean=} optionalAmdExternalAsGlobal
* @property {boolean} namedDefine
* @property {string | AuxiliaryCommentObject} auxiliaryComment
*/

class UmdMainTemplatePlugin {
/**
* @param {UmdMainTemplatePluginName} name the name of the UMD library
* @param {UmdMainTemplatePluginOption} options the plugin option
*/
constructor(name, options) {
if (typeof name === "object" && !Array.isArray(name)) {
this.name = name.root || name.amd || name.commonjs;
Expand All @@ -40,6 +77,10 @@ class UmdMainTemplatePlugin {
this.auxiliaryComment = options.auxiliaryComment;
}

/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate, runtimeTemplate } = compilation;

Expand Down Expand Up @@ -152,23 +193,27 @@ class UmdMainTemplatePlugin {
amdFactory = "factory";
}

const auxiliaryComment = this.auxiliaryComment;

const getAuxilaryComment = type => {
if (auxiliaryComment) {
if (typeof auxiliaryComment === "string")
return "\t//" + auxiliaryComment + "\n";
if (auxiliaryComment[type])
return "\t//" + auxiliaryComment[type] + "\n";
}
return "";
};

return new ConcatSource(
new OriginalSource(
"(function webpackUniversalModuleDefinition(root, factory) {\n" +
(this.auxiliaryComment && typeof this.auxiliaryComment === "string"
? " //" + this.auxiliaryComment + "\n"
: this.auxiliaryComment.commonjs2
? " //" + this.auxiliaryComment.commonjs2 + "\n"
: "") +
getAuxilaryComment("commonjs2") +
" if(typeof exports === 'object' && typeof module === 'object')\n" +
" module.exports = factory(" +
externalsRequireArray("commonjs2") +
");\n" +
(this.auxiliaryComment && typeof this.auxiliaryComment === "string"
? " //" + this.auxiliaryComment + "\n"
: this.auxiliaryComment.amd
? " //" + this.auxiliaryComment.amd + "\n"
: "") +
getAuxilaryComment("amd") +
" else if(typeof define === 'function' && define.amd)\n" +
(requiredExternals.length > 0
? this.names.amd && this.namedDefine === true
Expand All @@ -192,24 +237,14 @@ class UmdMainTemplatePlugin {
");\n"
: " define([], " + amdFactory + ");\n") +
(this.names.root || this.names.commonjs
? (this.auxiliaryComment &&
typeof this.auxiliaryComment === "string"
? " //" + this.auxiliaryComment + "\n"
: this.auxiliaryComment.commonjs
? " //" + this.auxiliaryComment.commonjs + "\n"
: "") +
? getAuxilaryComment("commonjs") +
" else if(typeof exports === 'object')\n" +
" exports[" +
libraryName(this.names.commonjs || this.names.root) +
"] = factory(" +
externalsRequireArray("commonjs") +
");\n" +
(this.auxiliaryComment &&
typeof this.auxiliaryComment === "string"
? " //" + this.auxiliaryComment + "\n"
: this.auxiliaryComment.root
? " //" + this.auxiliaryComment.root + "\n"
: "") +
getAuxilaryComment("root") +
" else\n" +
" " +
replaceKeys(
Expand Down

0 comments on commit 5c51f0c

Please sign in to comment.