|
1 | 1 | const { existsSync } = require('fs'); |
2 | | -const { resolve, extname, sep } = require('path'); |
| 2 | +const { resolve, sep, dirname } = require('path'); |
| 3 | +const { extensions } = require('interpret'); |
3 | 4 |
|
4 | 5 | const GroupHelper = require('../utils/group-helper'); |
5 | 6 |
|
6 | | -const VALID_EXTENSIONS = ['.mjs', '.js', '.json', '.babel.js', '.ts']; |
7 | 7 | const DEFAULT_CONFIG_LOC = ['.webpack/webpack.config', '.webpack/webpack.config.dev', '.webpack/webpack.config.prod', '.webpack/webpackfile', 'webpack.config']; |
8 | 8 |
|
9 | 9 | const getDefaultConfigFiles = () => { |
10 | | - return DEFAULT_CONFIG_LOC.map(filename => |
11 | | - VALID_EXTENSIONS.map(ext => ({ |
12 | | - path: resolve(filename + ext), |
| 10 | + return DEFAULT_CONFIG_LOC.map(filename => { |
| 11 | + return Object.keys(extensions).map(ext => { |
| 12 | + return { |
| 13 | + path: resolve(filename + ext), |
| 14 | + ext: ext, |
| 15 | + module: extensions[ext] |
| 16 | + } |
| 17 | + }) |
| 18 | + }).reduce((a, i) => a.concat(i), []); |
| 19 | +} |
| 20 | + |
| 21 | +const getConfigInfoFromFileName = (filename) => { |
| 22 | + const originalExt = filename.split('.').pop(); |
| 23 | + return Object.keys(extensions).filter(ext => { |
| 24 | + return '.'.concat(originalExt) === ext; |
| 25 | + }). |
| 26 | + map(ext => { |
| 27 | + return { |
| 28 | + path: resolve(filename), |
13 | 29 | ext: ext, |
14 | | - })), |
15 | | - ).reduce((a, i) => a.concat(i), []); |
| 30 | + module: extensions[ext] |
| 31 | + } |
| 32 | + }).filter(e => existsSync(e.path)); |
16 | 33 | } |
17 | 34 |
|
18 | 35 | class ConfigGroup extends GroupHelper { |
19 | 36 | constructor(options) { |
20 | 37 | super(options); |
21 | 38 | } |
22 | 39 |
|
23 | | - getConfigExtension(configPath) { |
24 | | - for (let i = VALID_EXTENSIONS.length - 1; i >= 0; i--) { |
25 | | - const tmpExt = VALID_EXTENSIONS[i]; |
26 | | - if (configPath.includes(tmpExt, configPath.length - tmpExt.length)) { |
27 | | - return tmpExt; |
28 | | - } |
29 | | - } |
30 | | - return extname(configPath); |
31 | | - } |
32 | | - mapConfigArg(config) { |
33 | | - const { path } = config; |
34 | | - const ext = this.getConfigExtension(path); |
35 | | - return { |
36 | | - path, |
37 | | - ext, |
38 | | - }; |
39 | | - } |
40 | | - |
41 | 40 | require(path) { |
42 | 41 | const result = require(path); |
43 | 42 | if (result && result.__esModule && result.default) { |
44 | 43 | return result.default; |
45 | 44 | } |
46 | | - return result; |
| 45 | + return { |
| 46 | + path: path, |
| 47 | + content: result |
| 48 | + }; |
47 | 49 | } |
48 | 50 |
|
49 | | - requireConfig(configPath) { |
50 | | - const { register } = this.args; |
| 51 | + requireConfig(configModule) { |
51 | 52 | return (() => { |
52 | | - if (register && register.length) { |
53 | | - module.paths.unshift(resolve(process.cwd(), 'node_modules')); |
54 | | - register.forEach(dep => { |
55 | | - const isRelative = ['./', '../', '.\\', '..\\'].some(start => dep.startsWith(start)); |
56 | | - if (isRelative) { |
57 | | - require(resolve(process.cwd(), dep)); |
58 | | - } else { |
59 | | - require(dep); |
60 | | - } |
61 | | - }); |
| 53 | + try { |
| 54 | + if(!configModule.module) { |
| 55 | + return this.require(configModule.path); |
| 56 | + } |
| 57 | + } catch(err) { |
| 58 | + console.log(err); |
62 | 59 | } |
63 | | - return this.require(configPath); |
64 | 60 | })(); |
65 | 61 | } |
66 | 62 |
|
67 | | - async resolveConfigFiles() { |
68 | | - const { config, mode } = this.args; |
69 | | - const path = require('path'); |
70 | | - |
71 | | - let configFiles; |
72 | | - if (config) { |
73 | | - //TODO: check for existence, give user feedback otherwise |
74 | | - const configPath = path.resolve(process.cwd(), config); |
75 | | - const ext = this.getConfigExtension(configPath); |
76 | | - configFiles = { |
77 | | - path: configPath, |
78 | | - ext, |
79 | | - }; |
80 | | - } |
81 | | - if (!configFiles) { |
82 | | - const defaultConfigFiles = getDefaultConfigFiles(); |
83 | | - const tmpConfigFiles = defaultConfigFiles |
84 | | - .filter(file => { |
85 | | - return existsSync(file.path); |
86 | | - }) |
87 | | - .map(this.mapConfigArg.bind(this)); |
88 | | - if (tmpConfigFiles.length) { |
89 | | - if (!config) { |
90 | | - const defaultConfig = tmpConfigFiles.find(p => p.path.includes(mode)); |
91 | | - configFiles = defaultConfig || tmpConfigFiles[0]; |
92 | | - } |
93 | | - } |
94 | | - } |
| 63 | + async finalize(moduleObj) { |
| 64 | + let newOptionsObject = { |
| 65 | + outputOptions: {}, |
| 66 | + options: {} |
| 67 | + }; |
95 | 68 |
|
96 | | - let configOptions = []; |
97 | | - if (configFiles) { |
98 | | - // TODO: support mjs etc.. |
99 | | - const resolvedConfigurationFiles = this.requireConfig(configFiles.path); |
100 | | - configOptions = resolvedConfigurationFiles; |
101 | | - if (configOptions && configFiles.path.includes('.webpack')) { |
102 | | - const currentPath = configFiles.path; |
103 | | - const parentContext = path.dirname(currentPath).split(sep).slice(0, -1).join('/'); |
104 | | - if(Array.isArray(configOptions)) { |
105 | | - configOptions.forEach(config => { |
106 | | - config.context = config.context || parentContext; |
107 | | - }) |
108 | | - } else { |
109 | | - configOptions.context = configOptions.context || parentContext; |
110 | | - } |
111 | | - } |
| 69 | + if(!moduleObj) { |
| 70 | + return newOptionsObject; |
112 | 71 | } |
| 72 | + const configPath = moduleObj.path; |
| 73 | + const configOptions = moduleObj.content; |
113 | 74 | if (configOptions.length > 0) { |
114 | | - this.opts['options'] = configOptions; |
| 75 | + newOptionsObject['options'] = configOptions; |
115 | 76 | } |
116 | 77 | else if (typeof configOptions === 'function') { |
117 | 78 | const newOptions = await configOptions(); |
118 | | - this.opts['options'] = newOptions; |
| 79 | + newOptionsObject['options'] = newOptions; |
119 | 80 | } |
120 | 81 | else { |
121 | 82 | if (Array.isArray(configOptions) && !configOptions.length) { |
122 | | - this.opts['options'] = {}; |
| 83 | + newOptionsObject['options'] = {}; |
| 84 | + return newOptionsObject; |
| 85 | + } |
| 86 | + newOptionsObject['options'] = configOptions; |
| 87 | + } |
| 88 | + |
| 89 | + if (configOptions && configPath.includes('.webpack')) { |
| 90 | + const currentPath = configPath; |
| 91 | + const parentContext = dirname(currentPath).split(sep).slice(0, -1).join('/'); |
| 92 | + if(Array.isArray(configOptions)) { |
| 93 | + configOptions.forEach(config => { |
| 94 | + config.context = config.context || parentContext; |
| 95 | + }) |
| 96 | + } else { |
| 97 | + configOptions.context = configOptions.context || parentContext; |
| 98 | + } |
| 99 | + newOptionsObject['options'] = configOptions; |
| 100 | + } |
| 101 | + return newOptionsObject; |
| 102 | + } |
| 103 | + |
| 104 | + async resolveConfigFiles() { |
| 105 | + const { config, mode } = this.args; |
| 106 | + |
| 107 | + if (config) { |
| 108 | + const configPath = resolve(process.cwd(), config); |
| 109 | + const configFiles = getConfigInfoFromFileName(configPath); |
| 110 | + if(!configFiles.length) { |
| 111 | + this.opts.processingMessageBuffer.push({ |
| 112 | + lvl: 'warn', |
| 113 | + msg: `Configuration ${config} not found in ${configPath}` |
| 114 | + }); |
| 115 | + return; |
| 116 | + } |
| 117 | + const foundConfig = configFiles[0]; |
| 118 | + const resolvedConfig = this.requireConfig(foundConfig); |
| 119 | + this.opts = this.finalize(resolvedConfig); |
| 120 | + return; |
| 121 | + } |
| 122 | + |
| 123 | + const defaultConfigFiles = getDefaultConfigFiles(); |
| 124 | + const tmpConfigFiles = defaultConfigFiles |
| 125 | + .filter(file => { |
| 126 | + return existsSync(file.path); |
| 127 | + }); |
| 128 | + |
| 129 | + const configFiles = tmpConfigFiles.map(this.requireConfig.bind(this)); |
| 130 | + if (configFiles.length) { |
| 131 | + const defaultConfig = configFiles.find(p => p.path.includes(mode)); |
| 132 | + if(defaultConfig) { |
| 133 | + const envConfig = defaultConfig.map(c => c.content); |
| 134 | + this.opts = this.finalize(envConfig); |
123 | 135 | return; |
124 | 136 | } |
125 | | - this.opts['options'] = configOptions; |
| 137 | + const foundConfig = configFiles.pop(); |
| 138 | + this.opts = this.finalize(foundConfig); |
| 139 | + return; |
126 | 140 | } |
127 | 141 | } |
128 | 142 |
|
129 | | - resolveConfigMerging() { |
| 143 | + async resolveConfigMerging() { |
130 | 144 | if (this.args.hasOwnProperty('merge')) { |
131 | 145 | const { merge } = this.args; |
132 | 146 |
|
133 | 147 | const newConfigPath = this.resolveFilePath(merge, 'webpack.base.js'); |
134 | | - const newConfig = newConfigPath ? this.require(newConfigPath) : null; |
135 | | - |
136 | | - const webpackMerge = require('webpack-merge'); |
137 | | - this.opts['options'] = webpackMerge(this.opts['options'], newConfig); |
| 148 | + if(newConfigPath) { |
| 149 | + const configFiles = getConfigInfoFromFileName(newConfigPath); |
| 150 | + if(!configFiles.length) { |
| 151 | + this.opts.processingMessageBuffer.push({ |
| 152 | + lvl: 'warn', |
| 153 | + msg: 'Could not find file to merge configuration with...' |
| 154 | + }) |
| 155 | + return; |
| 156 | + } |
| 157 | + const foundConfig = configFiles[0]; |
| 158 | + const resolvedConfig = this.requireConfig(foundConfig); |
| 159 | + const newConfigurationsObject = await this.finalize(resolvedConfig); |
| 160 | + const webpackMerge = require('webpack-merge'); |
| 161 | + this.opts['options'] = webpackMerge(this.opts['options'], newConfigurationsObject.options); |
| 162 | + } |
138 | 163 | } |
139 | 164 | } |
140 | 165 |
|
141 | 166 | async run() { |
142 | 167 | await this.resolveConfigFiles(); |
143 | | - this.resolveConfigMerging(); |
| 168 | + await this.resolveConfigMerging(); |
144 | 169 | return this.opts; |
145 | 170 | } |
146 | 171 | } |
|
0 commit comments