UNPKG

8.86 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = getUserConfig;
7exports.watchConfigs = watchConfigs;
8exports.unwatchConfigs = unwatchConfigs;
9
10var _fs = require("fs");
11
12var _path = require("path");
13
14var _assert = _interopRequireDefault(require("assert"));
15
16var _stripJsonComments = _interopRequireDefault(require("strip-json-comments"));
17
18var _didyoumean = _interopRequireDefault(require("didyoumean"));
19
20var _chalk = _interopRequireDefault(require("chalk"));
21
22var _lodash = _interopRequireDefault(require("lodash.isequal"));
23
24var _isPlainObject = _interopRequireDefault(require("is-plain-object"));
25
26var _reactDevUtils = require("../reactDevUtils");
27
28var _watch = require("./watch");
29
30var _getPlugins = _interopRequireDefault(require("./getPlugins"));
31
32function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
34function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
35
36function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
37
38const debug = require('debug')('af-webpack:getUserConfig');
39
40const plugins = (0, _getPlugins.default)();
41const pluginNames = plugins.map(p => p.name);
42const pluginsMapByName = plugins.reduce((memo, p) => {
43 memo[p.name] = p;
44 return memo;
45}, {});
46let devServer = null;
47const USER_CONFIGS = 'USER_CONFIGS';
48
49function throwError(msg) {
50 printError(msg);
51 throw new Error(msg);
52}
53
54function printError(messages) {
55 if (devServer) {
56 devServer.sockWrite(devServer.sockets, 'errors', typeof messages === 'string' ? [messages] : messages);
57 }
58}
59
60function reload() {
61 devServer.sockWrite(devServer.sockets, 'content-changed');
62}
63
64function restart(why) {
65 (0, _reactDevUtils.clearConsole)();
66 console.log(_chalk.default.green(`Since ${why}, try to restart the server`));
67 (0, _watch.unwatch)();
68 devServer.close();
69 process.send({
70 type: 'RESTART'
71 });
72}
73
74function merge(oldObj, newObj) {
75 for (const key in newObj) {
76 if (Array.isArray(newObj[key]) && Array.isArray(oldObj[key])) {
77 oldObj[key] = oldObj[key].concat(newObj[key]);
78 } else if ((0, _isPlainObject.default)(newObj[key]) && (0, _isPlainObject.default)(oldObj[key])) {
79 oldObj[key] = Object.assign(oldObj[key], newObj[key]);
80 } else {
81 oldObj[key] = newObj[key];
82 }
83 }
84}
85
86function replaceNpmVariables(value, pkg) {
87 if (typeof value === 'string') {
88 return value.replace('$npm_package_name', pkg.name).replace('$npm_package_version', pkg.version);
89 } else {
90 return value;
91 }
92}
93
94function getUserConfig(opts = {}) {
95 const _opts$cwd = opts.cwd,
96 cwd = _opts$cwd === void 0 ? process.cwd() : _opts$cwd,
97 _opts$configFile = opts.configFile,
98 configFile = _opts$configFile === void 0 ? '.webpackrc' : _opts$configFile,
99 _opts$disabledConfigs = opts.disabledConfigs,
100 disabledConfigs = _opts$disabledConfigs === void 0 ? [] : _opts$disabledConfigs,
101 preprocessor = opts.preprocessor; // TODO: 支持数组的形式?
102 // Read config from configFile and `${configFile}.js`
103
104 const rcFile = (0, _path.resolve)(cwd, configFile);
105 const jsRCFile = (0, _path.resolve)(cwd, `${configFile}.js`);
106 (0, _assert.default)(!((0, _fs.existsSync)(rcFile) && (0, _fs.existsSync)(jsRCFile)), `${configFile} file and ${configFile}.js file can not exist at the same time.`);
107 let config = {};
108
109 if ((0, _fs.existsSync)(rcFile)) {
110 config = JSON.parse((0, _stripJsonComments.default)((0, _fs.readFileSync)(rcFile, 'utf-8')));
111 }
112
113 if ((0, _fs.existsSync)(jsRCFile)) {
114 // no cache
115 delete require.cache[jsRCFile];
116 config = require(jsRCFile); // eslint-disable-line
117
118 if (config.default) {
119 config = config.default;
120 }
121 }
122
123 if (typeof preprocessor === 'function') {
124 config = preprocessor(config);
125 } // Context for validate function
126
127
128 const context = {
129 cwd
130 }; // Validate
131
132 let errorMsg = null;
133 Object.keys(config).forEach(key => {
134 // 禁用项
135 if (disabledConfigs.includes(key)) {
136 errorMsg = `Configuration item ${key} is disabled, please remove it.`;
137 } // 非法的项
138
139
140 if (!pluginNames.includes(key)) {
141 const guess = (0, _didyoumean.default)(key, pluginNames);
142 const affix = guess ? `do you meen ${guess} ?` : 'please remove it.';
143 errorMsg = `Configuration item ${key} is not valid, ${affix}`;
144 } else {
145 // run config plugin's validate
146 const plugin = pluginsMapByName[key];
147
148 if (plugin.validate) {
149 try {
150 plugin.validate.call(context, config[key]);
151 } catch (e) {
152 errorMsg = e.message;
153 }
154 }
155 }
156 }); // 确保不管校验是否出错,下次 watch 判断时能拿到正确的值
157
158 if (errorMsg) {
159 if (
160 /* from watch */
161 opts.setConfig) {
162 opts.setConfig(config);
163 }
164
165 throwError(errorMsg);
166 } // Merge config with current env
167
168
169 if (config.env) {
170 if (config.env[process.env.NODE_ENV]) {
171 merge(config, config.env[process.env.NODE_ENV]);
172 }
173
174 delete config.env;
175 } // Replace npm variables
176
177
178 const pkgFile = (0, _path.resolve)(cwd, 'package.json');
179
180 if (Object.keys(config).length && (0, _fs.existsSync)(pkgFile)) {
181 const pkg = JSON.parse((0, _fs.readFileSync)(pkgFile, 'utf-8'));
182 config = Object.keys(config).reduce((memo, key) => {
183 memo[key] = replaceNpmVariables(config[key], pkg);
184 return memo;
185 }, {});
186 }
187
188 let configFailed = false;
189
190 function watchConfigsAndRun(_devServer, watchOpts = {}) {
191 devServer = _devServer;
192 const watcher = watchConfigs(opts);
193
194 if (watcher) {
195 watcher.on('all', () => {
196 try {
197 if (watchOpts.beforeChange) {
198 watchOpts.beforeChange();
199 }
200
201 const _getUserConfig = getUserConfig(_objectSpread({}, opts, {
202 setConfig(newConfig) {
203 config = newConfig;
204 }
205
206 })),
207 newConfig = _getUserConfig.config; // 从失败中恢复过来,需要 reload 一次
208
209
210 if (configFailed) {
211 configFailed = false;
212 reload();
213 } // 比较,然后执行 onChange
214
215
216 var _iteratorNormalCompletion = true;
217 var _didIteratorError = false;
218 var _iteratorError = undefined;
219
220 try {
221 for (var _iterator = plugins[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
222 const plugin = _step.value;
223 const name = plugin.name,
224 onChange = plugin.onChange;
225
226 if (!(0, _lodash.default)(newConfig[name], config[name])) {
227 debug(`Config ${name} changed, from ${JSON.stringify(config[name])} to ${JSON.stringify(newConfig[name])}`);
228 (onChange || restart.bind(null, `${name} changed`)).call(null, {
229 name,
230 val: config[name],
231 newVal: newConfig[name],
232 config,
233 newConfig
234 });
235 }
236 }
237 } catch (err) {
238 _didIteratorError = true;
239 _iteratorError = err;
240 } finally {
241 try {
242 if (!_iteratorNormalCompletion && _iterator.return != null) {
243 _iterator.return();
244 }
245 } finally {
246 if (_didIteratorError) {
247 throw _iteratorError;
248 }
249 }
250 }
251 } catch (e) {
252 configFailed = true;
253 console.error(_chalk.default.red(`Watch handler failed, since ${e.message}`));
254 console.error(e);
255 }
256 });
257 }
258 }
259
260 debug(`UserConfig: ${JSON.stringify(config)}`);
261 return {
262 config,
263 watch: watchConfigsAndRun
264 };
265}
266
267function watchConfigs(opts = {}) {
268 const _opts$cwd2 = opts.cwd,
269 cwd = _opts$cwd2 === void 0 ? process.cwd() : _opts$cwd2,
270 _opts$configFile2 = opts.configFile,
271 configFile = _opts$configFile2 === void 0 ? '.webpackrc' : _opts$configFile2;
272 const rcFile = (0, _path.resolve)(cwd, configFile);
273 const jsRCFile = (0, _path.resolve)(cwd, `${configFile}.js`);
274 return (0, _watch.watch)(USER_CONFIGS, [rcFile, jsRCFile]);
275}
276
277function unwatchConfigs() {
278 (0, _watch.unwatch)(USER_CONFIGS);
279}
\No newline at end of file