UNPKG

5.19 kBJavaScriptView Raw
1const ChainedMap = require('./ChainedMap');
2const ChainedSet = require('./ChainedSet');
3const Resolve = require('./Resolve');
4const ResolveLoader = require('./ResolveLoader');
5const Output = require('./Output');
6const DevServer = require('./DevServer');
7const Plugin = require('./Plugin');
8const Module = require('./Module');
9const Optimization = require('./Optimization');
10const Performance = require('./Performance');
11
12module.exports = class extends ChainedMap {
13 constructor() {
14 super();
15 this.devServer = new DevServer(this);
16 this.entryPoints = new ChainedMap(this);
17 this.module = new Module(this);
18 this.node = new ChainedMap(this);
19 this.optimization = new Optimization(this);
20 this.output = new Output(this);
21 this.performance = new Performance(this);
22 this.plugins = new ChainedMap(this);
23 this.resolve = new Resolve(this);
24 this.resolveLoader = new ResolveLoader(this);
25 this.extend([
26 'amd',
27 'bail',
28 'cache',
29 'context',
30 'devtool',
31 'externals',
32 'loader',
33 'mode',
34 'name',
35 'parallelism',
36 'profile',
37 'recordsInputPath',
38 'recordsPath',
39 'recordsOutputPath',
40 'stats',
41 'target',
42 'watch',
43 'watchOptions',
44 ]);
45 }
46
47 static toString(config, { verbose = false, configPrefix = 'config' } = {}) {
48 // eslint-disable-next-line global-require
49 const { stringify } = require('javascript-stringify');
50
51 return stringify(
52 config,
53 (value, indent, stringify) => {
54 // improve plugin output
55 if (value && value.__pluginName) {
56 const prefix = `/* ${configPrefix}.${value.__pluginType}('${
57 value.__pluginName
58 }') */\n`;
59 const constructorExpression = value.__pluginPath
60 ? // The path is stringified to ensure special characters are escaped
61 // (such as the backslashes in Windows-style paths).
62 `(require(${stringify(value.__pluginPath)}))`
63 : value.__pluginConstructorName;
64
65 if (constructorExpression) {
66 // get correct indentation for args by stringifying the args array and
67 // discarding the square brackets.
68 const args = stringify(value.__pluginArgs).slice(1, -1);
69 return `${prefix}new ${constructorExpression}(${args})`;
70 }
71 return (
72 prefix +
73 stringify(
74 value.__pluginArgs && value.__pluginArgs.length
75 ? { args: value.__pluginArgs }
76 : {}
77 )
78 );
79 }
80
81 // improve rule/use output
82 if (value && value.__ruleNames) {
83 const prefix = `/* ${configPrefix}.module.rule('${
84 value.__ruleNames[0]
85 }')${value.__ruleNames
86 .slice(1)
87 .map(r => `.oneOf('${r}')`)
88 .join('')}${
89 value.__useName ? `.use('${value.__useName}')` : ``
90 } */\n`;
91 return prefix + stringify(value);
92 }
93
94 // shorten long functions
95 if (typeof value === 'function') {
96 if (value.__expression) {
97 return value.__expression;
98 }
99 if (!verbose && value.toString().length > 100) {
100 return `function () { /* omitted long function */ }`;
101 }
102 }
103
104 return stringify(value);
105 },
106 2
107 );
108 }
109
110 entry(name) {
111 return this.entryPoints.getOrCompute(name, () => new ChainedSet(this));
112 }
113
114 plugin(name) {
115 return this.plugins.getOrCompute(name, () => new Plugin(this, name));
116 }
117
118 toConfig() {
119 const entryPoints = this.entryPoints.entries() || {};
120
121 return this.clean(
122 Object.assign(this.entries() || {}, {
123 node: this.node.entries(),
124 output: this.output.entries(),
125 resolve: this.resolve.toConfig(),
126 resolveLoader: this.resolveLoader.toConfig(),
127 devServer: this.devServer.toConfig(),
128 module: this.module.toConfig(),
129 optimization: this.optimization.toConfig(),
130 plugins: this.plugins.values().map(plugin => plugin.toConfig()),
131 performance: this.performance.entries(),
132 entry: Object.keys(entryPoints).reduce(
133 (acc, key) =>
134 Object.assign(acc, { [key]: entryPoints[key].values() }),
135 {}
136 ),
137 })
138 );
139 }
140
141 toString(options) {
142 return module.exports.toString(this.toConfig(), options);
143 }
144
145 merge(obj = {}, omit = []) {
146 const omissions = [
147 'node',
148 'output',
149 'resolve',
150 'resolveLoader',
151 'devServer',
152 'optimization',
153 'performance',
154 'module',
155 ];
156
157 if (!omit.includes('entry') && 'entry' in obj) {
158 Object.keys(obj.entry).forEach(name =>
159 this.entry(name).merge([].concat(obj.entry[name]))
160 );
161 }
162
163 if (!omit.includes('plugin') && 'plugin' in obj) {
164 Object.keys(obj.plugin).forEach(name =>
165 this.plugin(name).merge(obj.plugin[name])
166 );
167 }
168
169 omissions.forEach(key => {
170 if (!omit.includes(key) && key in obj) {
171 this[key].merge(obj[key]);
172 }
173 });
174
175 return super.merge(obj, [...omit, ...omissions, 'entry', 'plugin']);
176 }
177};