1 | const fs = require('fs-extra')
|
2 | const path = require('path')
|
3 |
|
4 | const validatePathname = require('./validate-pathname')
|
5 | const validateConfigDist = require('./validate-config-dist')
|
6 |
|
7 | const getCwd = require('../utils/get-cwd')
|
8 | const readBuildConfigFile = require('../utils/read-build-config-file')
|
9 |
|
10 | const {
|
11 | keyFileProjectConfigTempFull,
|
12 | keyFileProjectConfigTempPortion,
|
13 | filenameProjectConfigTempFull,
|
14 | filenameProjectConfigTempPortion,
|
15 | propertiesToExtract: _propertiesToExtract,
|
16 | dirConfigTemp: _dirConfigTemp,
|
17 | typesSPA,
|
18 | } = require('../defaults/before-build')
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | module.exports = async (projectDir = getCwd()) => {
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | let fileFullConfig = typeof process.env.KOOT_BUILD_CONFIG_PATHNAME === 'string'
|
39 | ? process.env.KOOT_BUILD_CONFIG_PATHNAME
|
40 | : path.resolve(projectDir, 'koot.config.js')
|
41 |
|
42 |
|
43 | if (!fs.existsSync(fileFullConfig)) {
|
44 | const buildConfig = await readBuildConfigFile()
|
45 | return validateBuildConfig(buildConfig)
|
46 | }
|
47 |
|
48 |
|
49 | const fullConfig = { ...require(fileFullConfig) }
|
50 |
|
51 |
|
52 | const isCustomProjectConfig = typeof process.env.KOOT_PROJECT_CONFIG_FULL_PATHNAME === 'string'
|
53 |
|
54 |
|
55 | const propertiesToExtract = [..._propertiesToExtract]
|
56 |
|
57 |
|
58 | const isFullConfig = propertiesToExtract.some(([key]) => typeof fullConfig[key] !== 'undefined')
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | if (isFullConfig) {
|
67 |
|
68 | const dirConfigTemp = path.resolve(projectDir, _dirConfigTemp)
|
69 | await fs.ensureDir(dirConfigTemp)
|
70 |
|
71 |
|
72 | const isSPA = typesSPA.includes(fullConfig.type)
|
73 |
|
74 | if (isSPA) {
|
75 |
|
76 | propertiesToExtract.push(['inject', undefined])
|
77 |
|
78 |
|
79 | if (!fullConfig.inject &&
|
80 | typeof fullConfig.server === 'object' &&
|
81 | typeof fullConfig.server.inject !== 'undefined'
|
82 | ) {
|
83 | fullConfig.inject = fullConfig.server.inject
|
84 | }
|
85 | } else {
|
86 |
|
87 | if (!!fullConfig.inject &&
|
88 | typeof fullConfig.server === 'object' &&
|
89 | !fullConfig.server.inject
|
90 | ) {
|
91 | fullConfig.inject.server = fullConfig.inject
|
92 | delete fullConfig.inject
|
93 | }
|
94 | }
|
95 |
|
96 |
|
97 | const projectConfig = {}
|
98 |
|
99 |
|
100 | const buildConfig = propertiesToExtract.reduce((configRemains, curr) => {
|
101 |
|
102 | const [key, defaultValue] = curr
|
103 | projectConfig[key] = configRemains[key] || defaultValue
|
104 | delete configRemains[key]
|
105 | return configRemains
|
106 | }, fullConfig)
|
107 |
|
108 |
|
109 | if (isCustomProjectConfig) {
|
110 | return {
|
111 | ...validateBuildConfig(buildConfig),
|
112 | [keyFileProjectConfigTempFull]: process.env.KOOT_PROJECT_CONFIG_FULL_PATHNAME,
|
113 | [keyFileProjectConfigTempPortion]: process.env.KOOT_PROJECT_CONFIG_PORTION_PATHNAME
|
114 | }
|
115 | }
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | const validateProjectConfig = (keys) => {
|
130 | keys.forEach(key => {
|
131 | if (eval(`typeof projectConfig.${key} === 'string'`)) {
|
132 | const value = eval(`projectConfig.${key}`)
|
133 | const pathname = path.isAbsolute(value)
|
134 | ? value
|
135 | : validatePathname(value, projectDir).replace(/\\/g, '\\\\')
|
136 | const result = path.isAbsolute(pathname)
|
137 | ? pathname
|
138 | : ('../../../' + pathname.replace(/^\.\//, ''))
|
139 | eval(`projectConfig.${key} = \`require('${result}').default\``)
|
140 | }
|
141 | })
|
142 | }
|
143 | validateProjectConfig([
|
144 | 'router',
|
145 | 'redux.combineReducers',
|
146 | 'redux.store',
|
147 | 'client.before',
|
148 | 'client.after',
|
149 | 'client.onRouterUpdate',
|
150 | 'client.onHistoryUpdate',
|
151 | 'server.reducers',
|
152 | 'server.inject',
|
153 | 'server.before',
|
154 | 'server.after',
|
155 | 'server.onRender',
|
156 | 'server.onRender.beforeDataToStore',
|
157 | 'server.onRender.afterDataToStore',
|
158 | 'inject',
|
159 | ])
|
160 |
|
161 |
|
162 |
|
163 | let tempPortion = []
|
164 | const propertiesPortion = [
|
165 | 'redux',
|
166 | 'server'
|
167 | ]
|
168 | const tempFull = propertiesToExtract.map(([key]) => {
|
169 | let result = ''
|
170 | if (key === 'server') {
|
171 | if (isSPA) return ''
|
172 | result = `export const ${key} = __SERVER__ ? ${JSON.stringify(projectConfig[key])} : {};`
|
173 | } else {
|
174 | result = `export const ${key} = ${JSON.stringify(projectConfig[key])};`
|
175 | }
|
176 | if (propertiesPortion.includes(key)) {
|
177 | tempPortion.push(result)
|
178 | }
|
179 | return result
|
180 | })
|
181 | .join('\n')
|
182 | .replace(/"require\((.+?)\).default"/g, `require($1).default`)
|
183 |
|
184 | tempPortion = tempPortion.join('\n').replace(/"require\((.+?)\).default"/g, `require($1).default`)
|
185 |
|
186 |
|
187 |
|
188 |
|
189 | const pathFull = path.resolve(dirConfigTemp, filenameProjectConfigTempFull.replace(/\*/g, Date.now()))
|
190 | process.env.KOOT_PROJECT_CONFIG_FULL_PATHNAME = pathFull
|
191 | await fs.writeFile(pathFull, tempFull, 'utf-8')
|
192 |
|
193 | const pathPortion = path.resolve(dirConfigTemp, filenameProjectConfigTempPortion.replace(/\*/g, Date.now()))
|
194 | process.env.KOOT_PROJECT_CONFIG_PORTION_PATHNAME = pathPortion
|
195 | await fs.writeFile(pathPortion, tempPortion, 'utf-8')
|
196 |
|
197 | return {
|
198 | ...validateBuildConfig(buildConfig),
|
199 | [keyFileProjectConfigTempFull]: pathFull,
|
200 | [keyFileProjectConfigTempPortion]: pathPortion
|
201 | }
|
202 |
|
203 | } else {
|
204 |
|
205 | const buildConfig = await readBuildConfigFile()
|
206 | return validateBuildConfig(buildConfig)
|
207 | }
|
208 | }
|
209 |
|
210 |
|
211 | const validateBuildConfig = (config = {}) => {
|
212 |
|
213 |
|
214 | if (typeof config.dest !== 'undefined') {
|
215 | config.dist = config.dest
|
216 | delete config.dest
|
217 | }
|
218 | if (typeof config.dist !== 'undefined') {
|
219 | validateConfigDist(config.dist)
|
220 | }
|
221 |
|
222 |
|
223 | if (typeof config.webpack === 'object') {
|
224 | |
225 |
|
226 |
|
227 |
|
228 |
|
229 | const applyWebpackConfig = (nameInObject, nameAfter) => {
|
230 | if (typeof config.webpack[nameInObject] !== 'undefined') {
|
231 | config[nameAfter] = config.webpack[nameInObject]
|
232 | delete config.webpack[nameInObject]
|
233 | }
|
234 | }
|
235 | applyWebpackConfig('config', 'config')
|
236 | applyWebpackConfig('beforeBuild', 'beforeBuild')
|
237 | applyWebpackConfig('afterBuild', 'afterBuild')
|
238 | applyWebpackConfig('defines', 'defines')
|
239 | applyWebpackConfig('dll', 'webpackDll')
|
240 | applyWebpackConfig('hmr', 'webpackHmr')
|
241 | applyWebpackConfig('compilerHook', 'webpackCompilerHook')
|
242 | Object.keys(config.webpack).forEach(key => {
|
243 | applyWebpackConfig(key, 'webpack' + key.substr(0, 1).toUpperCase() + key.substr(1))
|
244 | })
|
245 | delete config.webpack
|
246 | }
|
247 |
|
248 | return config
|
249 | }
|