UNPKG

5.18 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}('${value.__pluginName}') */\n`;
57 const constructorExpression = value.__pluginPath
58 ? // The path is stringified to ensure special characters are escaped
59 // (such as the backslashes in Windows-style paths).
60 `(require(${stringify(value.__pluginPath)}))`
61 : value.__pluginConstructorName;
62
63 if (constructorExpression) {
64 // get correct indentation for args by stringifying the args array and
65 // discarding the square brackets.
66 const args = stringify(value.__pluginArgs).slice(1, -1);
67 return `${prefix}new ${constructorExpression}(${args})`;
68 }
69 return (
70 prefix +
71 stringify(
72 value.__pluginArgs && value.__pluginArgs.length
73 ? { args: value.__pluginArgs }
74 : {},
75 )
76 );
77 }
78
79 // improve rule/use output
80 if (value && value.__ruleNames) {
81 const prefix = `/* ${configPrefix}.module.rule('${
82 value.__ruleNames[0]
83 }')${value.__ruleNames
84 .slice(1)
85 .map(r => `.oneOf('${r}')`)
86 .join('')}${
87 value.__useName ? `.use('${value.__useName}')` : ``
88 } */\n`;
89 return prefix + stringify(value);
90 }
91
92 if (value && value.__expression) {
93 return value.__expression;
94 }
95
96 // shorten long functions
97 if (typeof value === 'function') {
98 if (!verbose && value.toString().length > 100) {
99 return `function () { /* omitted long function */ }`;
100 }
101 }
102
103 return stringify(value);
104 },
105 2,
106 );
107 }
108
109 entry(name) {
110 return this.entryPoints.getOrCompute(name, () => new ChainedSet(this));
111 }
112
113 plugin(name) {
114 return this.plugins.getOrCompute(name, () => new Plugin(this, name));
115 }
116
117 toConfig() {
118 const entryPoints = this.entryPoints.entries() || {};
119
120 return this.clean(
121 Object.assign(this.entries() || {}, {
122 node: this.node.entries(),
123 output: this.output.entries(),
124 resolve: this.resolve.toConfig(),
125 resolveLoader: this.resolveLoader.toConfig(),
126 devServer: this.devServer.toConfig(),
127 module: this.module.toConfig(),
128 optimization: this.optimization.toConfig(),
129 plugins: this.plugins.values().map(plugin => plugin.toConfig()),
130 performance: this.performance.entries(),
131 entry: Object.keys(entryPoints).reduce(
132 (acc, key) =>
133 Object.assign(acc, { [key]: entryPoints[key].values() }),
134 {},
135 ),
136 }),
137 );
138 }
139
140 toString(options) {
141 return module.exports.toString(this.toConfig(), options);
142 }
143
144 merge(obj = {}, omit = []) {
145 const omissions = [
146 'node',
147 'output',
148 'resolve',
149 'resolveLoader',
150 'devServer',
151 'optimization',
152 'performance',
153 'module',
154 ];
155
156 if (!omit.includes('entry') && 'entry' in obj) {
157 Object.keys(obj.entry).forEach(name =>
158 this.entry(name).merge([].concat(obj.entry[name])),
159 );
160 }
161
162 if (!omit.includes('plugin') && 'plugin' in obj) {
163 Object.keys(obj.plugin).forEach(name =>
164 this.plugin(name).merge(obj.plugin[name]),
165 );
166 }
167
168 omissions.forEach(key => {
169 if (!omit.includes(key) && key in obj) {
170 this[key].merge(obj[key]);
171 }
172 });
173
174 return super.merge(obj, [...omit, ...omissions, 'entry', 'plugin']);
175 }
176};