Permalink
Browse files

Dynamic entry support (#3634)

* enable to set a function to entry option

* add tests for entry function

* fix style

* fix identifier and readableIdentifier of MultiModule

* use arrow functions

* use arrow function

* remove incorrect new operators

* fix Validation tests
  • Loading branch information...
1 parent 42b95d9 commit a22b00e23d44f58932a513084f02d376c75854f7 @nkzawa nkzawa committed with TheLarkInn Jan 9, 2017
@@ -0,0 +1,59 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Naoyuki Kanezawa @nkzawa
+*/
+"use strict";
+
+const MultiEntryDependency = require("./dependencies/MultiEntryDependency");
+const SingleEntryDependency = require("./dependencies/SingleEntryDependency");
+const MultiModuleFactory = require("./MultiModuleFactory");
+const MultiEntryPlugin = require("./MultiEntryPlugin");
+const SingleEntryPlugin = require("./SingleEntryPlugin");
+
+class DynamicEntryPlugin {
+ constructor(context, entry) {
+ this.context = context;
+ this.entry = entry;
+ }
+
+ apply(compiler) {
+ compiler.plugin("compilation", (compilation, params) => {
+ const multiModuleFactory = new MultiModuleFactory();
+ const normalModuleFactory = params.normalModuleFactory;
+
+ compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory);
+ compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
+ });
+
+ compiler.plugin("make", (compilation, callback) => {
+ const addEntry = (entry, name) => {
+ const dep = DynamicEntryPlugin.createDependency(entry, name);
+ return new Promise((resolve, reject) => {
+ compilation.addEntry(this.context, dep, name, (err) => {
+ if(err) return reject(err);
+ resolve();
+ });
+ })
+ };
+
+ Promise.resolve(this.entry()).then((entry) => {
+ if(typeof entry === "string" || Array.isArray(entry)) {
+ addEntry(entry, "main").then(() => callback(), callback);
+ } else if(typeof entry === "object") {
+ Promise.all(Object.keys(entry).map((name) => {
+ return addEntry(entry[name], name);
+ })).then(() => callback(), callback);
+ }
+ })
+ });
+ }
+}
+
+module.exports = DynamicEntryPlugin;
+
+DynamicEntryPlugin.createDependency = function(entry, name) {
+ if(Array.isArray(entry))
+ return MultiEntryPlugin.createDependency(entry, name);
+ else
+ return SingleEntryPlugin.createDependency(entry, name);
+};
@@ -6,6 +6,7 @@
const SingleEntryPlugin = require("./SingleEntryPlugin");
const MultiEntryPlugin = require("./MultiEntryPlugin");
+const DynamicEntryPlugin = require("./DynamicEntryPlugin");
module.exports = class EntryOptionPlugin {
apply(compiler) {
@@ -21,6 +22,8 @@ module.exports = class EntryOptionPlugin {
compiler.apply(itemToPlugin(entry, "main"));
} else if(typeof entry === "object") {
Object.keys(entry).forEach(name => compiler.apply(itemToPlugin(entry[name], name)));
+ } else if(typeof entry === "function") {
+ compiler.apply(new DynamicEntryPlugin(context, entry));
}
return true;
});
@@ -24,11 +24,16 @@ module.exports = class MultiEntryPlugin {
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
});
compiler.plugin("make", (compilation, callback) => {
- compilation.addEntry(this.context, new MultiEntryDependency(this.entries.map((e, idx) => {
- const dep = new SingleEntryDependency(e);
- dep.loc = `${this.name}:${(100000 + idx)}`;
- return dep;
- }, this), this.name), this.name, callback);
+ const dep = MultiEntryPlugin.createDependency(this.entries, this.name);
+ compilation.addEntry(this.context, dep, this.name, callback);
});
}
+
+ static createDependency(entries, name) {
+ return new MultiEntryDependency(entries.map((e, idx) => {
+ const dep = new SingleEntryDependency(e);
+ dep.loc = name + ":" + (100000 + idx);
+ return dep;
+ }), name);
+ }
}
View
@@ -19,11 +19,13 @@ MultiModule.prototype = Object.create(Module.prototype);
MultiModule.prototype.constructor = MultiModule;
MultiModule.prototype.identifier = function() {
- return "multi " + this.name;
+ return "multi " + this.dependencies.map((d) => d.request).join(" ");
};
-MultiModule.prototype.readableIdentifier = function() {
- return "multi " + this.name;
+MultiModule.prototype.readableIdentifier = function(requestShortener) {
+ return "multi " + this.dependencies.map((d) => {
+ return requestShortener.shorten(d.request);
+ }).join(" ");
};
MultiModule.prototype.disconnect = function disconnect() {
@@ -20,11 +20,16 @@ class SingleEntryPlugin {
});
compiler.plugin("make", (compilation, callback) => {
- const dep = new SingleEntryDependency(this.entry);
- dep.loc = this.name;
+ const dep = SingleEntryPlugin.createDependency(this.entry, this.name);
compilation.addEntry(this.context, dep, this.name, callback);
});
}
+
+ static createDependency(entry, name) {
+ const dep = new SingleEntryDependency(entry);
+ dep.loc = name;
+ return dep;
+ }
}
module.exports = SingleEntryPlugin
@@ -68,6 +68,10 @@
}
],
"description": "All modules are loaded upon startup. The last one is exported."
+ },
+ {
+ "description": "function returning an entry object or a promise.",
+ "instanceof": "Function"
}
]
},
@@ -20,7 +20,7 @@ describe("Validation", function() {
config: {},
message: [
" - configuration misses the property 'entry'.",
- " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
+ " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" The entry point(s) of the compilation."
]
}, {
@@ -30,13 +30,15 @@ describe("Validation", function() {
},
message: [
" - configuration.entry should be one of these:",
- " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
+ " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an object.",
" * configuration.entry should not be empty.",
" * configuration.entry should be an array:",
- " [non-empty string]"
+ " [non-empty string]",
+ " * configuration.entry should be an instance of function",
+ " function returning an entry object or a promise.."
]
}, {
name: "empty entry bundle array",
@@ -47,7 +49,7 @@ describe("Validation", function() {
},
message: [
" - configuration.entry should be one of these:",
- " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
+ " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" The entry point(s) of the compilation.",
" Details:",
" * configuration.entry['bundle'] should be a string.",
@@ -56,7 +58,9 @@ describe("Validation", function() {
" non-empty string | [non-empty string]",
" * configuration.entry should be a string.",
" * configuration.entry should be an array:",
- " [non-empty string]"
+ " [non-empty string]",
+ " * configuration.entry should be an instance of function",
+ " function returning an entry object or a promise.."
]
}, {
name: "invalid instanceof",
@@ -79,12 +83,14 @@ describe("Validation", function() {
},
message: [
" - configuration.entry should be one of these:",
- " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
+ " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an object.",
" * configuration.entry should be a string.",
" * configuration.entry[0] should be a string.",
+ " * configuration.entry should be an instance of function",
+ " function returning an entry object or a promise..",
" - configuration.output.filename should be a string."
]
}, {
@@ -99,12 +105,14 @@ describe("Validation", function() {
}],
message: [
" - configuration[0].entry should be one of these:",
- " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
+ " object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" The entry point(s) of the compilation.",
" Details:",
" * configuration[0].entry should be an object.",
" * configuration[0].entry should be a string.",
" * configuration[0].entry[0] should be a string.",
+ " * configuration[0].entry should be an instance of function",
+ " function returning an entry object or a promise..",
" - configuration[1].output.filename should be a string."
]
}, {
@@ -0,0 +1,3 @@
+it("should compile", (done) => {
+ done()
+});
@@ -0,0 +1,3 @@
+it("should compile", (done) => {
+ done()
+});
@@ -0,0 +1,8 @@
+module.exports = {
+ findBundle: function() {
+ return [
+ "./a.js",
+ "./b.js"
+ ]
+ }
+};
@@ -0,0 +1,11 @@
+module.exports = {
+ entry() {
+ return Promise.resolve({
+ a: "./a",
+ b: ["./b"]
+ })
+ },
+ output: {
+ filename: "[name].js"
+ }
+};
@@ -0,0 +1,3 @@
+it("should compile", (done) => {
+ done()
+});
@@ -0,0 +1,3 @@
+it("should compile", (done) => {
+ done()
+});
@@ -0,0 +1,8 @@
+module.exports = {
+ findBundle: function() {
+ return [
+ "./a.js",
+ "./b.js"
+ ]
+ }
+};
@@ -0,0 +1,11 @@
+module.exports = {
+ entry() {
+ return {
+ a: "./a",
+ b: ["./b"]
+ }
+ },
+ output: {
+ filename: "[name].js"
+ }
+};

0 comments on commit a22b00e

Please sign in to comment.