1 | let { isAbsolute, dirname, join, relative } = require('path')
|
2 | let { lilconfig } = require('lilconfig')
|
3 | let globby = require('globby')
|
4 | let bytes = require('bytes-iec')
|
5 |
|
6 | let SizeLimitError = require('./size-limit-error')
|
7 |
|
8 | let 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 |
|
27 | function isStrings(value) {
|
28 | if (!Array.isArray(value)) return false
|
29 | return value.every(i => typeof i === 'string')
|
30 | }
|
31 |
|
32 | function isStringsOrUndefined(value) {
|
33 | let type = typeof value
|
34 | return type === 'undefined' || type === 'string' || isStrings(value)
|
35 | }
|
36 |
|
37 | function 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 |
|
71 | function toAbsolute(file, cwd) {
|
72 | return isAbsolute(file) ? file : join(cwd, file)
|
73 | }
|
74 |
|
75 | function toName(files, cwd) {
|
76 | return files.map(i => (i.startsWith(cwd) ? relative(cwd, i) : i)).join(', ')
|
77 | }
|
78 |
|
79 | module.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 | }
|