UNPKG

8.83 kBJavaScriptView Raw
1import path from 'path'
2import fs from 'fs'
3
4import require_hacker from 'require-hacker'
5
6import { is_object, exists, starts_with } from './helpers'
7
8// returns a stub for webpack-assets.json if it doesn't exist yet
9// (because node.js and webpack are being run in parallel in development mode)
10export function default_webpack_assets()
11{
12 const webpack_assets =
13 {
14 javascript: {},
15 styles: {},
16 assets: {}
17 }
18
19 return webpack_assets
20}
21
22// adds missing fields, etc
23export function normalize_options(options)
24{
25 // parameters check
26 for (let key of Object.keys(options))
27 {
28 switch (key)
29 {
30 case 'assets':
31 if (!is_object(options[key]))
32 {
33 throw new Error(`"${key}" configuration parameter must be ` + `an object`)
34 }
35 break
36
37 case 'debug':
38 if (typeof options[key] !== 'boolean')
39 {
40 throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
41 }
42 break
43
44 case 'verbose':
45 if (typeof options[key] !== 'boolean')
46 {
47 throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
48 }
49 // Legacy `verbose` option is converted to `verbosity`
50 console.log('[webpack-isomorphic-tools] WARNING: `verbose` option is now called `verbosity`')
51 if (options.verbose)
52 {
53 options.verbosity = verbosity_levels.webpack_stats_for_each_build
54 }
55 delete options.verbose
56 break
57
58 case 'verbosity':
59 if (typeof options[key] !== 'string')
60 {
61 throw new Error(`"${key}" configuration parameter must be ` + `a string`)
62 }
63 if (Object.keys(verbosity_levels).map(key => verbosity_levels[key]).indexOf(options[key]) < 0)
64 {
65 throw new Error(`Unknown "verbosity" passed: ${options[key]}`)
66 }
67 break
68
69 case 'port':
70 if (typeof options[key] !== 'number')
71 {
72 throw new Error(`"${key}" configuration parameter must be ` + `a number`)
73 }
74 break
75
76 case 'webpack_assets_file_path':
77 case 'webpack_stats_file_path':
78 if (typeof options[key] !== 'string')
79 {
80 throw new Error(`"${key}" configuration parameter must be ` + `a string`)
81 }
82 break
83
84 case 'alias':
85 if (!is_object(options[key]))
86 {
87 throw new Error(`"${key}" configuration parameter must be ` + `an object`)
88 }
89 break
90
91 case 'modules_directories':
92 if (!Array.isArray(options[key]))
93 {
94 throw new Error(`"${key}" configuration parameter must be ` + `an array`)
95 }
96 break
97
98 case 'require_context':
99 if (typeof options[key] !== 'boolean')
100 {
101 throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
102 }
103 // Legacy `require_context` option is converted to `patch_require`
104 console.log('[webpack-isomorphic-tools] WARNING: `require_context` option is now called `patch_require`')
105 delete options.require_context
106 options.patch_require = true
107 break
108
109 case 'patch_require':
110 if (typeof options[key] !== 'boolean')
111 {
112 throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
113 }
114 break
115
116 default:
117 throw new Error(`Unknown configuration parameter "${key}"`)
118 }
119 }
120
121 // if no assets specified (for whatever reason), make it an empty array
122 if (!options.assets)
123 {
124 // options.assets = {}
125 throw new Error('You must specify "assets" parameter in webpack-isomorphic-tools configuration')
126 }
127
128 // webpack-assets.json path, relative to the project base path
129 options.webpack_assets_file_path = options.webpack_assets_file_path || 'webpack-assets.json'
130
131 // webpack-stats.json path, relative to the project base path
132 options.webpack_stats_file_path = options.webpack_stats_file_path || 'webpack-stats.json'
133
134 // if Webpack aliases are supplied, validate them
135 if (options.alias)
136 {
137 for (let key of Object.keys(options.alias))
138 {
139 if (typeof options.alias[key] !== 'string')
140 {
141 throw new Error(`Invalid alias for "${key}": "${options.alias[key]}"`)
142 }
143 }
144 }
145
146 // generate names (if required) for each user defined asset type, normalize extensions
147 for (let asset_type of Object.keys(options.assets))
148 {
149 const description = options.assets[asset_type]
150
151 // normalize extensions
152 if (description.extension)
153 {
154 // sanity check
155 if (Array.isArray(description.extension))
156 {
157 throw new Error(`Use "extensions" key instead of "extension" for specifying an array of file extensions for assets of type "${asset_type}"`)
158 }
159
160 // sanity check
161 if (typeof description.extension !== 'string')
162 {
163 throw new Error(`"extension" value must be a string for assets of type "${asset_type}"`)
164 }
165
166 // normalize
167 description.extensions = [description.extension]
168 delete description.extension
169 }
170
171 // sanity check
172 if (!description.extensions)
173 {
174 throw new Error(`You must specify file extensions for assets of type "${asset_type}"`)
175 }
176
177 // parameters check
178 for (let key of Object.keys(description))
179 {
180 switch (key)
181 {
182 case 'extensions':
183 break
184
185 case 'exclude':
186 case 'include':
187 if (!Array.isArray(description[key]))
188 {
189 throw new Error(`"${key}" must be an array for asset type "${asset_type}"`)
190 }
191 for (let clusion of description[key])
192 {
193 if (typeof clusion !== 'string'
194 && !(clusion instanceof RegExp)
195 && typeof clusion !== 'function')
196 {
197 throw new Error(`Unsupported object type for exclusion/inclusion "${clusion}" for asset type "${asset_type}"`)
198 }
199 }
200 break
201
202 case 'filter':
203 case 'parser':
204 case 'path':
205 if (typeof description[key] !== 'function')
206 {
207 throw new Error(`"${key}" must be a function for asset type "${asset_type}"`)
208 }
209 break
210
211 case 'regular_expression':
212 if (!(description[key] instanceof RegExp))
213 {
214 throw new Error(`"${key}" must be a regular expression for asset type "${asset_type}"`)
215 }
216 break
217
218 default:
219 throw new Error(`Unknown property "${key}" for asset type "${asset_type}"`)
220 }
221 }
222 }
223}
224
225// alias the path if an alias is found,
226// and resolve it to a global filesystem path
227export function alias_hook(path, module, project_path, aliases, log)
228{
229 // possibly alias the path
230 const aliased_path = alias(path, aliases)
231
232 // return if an alias not found
233 if (!aliased_path)
234 {
235 return
236 }
237
238 // if an alias is found, require() the correct path
239 log.debug(`require("${path}") was called and an alias was found, so aliasing to module path "${aliased_path}"`)
240
241 // resolve the path to a real filesystem path (resolves `npm link`, etc)
242 const global_path = require_hacker.resolve(aliased_path, module)
243 log.debug(` resolved the path for the aliased module to ${global_path}`)
244
245 return global_path
246
247 // const result = require(global_path)
248 // // log.debug(` the path was found`)
249
250 // return require_hacker.to_javascript_module_source(result)
251}
252
253// alias the path provided the aliases map
254function alias(path, aliases)
255{
256 // if it's a path to a file - don't interfere
257 if (starts_with(path, '.') || starts_with(path, '/'))
258 {
259 return
260 }
261
262 // extract module name from the path
263 const slash_index = path.indexOf('/')
264 const module_name = slash_index >= 0 ? path.substring(0, slash_index) : path
265 const rest = slash_index >= 0 ? path.substring(slash_index) : ''
266
267 // find an alias
268 const alias = aliases[module_name]
269
270 // if an alias is found, require() the correct path
271 if (alias)
272 {
273 return alias + rest
274 }
275}
276
277// converts global asset path to local-to-the-project asset path
278export function normalize_asset_path(global_asset_path, project_path)
279{
280 // // if this path is outside project folder,
281 // // return it as a global path
282 // if (!starts_with(global_asset_path, project_path + path.sep))
283 // {
284 // return global_asset_path
285 // }
286
287 // this path is inside project folder,
288 // convert it to a relative path
289
290 // asset path relative to the project folder
291 let asset_path = path.relative(project_path, global_asset_path)
292
293 // for Windows:
294 //
295 // convert Node.js path to a correct Webpack path
296 asset_path = uniform_path(asset_path)
297
298 return asset_path
299}
300
301// for Windows:
302//
303// converts Node.js path to a correct Webpack path
304export function uniform_path(asset_path)
305{
306 // correct slashes
307 asset_path = asset_path.replace(/\\/g, '/')
308
309 // add './' in the beginning if it's missing (for example, in case of Windows)
310 if (asset_path.indexOf('.') !== 0)
311 {
312 asset_path = './' + asset_path
313 }
314
315 return asset_path
316}
317
318export const verbosity_levels =
319{
320 no_webpack_stats : 'no webpack stats',
321 webpack_stats_for_each_build : 'webpack stats for each build'
322}
\No newline at end of file