1 | import { cosmiconfigSync } from 'cosmiconfig';
|
2 | import { all as merge } from 'deepmerge';
|
3 | import { validate } from 'jsonschema';
|
4 | import * as colors from 'kleur/colors';
|
5 | import path from 'path';
|
6 | import yargs from 'yargs-parser';
|
7 | import { esbuildPlugin } from './commands/esbuildPlugin';
|
8 | import { DEV_DEPENDENCIES_DIR } from './util';
|
9 | const CONFIG_NAME = 'snowpack';
|
10 | const ALWAYS_EXCLUDE = ['**/node_modules/**/*', '**/.types/**/*'];
|
11 | const SCRIPT_TYPES_WEIGHTED = {
|
12 | proxy: 1,
|
13 | mount: 2,
|
14 | run: 3,
|
15 | build: 4,
|
16 | bundle: 100,
|
17 | };
|
18 |
|
19 | const DEFAULT_CONFIG = {
|
20 | exclude: ['__tests__/**/*', '**/*.@(spec|test).*'],
|
21 | plugins: [],
|
22 | installOptions: {
|
23 | dest: 'web_modules',
|
24 | externalPackage: [],
|
25 | installTypes: false,
|
26 | env: {},
|
27 | alias: {},
|
28 | namedExports: [],
|
29 | rollup: {
|
30 | plugins: [],
|
31 | dedupe: [],
|
32 | },
|
33 | },
|
34 | devOptions: {
|
35 | secure: false,
|
36 | port: 8080,
|
37 | open: 'default',
|
38 | out: 'build',
|
39 | fallback: 'index.html',
|
40 | hmr: true,
|
41 | bundle: undefined,
|
42 | },
|
43 | buildOptions: {
|
44 | baseUrl: '/',
|
45 | metaDir: '__snowpack__',
|
46 | },
|
47 | };
|
48 | const configSchema = {
|
49 | type: 'object',
|
50 | properties: {
|
51 | extends: { type: 'string' },
|
52 | install: { type: 'array', items: { type: 'string' } },
|
53 | exclude: { type: 'array', items: { type: 'string' } },
|
54 | plugins: { type: 'array' },
|
55 | webDependencies: {
|
56 | type: ['object'],
|
57 | additionalProperties: { type: 'string' },
|
58 | },
|
59 | scripts: {
|
60 | type: ['object'],
|
61 | additionalProperties: { type: 'string' },
|
62 | },
|
63 | devOptions: {
|
64 | type: 'object',
|
65 | properties: {
|
66 | secure: { type: 'boolean' },
|
67 | port: { type: 'number' },
|
68 | out: { type: 'string' },
|
69 | fallback: { type: 'string' },
|
70 | bundle: { type: 'boolean' },
|
71 | open: { type: 'string' },
|
72 | hmr: { type: 'boolean' },
|
73 | },
|
74 | },
|
75 | installOptions: {
|
76 | type: 'object',
|
77 | properties: {
|
78 | dest: { type: 'string' },
|
79 | externalPackage: { type: 'array', items: { type: 'string' } },
|
80 | treeshake: { type: 'boolean' },
|
81 | installTypes: { type: 'boolean' },
|
82 | sourceMap: { oneOf: [{ type: 'boolean' }, { type: 'string' }] },
|
83 | alias: {
|
84 | type: 'object',
|
85 | additionalProperties: { type: 'string' },
|
86 | },
|
87 | env: {
|
88 | type: 'object',
|
89 | additionalProperties: {
|
90 | oneOf: [
|
91 | { id: 'EnvVarString', type: 'string' },
|
92 | { id: 'EnvVarNumber', type: 'number' },
|
93 | { id: 'EnvVarTrue', type: 'boolean', enum: [true] },
|
94 | ],
|
95 | },
|
96 | },
|
97 | rollup: {
|
98 | type: 'object',
|
99 | properties: {
|
100 | plugins: { type: 'array', items: { type: 'object' } },
|
101 | dedupe: {
|
102 | type: 'array',
|
103 | items: { type: 'string' },
|
104 | },
|
105 | },
|
106 | },
|
107 | },
|
108 | },
|
109 | buildOptions: {
|
110 | type: ['object'],
|
111 | properties: {
|
112 | baseUrl: { type: 'string' },
|
113 | metaDir: { type: 'string' },
|
114 | },
|
115 | },
|
116 | proxy: {
|
117 | type: 'object',
|
118 | },
|
119 | },
|
120 | };
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | function expandCliFlags(flags) {
|
128 | const result = {
|
129 | installOptions: {},
|
130 | devOptions: {},
|
131 | buildOptions: {},
|
132 | };
|
133 | const { help, version, reload, config, ...relevantFlags } = flags;
|
134 | for (const [flag, val] of Object.entries(relevantFlags)) {
|
135 | if (flag === '_' || flag.includes('-')) {
|
136 | continue;
|
137 | }
|
138 | if (configSchema.properties[flag]) {
|
139 | result[flag] = val;
|
140 | continue;
|
141 | }
|
142 | if (configSchema.properties.installOptions.properties[flag]) {
|
143 | result.installOptions[flag] = val;
|
144 | continue;
|
145 | }
|
146 | if (configSchema.properties.devOptions.properties[flag]) {
|
147 | result.devOptions[flag] = val;
|
148 | continue;
|
149 | }
|
150 | console.error(`Unknown CLI flag: "${flag}"`);
|
151 | process.exit(1);
|
152 | }
|
153 | if (result.installOptions.env) {
|
154 | result.installOptions.env = result.installOptions.env.reduce((acc, id) => {
|
155 | const index = id.indexOf('=');
|
156 | const [key, val] = index > 0 ? [id.substr(0, index), id.substr(index + 1)] : [id, true];
|
157 | acc[key] = val;
|
158 | return acc;
|
159 | }, {});
|
160 | }
|
161 | return result;
|
162 | }
|
163 |
|
164 |
|
165 |
|
166 |
|
167 | function handleLegacyProxyScripts(config) {
|
168 | for (const scriptId in config.scripts) {
|
169 | if (!scriptId.startsWith('proxy:')) {
|
170 | continue;
|
171 | }
|
172 | const cmdArr = config.scripts[scriptId].split(/\s+/);
|
173 | if (cmdArr[0] !== 'proxy') {
|
174 | handleConfigError(`scripts[${scriptId}] must use the proxy command`);
|
175 | }
|
176 | cmdArr.shift();
|
177 | const { to, _ } = yargs(cmdArr);
|
178 | if (_.length !== 1) {
|
179 | handleConfigError(`scripts[${scriptId}] must use the format: "proxy http://SOME.URL --to /PATH"`);
|
180 | }
|
181 | if (to && to[0] !== '/') {
|
182 | handleConfigError(`scripts[${scriptId}]: "--to ${to}" must be a URL path, and start with a "/"`);
|
183 | }
|
184 | const { toUrl, fromUrl } = { fromUrl: _[0], toUrl: to };
|
185 | if (config.proxy[toUrl]) {
|
186 | handleConfigError(`scripts[${scriptId}]: Cannot overwrite proxy[${toUrl}].`);
|
187 | }
|
188 | config.proxy[toUrl] = fromUrl;
|
189 | delete config.scripts[scriptId];
|
190 | }
|
191 | return config;
|
192 | }
|
193 | function normalizeScripts(scripts) {
|
194 | function prefixDot(file) {
|
195 | return `.${file}`.replace(/^\.+/, '.');
|
196 | }
|
197 | const processedScripts = [];
|
198 | if (Object.keys(scripts).filter((k) => k.startsWith('bundle:')).length > 1) {
|
199 | handleConfigError(`scripts can only contain 1 script of type "bundle:".`);
|
200 | }
|
201 | for (const scriptId of Object.keys(scripts)) {
|
202 | if (scriptId.includes('::watch')) {
|
203 | continue;
|
204 | }
|
205 | const [scriptType, scriptMatch] = scriptId.split(':');
|
206 | if (!SCRIPT_TYPES_WEIGHTED[scriptType]) {
|
207 | handleConfigError(`scripts[${scriptId}]: "${scriptType}" is not a known script type.`);
|
208 | }
|
209 | const cmd = scripts[scriptId];
|
210 | const newScriptConfig = {
|
211 | id: scriptId,
|
212 | type: scriptType,
|
213 | match: scriptMatch.split(',').map(prefixDot),
|
214 | cmd,
|
215 | watch: scripts[`${scriptId}::watch`],
|
216 | };
|
217 | if (newScriptConfig.watch) {
|
218 | newScriptConfig.watch = newScriptConfig.watch.replace('$1', newScriptConfig.cmd);
|
219 | }
|
220 | if (scriptType === 'mount') {
|
221 | const cmdArr = cmd.split(/\s+/);
|
222 | if (cmdArr[0] !== 'mount') {
|
223 | handleConfigError(`scripts[${scriptId}] must use the mount command`);
|
224 | }
|
225 | cmdArr.shift();
|
226 | const { to, _ } = yargs(cmdArr);
|
227 | if (_.length !== 1) {
|
228 | handleConfigError(`scripts[${scriptId}] must use the format: "mount dir [--to /PATH]"`);
|
229 | }
|
230 | if (to && to[0] !== '/') {
|
231 | handleConfigError(`scripts[${scriptId}]: "--to ${to}" must be a URL path, and start with a "/"`);
|
232 | }
|
233 | let dirDisk = cmdArr[0];
|
234 | const dirUrl = to || `/${cmdArr[0]}`;
|
235 |
|
236 |
|
237 | if (scriptId === 'mount:web_modules') {
|
238 | dirDisk = DEV_DEPENDENCIES_DIR;
|
239 | }
|
240 | newScriptConfig.args = {
|
241 | fromDisk: path.posix.normalize(dirDisk + '/'),
|
242 | toUrl: path.posix.normalize(dirUrl + '/'),
|
243 | };
|
244 | }
|
245 | processedScripts.push(newScriptConfig);
|
246 | }
|
247 | const allBuildMatch = new Set();
|
248 | for (const { type, match } of processedScripts) {
|
249 | if (type !== 'build') {
|
250 | continue;
|
251 | }
|
252 | for (const ext of match) {
|
253 | if (allBuildMatch.has(ext)) {
|
254 | handleConfigError(`Multiple "scripts" match the "${ext}" file extension.\nCurrently, only one script per file type is supported.`);
|
255 | }
|
256 | allBuildMatch.add(prefixDot(ext));
|
257 | }
|
258 | }
|
259 | if (!scripts['mount:web_modules']) {
|
260 | processedScripts.push({
|
261 | id: 'mount:web_modules',
|
262 | type: 'mount',
|
263 | match: ['web_modules'],
|
264 | cmd: `mount $WEB_MODULES --to /web_modules`,
|
265 | args: {
|
266 | fromDisk: DEV_DEPENDENCIES_DIR,
|
267 | toUrl: '/web_modules',
|
268 | },
|
269 | });
|
270 | }
|
271 | const defaultBuildMatch = ['.js', '.jsx', '.ts', '.tsx'].filter((ext) => !allBuildMatch.has(ext));
|
272 | if (defaultBuildMatch.length > 0) {
|
273 | const defaultBuildWorkerConfig = {
|
274 | id: `build:${defaultBuildMatch.join(',')}`,
|
275 | type: 'build',
|
276 | match: defaultBuildMatch,
|
277 | cmd: '(default) esbuild',
|
278 | plugin: esbuildPlugin(),
|
279 | };
|
280 | processedScripts.push(defaultBuildWorkerConfig);
|
281 | }
|
282 | processedScripts.sort((a, b) => {
|
283 | if (a.type === b.type) {
|
284 | if (a.id === 'mount:web_modules') {
|
285 | return -1;
|
286 | }
|
287 | if (b.id === 'mount:web_modules') {
|
288 | return 1;
|
289 | }
|
290 | return a.id.localeCompare(b.id);
|
291 | }
|
292 | return SCRIPT_TYPES_WEIGHTED[a.type] - SCRIPT_TYPES_WEIGHTED[b.type];
|
293 | });
|
294 | return processedScripts;
|
295 | }
|
296 | function normalizeProxies(proxies) {
|
297 | return Object.entries(proxies).map(([pathPrefix, options]) => {
|
298 | if (typeof options !== 'string') {
|
299 | return [
|
300 | pathPrefix,
|
301 | {
|
302 |
|
303 | on: {},
|
304 | ...options,
|
305 | },
|
306 | ];
|
307 | }
|
308 | return [
|
309 | pathPrefix,
|
310 | {
|
311 | on: {
|
312 | proxyReq: (proxyReq, req) => {
|
313 | const proxyPath = proxyReq.path.split(req.url)[0];
|
314 | proxyReq.path = proxyPath + req.url.replace(pathPrefix, '');
|
315 | },
|
316 | },
|
317 | target: options,
|
318 | changeOrigin: true,
|
319 | secure: false,
|
320 | },
|
321 | ];
|
322 | });
|
323 | }
|
324 |
|
325 | function normalizeConfig(config) {
|
326 | const cwd = process.cwd();
|
327 | config.knownEntrypoints = config.install || [];
|
328 | config.installOptions.dest = path.resolve(cwd, config.installOptions.dest);
|
329 | config.devOptions.out = path.resolve(cwd, config.devOptions.out);
|
330 | config.exclude = Array.from(new Set([...ALWAYS_EXCLUDE, ...config.exclude]));
|
331 | if (!config.scripts) {
|
332 | config.exclude.push('**/.*');
|
333 | config.scripts = {
|
334 | 'mount:*': 'mount . --to /',
|
335 | };
|
336 | }
|
337 | if (!config.proxy) {
|
338 | config.proxy = {};
|
339 | }
|
340 | const allPlugins = {};
|
341 |
|
342 | config.buildOptions.metaDir = config.buildOptions.metaDir
|
343 | .replace(/^(\/|\\)/g, '')
|
344 | .replace(/(\/|\\)$/g, '');
|
345 | config.plugins = config.plugins.map((plugin) => {
|
346 | const configPluginPath = Array.isArray(plugin) ? plugin[0] : plugin;
|
347 | const configPluginOptions = (Array.isArray(plugin) && plugin[1]) || {};
|
348 | const configPluginLoc = require.resolve(configPluginPath, { paths: [cwd] });
|
349 | const configPlugin = require(configPluginLoc)(config, configPluginOptions);
|
350 | if ((configPlugin.build ? 1 : 0) +
|
351 | (configPlugin.transform ? 1 : 0) +
|
352 | (configPlugin.bundle ? 1 : 0) >
|
353 | 1) {
|
354 | handleConfigError(`plugin[${configPluginLoc}]: A valid plugin can only have one build(), transform(), or bundle() function.`);
|
355 | }
|
356 | allPlugins[configPluginPath] = configPlugin;
|
357 | if (configPlugin.knownEntrypoints) {
|
358 | config.knownEntrypoints.push(...configPlugin.knownEntrypoints);
|
359 | }
|
360 | if (configPlugin.defaultBuildScript &&
|
361 | !config.scripts[configPlugin.defaultBuildScript] &&
|
362 | !Object.values(config.scripts).includes(configPluginPath)) {
|
363 | config.scripts[configPlugin.defaultBuildScript] = configPluginPath;
|
364 | }
|
365 | return configPlugin;
|
366 | });
|
367 | if (config.devOptions.bundle === true && !config.scripts['bundle:*']) {
|
368 | handleConfigError(`--bundle set to true, but no "bundle:*" script/plugin was provided.`);
|
369 | }
|
370 | config = handleLegacyProxyScripts(config);
|
371 | config.proxy = normalizeProxies(config.proxy);
|
372 | config.scripts = normalizeScripts(config.scripts);
|
373 | config.scripts.forEach((script) => {
|
374 | if (script.plugin)
|
375 | return;
|
376 |
|
377 | if (['build', 'bundle'].includes(script.type)) {
|
378 | if (allPlugins[script.cmd]?.[script.type]) {
|
379 | script.plugin = allPlugins[script.cmd];
|
380 | }
|
381 | else if (allPlugins[script.cmd] && !allPlugins[script.cmd][script.type]) {
|
382 | handleConfigError(`scripts[${script.id}]: Plugin "${script.cmd}" has no ${script.type} script.`);
|
383 | }
|
384 | else if (script.cmd.startsWith('@') || script.cmd.startsWith('.')) {
|
385 | handleConfigError(`scripts[${script.id}]: Register plugin "${script.cmd}" in your Snowpack "plugins" config.`);
|
386 | }
|
387 | }
|
388 | });
|
389 | return config;
|
390 | }
|
391 | function handleConfigError(msg) {
|
392 | console.error(`[error]: ${msg}`);
|
393 | process.exit(1);
|
394 | }
|
395 | function handleValidationErrors(filepath, errors) {
|
396 | console.error(colors.red(`! ${filepath || 'Configuration error'}`));
|
397 | console.error(errors.map((err) => ` - ${err.toString()}`).join('\n'));
|
398 | console.error(` See https://www.snowpack.dev/#configuration for more info.`);
|
399 | process.exit(1);
|
400 | }
|
401 | function handleDeprecatedConfigError(mainMsg, ...msgs) {
|
402 | console.error(colors.red(mainMsg));
|
403 | msgs.forEach(console.error);
|
404 | console.error(`See https://www.snowpack.dev/#configuration for more info.`);
|
405 | process.exit(1);
|
406 | }
|
407 | function validateConfigAgainstV1(rawConfig, cliFlags) {
|
408 |
|
409 | if (rawConfig.dedupe || cliFlags.dedupe) {
|
410 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `dedupe` is now `installOptions.rollup.dedupe`.');
|
411 | }
|
412 | if (rawConfig.namedExports) {
|
413 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `rollup.namedExports` is no longer required. See also: installOptions.namedExports');
|
414 | }
|
415 | if (rawConfig.installOptions?.rollup?.namedExports) {
|
416 | delete rawConfig.installOptions.rollup.namedExports;
|
417 | console.error(colors.yellow('[Snowpack v2.3.0] `rollup.namedExports` is no longer required. See also: installOptions.namedExports'));
|
418 | }
|
419 | if (rawConfig.rollup) {
|
420 | handleDeprecatedConfigError('[Snowpack v1 -> v2] top-level `rollup` config is now `installOptions.rollup`.');
|
421 | }
|
422 | if (rawConfig.installOptions?.include || cliFlags.include) {
|
423 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.include` is now handled via "mount" build scripts!');
|
424 | }
|
425 | if (rawConfig.installOptions?.exclude) {
|
426 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.exclude` is now `exclude`.');
|
427 | }
|
428 | if (Array.isArray(rawConfig.webDependencies)) {
|
429 | handleDeprecatedConfigError('[Snowpack v1 -> v2] The `webDependencies` array is now `install`.');
|
430 | }
|
431 | if (rawConfig.knownEntrypoints) {
|
432 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `knownEntrypoints` is now `install`.');
|
433 | }
|
434 | if (rawConfig.entrypoints) {
|
435 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `entrypoints` is now `install`.');
|
436 | }
|
437 | if (rawConfig.include) {
|
438 | handleDeprecatedConfigError('[Snowpack v1 -> v2] All files are now included by default. "include" config is safe to remove.', 'Whitelist & include specific folders via "mount" build scripts.');
|
439 | }
|
440 |
|
441 | if (rawConfig.source || cliFlags.source) {
|
442 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `source` is now detected automatically, this config is safe to remove.');
|
443 | }
|
444 | if (rawConfig.stat || cliFlags.stat) {
|
445 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `stat` is now the default output, this config is safe to remove.');
|
446 | }
|
447 | if (rawConfig.scripts &&
|
448 | Object.keys(rawConfig.scripts).filter((k) => k.startsWith('lintall')).length > 0) {
|
449 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `scripts["lintall:..."]` has been renamed to scripts["run:..."]');
|
450 | }
|
451 | if (rawConfig.scripts &&
|
452 | Object.keys(rawConfig.scripts).filter((k) => k.startsWith('plugin:`')).length > 0) {
|
453 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `scripts["plugin:..."]` have been renamed to scripts["build:..."].');
|
454 | }
|
455 |
|
456 | if (rawConfig.devOptions?.dist) {
|
457 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `devOptions.dist` is no longer required. This config is safe to remove.', `If you'd still like to host your src/ directory at the "/_dist/*" URL, create a mount script:',
|
458 | ' {"scripts": {"mount:src": "mount src --to /_dist_"}} `);
|
459 | }
|
460 | if (rawConfig.hash || cliFlags.hash) {
|
461 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.hash` has been replaced by `snowpack build`.');
|
462 | }
|
463 | if (rawConfig.installOptions?.nomodule || cliFlags.nomodule) {
|
464 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.nomodule` has been replaced by `snowpack build`.');
|
465 | }
|
466 | if (rawConfig.installOptions?.nomoduleOutput || cliFlags.nomoduleOutput) {
|
467 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.nomoduleOutput` has been replaced by `snowpack build`.');
|
468 | }
|
469 | if (rawConfig.installOptions?.babel || cliFlags.babel) {
|
470 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.babel` has been replaced by `snowpack build`.');
|
471 | }
|
472 | if (rawConfig.installOptions?.optimize || cliFlags.optimize) {
|
473 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.optimize` has been replaced by `snowpack build`.');
|
474 | }
|
475 | if (rawConfig.installOptions?.strict || cliFlags.strict) {
|
476 | handleDeprecatedConfigError('[Snowpack v1 -> v2] `installOptions.strict` is no longer supported.');
|
477 | }
|
478 | }
|
479 | export function createConfiguration(config) {
|
480 | const { errors: validationErrors } = validate(config, configSchema, {
|
481 | propertyName: CONFIG_NAME,
|
482 | allowUnknownAttributes: false,
|
483 | });
|
484 | if (validationErrors.length > 0) {
|
485 | return [validationErrors, undefined];
|
486 | }
|
487 | const mergedConfig = merge([DEFAULT_CONFIG, config]);
|
488 | return [null, normalizeConfig(mergedConfig)];
|
489 | }
|
490 | export function loadAndValidateConfig(flags, pkgManifest) {
|
491 | const explorerSync = cosmiconfigSync(CONFIG_NAME, {
|
492 |
|
493 | searchPlaces: ['package.json', 'snowpack.config.js', 'snowpack.config.json'],
|
494 |
|
495 | stopDir: path.dirname(process.cwd()),
|
496 | });
|
497 | let result;
|
498 |
|
499 | if (flags.config) {
|
500 | result = explorerSync.load(path.resolve(process.cwd(), flags.config));
|
501 | if (!result) {
|
502 | handleConfigError(`Could not locate Snowpack config at ${flags.config}`);
|
503 | }
|
504 | }
|
505 |
|
506 | result = result || explorerSync.search();
|
507 |
|
508 | if (!result || !result.config || result.isEmpty) {
|
509 | result = { config: { ...DEFAULT_CONFIG } };
|
510 | }
|
511 |
|
512 | const config = result.config;
|
513 | validateConfigAgainstV1(config, flags);
|
514 | const cliConfig = expandCliFlags(flags);
|
515 | let extendConfig = {};
|
516 | if (config.extends) {
|
517 | const extendConfigLoc = config.extends.startsWith('.')
|
518 | ? path.resolve(path.dirname(result.filepath), config.extends)
|
519 | : require.resolve(config.extends, { paths: [process.cwd()] });
|
520 | const extendResult = explorerSync.load(extendConfigLoc);
|
521 | if (!extendResult) {
|
522 | handleConfigError(`Could not locate Snowpack config at ${flags.config}`);
|
523 | process.exit(1);
|
524 | }
|
525 | extendConfig = extendResult.config;
|
526 | const extendValidation = validate(extendConfig, configSchema, {
|
527 | allowUnknownAttributes: false,
|
528 | propertyName: CONFIG_NAME,
|
529 | });
|
530 | if (extendValidation.errors && extendValidation.errors.length > 0) {
|
531 | handleValidationErrors(result.filepath, extendValidation.errors);
|
532 | process.exit(1);
|
533 | }
|
534 | }
|
535 |
|
536 | const mergedConfig = merge([
|
537 | pkgManifest.homepage ? { buildOptions: { baseUrl: pkgManifest.homepage } } : {},
|
538 | extendConfig,
|
539 | { webDependencies: pkgManifest.webDependencies },
|
540 | config,
|
541 | cliConfig,
|
542 | ]);
|
543 | for (const webDependencyName of Object.keys(mergedConfig.webDependencies || {})) {
|
544 | if (pkgManifest.dependencies && pkgManifest.dependencies[webDependencyName]) {
|
545 | handleConfigError(`"${webDependencyName}" is included in "webDependencies". Please remove it from your package.json "dependencies" config.`);
|
546 | }
|
547 | if (pkgManifest.devDependencies && pkgManifest.devDependencies[webDependencyName]) {
|
548 | handleConfigError(`"${webDependencyName}" is included in "webDependencies". Please remove it from your package.json "devDependencies" config.`);
|
549 | }
|
550 | }
|
551 | const [validationErrors, configResult] = createConfiguration(mergedConfig);
|
552 | if (validationErrors) {
|
553 | handleValidationErrors(result.filepath, validationErrors);
|
554 | process.exit(1);
|
555 | }
|
556 | return configResult;
|
557 | }
|