UNPKG

5.34 kBJavaScriptView Raw
1let { isAbsolute, dirname, join, relative } = require('path')
2let { lilconfig } = require('lilconfig')
3let globby = require('globby')
4let bytes = require('bytes-iec')
5
6let SizeLimitError = require('./size-limit-error')
7
8let OPTIONS = {
9 name: true,
10 path: true,
11 limit: true,
12 module: true,
13 entry: 'webpack',
14 config: 'webpack',
15 modifyWebpackConfig: 'webpack',
16 webpack: 'webpack',
17 ignore: 'webpack',
18 import: 'webpack',
19 gzip: ['webpack', 'file'],
20 running: 'time',
21 disableModuleConcatenation: 'webpack',
22 brotli: 'webpack',
23 hidePassed: false,
24 highlightLess: false
25}
26
27function isStrings(value) {
28 if (!Array.isArray(value)) return false
29 return value.every(i => typeof i === 'string')
30}
31
32function isStringsOrUndefined(value) {
33 let type = typeof value
34 return type === 'undefined' || type === 'string' || isStrings(value)
35}
36
37function checkChecks(plugins, checks) {
38 if (!Array.isArray(checks)) {
39 throw new SizeLimitError('noArrayConfig')
40 }
41 if (checks.length === 0) {
42 throw new SizeLimitError('emptyConfig')
43 }
44 for (let check of checks) {
45 if (typeof check !== 'object') {
46 throw new SizeLimitError('noObjectCheck')
47 }
48 if (!isStringsOrUndefined(check.path)) {
49 throw new SizeLimitError('pathNotString')
50 }
51 if (!isStringsOrUndefined(check.entry)) {
52 throw new SizeLimitError('entryNotString')
53 }
54 for (let opt in check) {
55 let available = OPTIONS[opt]
56 if (typeof available === 'string') {
57 if (!plugins.has(available)) {
58 throw new SizeLimitError('pluginlessConfig', opt, available)
59 }
60 } else if (Array.isArray(available)) {
61 if (available.every(i => !plugins.has(i))) {
62 throw new SizeLimitError('multiPluginlessConfig', opt, ...available)
63 }
64 } else if (available !== true) {
65 throw new SizeLimitError('unknownOption', opt)
66 }
67 }
68 }
69}
70
71function toAbsolute(file, cwd) {
72 return isAbsolute(file) ? file : join(cwd, file)
73}
74
75function toName(files, cwd) {
76 return files.map(i => (i.startsWith(cwd) ? relative(cwd, i) : i)).join(', ')
77}
78
79module.exports = async function getConfig(plugins, process, args, pkg) {
80 let config = {
81 cwd: process.cwd()
82 }
83 if (args.why) {
84 config.project = pkg.packageJson.name
85 config.why = args.why
86 }
87 if (args.saveBundle) {
88 config.saveBundle = toAbsolute(args.saveBundle, process.cwd())
89 }
90 if (args.cleanDir) {
91 config.cleanDir = args.cleanDir
92 }
93 if (args.hidePassed) {
94 config.hidePassed = args.hidePassed
95 }
96 if (args.highlightLess) {
97 config.highlightLess = args.highlightLess
98 }
99
100 if (args.files.length > 0) {
101 config.checks = [{ files: args.files }]
102 } else {
103 let explorer = lilconfig('size-limit', {
104 searchPlaces: [
105 'package.json',
106 '.size-limit.json',
107 '.size-limit',
108 '.size-limit.js',
109 '.size-limit.cjs'
110 ]
111 })
112 let result = await explorer.search(process.cwd())
113
114 if (result === null) throw new SizeLimitError('noConfig')
115 checkChecks(plugins, result.config)
116
117 config.configPath = relative(process.cwd(), result.filepath)
118 config.cwd = dirname(result.filepath)
119 config.checks = await Promise.all(
120 result.config.map(async check => {
121 let processed = { ...check }
122 if (check.path) {
123 processed.files = await globby(check.path, { cwd: config.cwd })
124 } else if (!check.entry) {
125 if (pkg.packageJson.main) {
126 processed.files = [
127 require.resolve(join(dirname(pkg.path), pkg.packageJson.main))
128 ]
129 } else {
130 processed.files = [join(dirname(pkg.path), 'index.js')]
131 }
132 }
133 return processed
134 })
135 )
136 }
137
138 let peer = Object.keys(pkg.packageJson.peerDependencies || {})
139 for (let check of config.checks) {
140 if (peer.length > 0) check.ignore = peer.concat(check.ignore || [])
141 if (check.entry && !Array.isArray(check.entry)) check.entry = [check.entry]
142 if (!check.name) check.name = toName(check.entry || check.files, config.cwd)
143 if (args.limit) check.limit = args.limit
144 if (check.limit) {
145 if (/ ?ms/i.test(check.limit)) {
146 check.timeLimit = parseFloat(check.limit) / 1000
147 } else if (/ ?s/i.test(check.limit)) {
148 check.timeLimit = parseFloat(check.limit)
149 } else {
150 check.sizeLimit = bytes.parse(check.limit)
151 }
152 if (check.timeLimit && !plugins.has('time')) {
153 throw new SizeLimitError('timeWithoutPlugin')
154 }
155 }
156 if (config.highlightLess) check.highlightLess = true
157 if (/\sB$|\dB$/.test(check.limit)) check.highlightLess = true
158 if (check.files) {
159 check.files = check.files.map(i => toAbsolute(i, config.cwd))
160 }
161 if (check.config) check.config = toAbsolute(check.config, config.cwd)
162 if (typeof check.import === 'string') {
163 check.import = {
164 [check.files[0]]: check.import
165 }
166 }
167 if (check.import) {
168 let imports = {}
169 for (let i in check.import) {
170 if (peer.includes(i)) {
171 check.ignore = check.ignore.filter(j => j !== i)
172 imports[require.resolve(i, config.cwd)] = check.import[i]
173 } else {
174 imports[toAbsolute(i, config.cwd)] = check.import[i]
175 }
176 }
177 check.import = imports
178 }
179 }
180
181 return config
182}