UNPKG

3.28 kBJavaScriptView Raw
1/*
2 Copyright © 2018 Andrew Powell
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 The above copyright notice and this permission notice shall be
9 included in all copies or substantial portions of this Source Code Form.
10*/
11const { existsSync } = require('fs');
12const { resolve } = require('path');
13
14const rechoir = require('rechoir');
15
16const fileTypes = {
17 '.babel.js': ['@babel/register', 'babel-register', 'babel-core/register', 'babel/register'],
18 '.babel.ts': ['@babel/register'],
19 '.es6': ['@babel/register'],
20 '.mjs': ['@babel/register'],
21 '.ts': [
22 'ts-node/register',
23 'typescript-node/register',
24 'typescript-register',
25 'typescript-require'
26 ]
27};
28const configTypes = {
29 function: (c, argv) => Promise.resolve(c(argv.env || {}, argv)),
30 object: (c) => Promise.resolve(c)
31};
32const cwd = process.cwd();
33const defaultConfigPath = resolve(cwd, 'webpack.config.js');
34
35const requireLoader = (extension) => {
36 try {
37 rechoir.prepare(fileTypes, `config${extension}`, cwd);
38 } catch (e) {
39 let message;
40 if (/no module loader/i.test(e.message)) {
41 const [, fileType] = e.message.match(/(".+").$/);
42 message = `A loader could not be found for the ${fileType} file type`;
43 } else {
44 const modules = e.failures.map(({ moduleName }) => `\n ${moduleName}`);
45 message = `${e.message.slice(0, -1)}:${modules}`;
46 }
47
48 const error = new RangeError(message);
49 error.code = 'ERR_MODULE_LOADER';
50 throw error;
51 }
52};
53
54const loadConfig = async (argv) => {
55 if (!argv.config && existsSync(defaultConfigPath)) {
56 // eslint-disable-next-line no-param-reassign
57 argv.config = defaultConfigPath;
58 }
59
60 // let's not process any config if the user hasn't specified any
61 if (argv.config) {
62 const configName = typeof argv.config !== 'string' ? Object.keys(argv.config)[0] : null;
63 // e.g. --config.batman webpack.config.js
64 const configPath = argv.config[configName] || argv.config;
65 const resolvedPath = resolve(configPath);
66
67 // only register a loader if the config file extension matches one we support
68 const extension = Object.keys(fileTypes).find((t) => resolvedPath.endsWith(t));
69
70 if (extension) {
71 requireLoader(extension);
72 }
73
74 let configExport = require(resolvedPath); // eslint-disable-line global-require, import/no-dynamic-require
75
76 if (configExport.default) {
77 configExport = configExport.default;
78 }
79
80 if (configName) {
81 if (!Array.isArray(configExport)) {
82 throw new TypeError(
83 `A config with name was specified, but the config ${configPath} does not export an Array.`
84 );
85 }
86
87 configExport = configExport.find((c) => c.name === configName);
88
89 if (!configExport) {
90 throw new RangeError(`A config with name '${configName}' was not found in ${configPath}`);
91 }
92 }
93
94 const configType = typeof configExport;
95 const config = await configTypes[configType](configExport, argv);
96 const watchConfig = [].concat(config).find((c) => !!c.watch);
97
98 return { config, watchConfig };
99 }
100
101 return { config: {} };
102};
103
104module.exports = { loadConfig };