UNPKG

4.61 kBJavaScriptView Raw
1const { superstruct } = require('superstruct')
2const getFileNames = require('./getFileNames')
3
4module.exports = (api, config) => {
5 api.logger.debug('Validating config', config)
6 const struct = superstruct()
7
8 const entry = struct.optional(struct.union(['string', 'array', 'object']))
9
10 const output = struct(
11 {
12 dir: 'string',
13 sourceMap: 'boolean',
14 minimize: 'boolean',
15 format: struct.enum(['iife', 'cjs', 'umd']),
16 moduleName: struct.optional('string'),
17 publicUrl: 'string',
18 target: struct.enum([
19 'web',
20 'node',
21 'electron', // Alias to electron-renderer
22 'electron-renderer',
23 'electron-main',
24 'node-webkit',
25 'webworker',
26 'async-node'
27 ]),
28 clean: 'boolean',
29 fileNames: struct.optional(
30 struct.object({
31 js: struct.optional('string'),
32 css: struct.optional('string'),
33 font: struct.optional('string'),
34 image: struct.optional('string')
35 })
36 ),
37 html: struct.optional(struct.union(['boolean', 'object']))
38 },
39 {
40 dir: 'dist',
41 sourceMap: !api.isProd,
42 minimize: api.isProd,
43 format: 'iife',
44 publicUrl: '/',
45 target: 'web',
46 default: true,
47 clean: true
48 }
49 )
50
51 const babel = struct(
52 {
53 jsx: 'string',
54 transpileModules: struct.optional(struct.list(['string'])),
55 namedImports: struct.optional('object')
56 },
57 {
58 jsx: 'react'
59 }
60 )
61
62 const css = struct(
63 {
64 extract: 'boolean',
65 loaderOptions: struct.optional(
66 struct.object({
67 css: struct.optional('object'),
68 less: struct.optional('object'),
69 postcss: struct.optional('object'),
70 sass: struct.optional('object'),
71 stylus: struct.optional('object')
72 })
73 )
74 },
75 {
76 extract: api.isProd
77 }
78 )
79
80 const devServer = struct(
81 {
82 hot: 'boolean',
83 hotOnly: 'boolean?',
84 host: 'string',
85 port: struct.union(['string', 'number']),
86 hotEntries: struct(['string']),
87 headers: struct.optional('object'),
88 proxy: struct.optional(
89 struct.union([
90 'string',
91 'object',
92 'function',
93 struct([struct.union(['object', 'function'])])
94 ])
95 ),
96 open: 'boolean',
97 historyApiFallback: struct.optional(struct.union(['boolean', 'object'])),
98 before: struct.optional('function'),
99 after: struct.optional('function'),
100 https: struct.optional(struct.union(['boolean', 'object']))
101 },
102 {
103 hot: true,
104 // Cloud IDEs use envs
105 host: process.env.HOST || '0.0.0.0',
106 port: process.env.PORT || 4000,
107 hotEntries: ['index'],
108 open: false
109 }
110 )
111
112 const plugins = struct.optional([
113 struct.union([
114 'string',
115 struct({
116 resolve: struct.union(['string', 'object']),
117 options: struct.optional('object')
118 })
119 ])
120 ])
121
122 const assets = struct(
123 {
124 inlineImageMaxSize: struct.optional('number')
125 },
126 {
127 inlineImageMaxSize: 5000
128 }
129 )
130
131 const Struct = struct(
132 {
133 entry,
134 output,
135 plugins,
136 parallel: 'boolean',
137 cache: 'boolean',
138 babel,
139 css,
140 devServer,
141 envs: struct.optional('object'),
142 constants: struct.optional('object'),
143 chainWebpack: struct.optional('function'),
144 configureWebpack: struct.optional(struct.union(['object', 'function'])),
145 assets,
146 publicFolder: struct.union(['string', 'boolean']),
147 pages: struct.optional('object')
148 },
149 {
150 cache: true,
151 parallel: false,
152 publicFolder: 'public'
153 }
154 )
155
156 const [error, result] = Struct.validate(config)
157
158 if (error) {
159 throw error
160 }
161
162 result.output.fileNames = Object.assign(
163 getFileNames({ useHash: api.isProd, format: result.output.format }),
164 result.output.fileNames
165 )
166
167 if (!result.entry) {
168 if (api.pkg.data.source) {
169 api.logger.debug(
170 'Using the value of `source` field in `package.json` as app entry'
171 )
172 result.entry = api.pkg.data.source
173 } else {
174 api.logger.debug('Using `index` as app entry')
175 result.entry = 'index'
176 }
177 }
178
179 // Always disable cache in test mode
180 if (process.env.NODE_ENV === 'test') {
181 result.cache = false
182 }
183
184 // Ensure publicUrl
185 result.output.publicUrl = result.output.publicUrl
186 // Must end with slash
187 .replace(/\/?$/, '/')
188 // Remove leading ./
189 .replace(/^\.\//, '')
190
191 api.logger.debug('Validated config', result)
192
193 return result
194}