@mpxjs/webpack-plugin 2.8.1 → 2.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +2 -2
- package/lib/json-compiler/index.js +1 -1
- package/lib/loader.js +5 -6
- package/lib/native-loader.js +1 -1
- package/lib/resolver/FixDescriptionInfoPlugin.js +1 -0
- package/lib/runtime/animation.js +60 -0
- package/lib/runtime/optionProcessor.js +9 -101
- package/lib/runtime/transRpxStyle.js +44 -0
- package/lib/script-setup-compiler/index.js +1 -1
- package/lib/utils/get-json-content.js +7 -3
- package/lib/web/processJSON.js +2 -4
- package/lib/web/processScript.js +8 -4
- package/lib/wxss/CssSyntaxError.js +29 -0
- package/lib/wxss/Warning.js +22 -0
- package/lib/wxss/index.js +5 -0
- package/lib/wxss/loader.js +234 -132
- package/lib/wxss/options.json +209 -0
- package/lib/wxss/plugins/index.js +5 -0
- package/lib/wxss/plugins/postcss-icss-parser.js +124 -0
- package/lib/wxss/plugins/postcss-import-parser.js +372 -0
- package/lib/wxss/plugins/postcss-url-parser.js +447 -0
- package/lib/wxss/runtime/api.js +104 -0
- package/lib/wxss/runtime/getUrl.js +28 -0
- package/lib/wxss/runtime/noSourceMaps.js +1 -0
- package/lib/wxss/runtime/sourceMaps.js +25 -0
- package/lib/wxss/utils.js +1312 -0
- package/package.json +2 -2
- package/lib/wxss/url/escape.js +0 -16
|
@@ -0,0 +1,1312 @@
|
|
|
1
|
+
/* eslint-disable operator-linebreak */
|
|
2
|
+
/*
|
|
3
|
+
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
4
|
+
Author Tobias Koppers @sokra
|
|
5
|
+
*/
|
|
6
|
+
const { fileURLToPath } = require('url')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
const isUrlRequest = require('../utils/is-url-request')
|
|
9
|
+
const modulesValues = require('postcss-modules-values')
|
|
10
|
+
const localByDefault = require('postcss-modules-local-by-default')
|
|
11
|
+
const extractImports = require('postcss-modules-extract-imports')
|
|
12
|
+
const modulesScope = require('postcss-modules-scope')
|
|
13
|
+
|
|
14
|
+
const WEBPACK_IGNORE_COMMENT_REGEXP = /webpackIgnore:(\s+)?(true|false)/
|
|
15
|
+
|
|
16
|
+
const matchRelativePath = /^\.\.?[/\\]/
|
|
17
|
+
|
|
18
|
+
function isAbsolutePath (str) {
|
|
19
|
+
return path.posix.isAbsolute(str) || path.win32.isAbsolute(str)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isRelativePath (str) {
|
|
23
|
+
return matchRelativePath.test(str)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TODO simplify for the next major release
|
|
27
|
+
function stringifyRequest (loaderContext, request) {
|
|
28
|
+
if (
|
|
29
|
+
typeof loaderContext.utils !== 'undefined' &&
|
|
30
|
+
typeof loaderContext.utils.contextify === 'function'
|
|
31
|
+
) {
|
|
32
|
+
return JSON.stringify(
|
|
33
|
+
loaderContext.utils.contextify(
|
|
34
|
+
loaderContext.context || loaderContext.rootContext,
|
|
35
|
+
request
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const splitted = request.split('!')
|
|
41
|
+
const { context } = loaderContext
|
|
42
|
+
|
|
43
|
+
return JSON.stringify(
|
|
44
|
+
splitted
|
|
45
|
+
.map((part) => {
|
|
46
|
+
// First, separate singlePath from query, because the query might contain paths again
|
|
47
|
+
const splittedPart = part.match(/^(.*?)(\?.*)/)
|
|
48
|
+
const query = splittedPart ? splittedPart[2] : ''
|
|
49
|
+
let singlePath = splittedPart ? splittedPart[1] : part
|
|
50
|
+
|
|
51
|
+
if (isAbsolutePath(singlePath) && context) {
|
|
52
|
+
singlePath = path.relative(context, singlePath)
|
|
53
|
+
|
|
54
|
+
if (isAbsolutePath(singlePath)) {
|
|
55
|
+
// If singlePath still matches an absolute path, singlePath was on a different drive than context.
|
|
56
|
+
// In this case, we leave the path platform-specific without replacing any separators.
|
|
57
|
+
// @see https://github.com/webpack/loader-utils/pull/14
|
|
58
|
+
return singlePath + query
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isRelativePath(singlePath) === false) {
|
|
62
|
+
// Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
|
|
63
|
+
singlePath = `./${singlePath}`
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return singlePath.replace(/\\/g, '/') + query
|
|
68
|
+
})
|
|
69
|
+
.join('!')
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// We can't use path.win32.isAbsolute because it also matches paths starting with a forward slash
|
|
74
|
+
const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i
|
|
75
|
+
const IS_MODULE_REQUEST = /^[^?]*~/
|
|
76
|
+
|
|
77
|
+
function urlToRequest (url, root) {
|
|
78
|
+
let request
|
|
79
|
+
|
|
80
|
+
if (IS_NATIVE_WIN32_PATH.test(url)) {
|
|
81
|
+
// absolute windows path, keep it
|
|
82
|
+
request = url
|
|
83
|
+
} else if (typeof root !== 'undefined' && /^\//.test(url)) {
|
|
84
|
+
request = root + url
|
|
85
|
+
} else if (/^\.\.?\//.test(url)) {
|
|
86
|
+
// A relative url stays
|
|
87
|
+
request = url
|
|
88
|
+
} else {
|
|
89
|
+
// every other url is threaded like a relative url
|
|
90
|
+
request = `./${url}`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A `~` makes the url an module
|
|
94
|
+
if (IS_MODULE_REQUEST.test(request)) {
|
|
95
|
+
request = request.replace(IS_MODULE_REQUEST, '')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return request
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// eslint-disable-next-line no-useless-escape
|
|
102
|
+
const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/
|
|
103
|
+
const regexExcessiveSpaces =
|
|
104
|
+
/(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g
|
|
105
|
+
|
|
106
|
+
const preserveCamelCase = (string) => {
|
|
107
|
+
let result = string
|
|
108
|
+
let isLastCharLower = false
|
|
109
|
+
let isLastCharUpper = false
|
|
110
|
+
let isLastLastCharUpper = false
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < result.length; i++) {
|
|
113
|
+
const character = result[i]
|
|
114
|
+
|
|
115
|
+
if (isLastCharLower && /[\p{Lu}]/u.test(character)) {
|
|
116
|
+
result = `${result.slice(0, i)}-${result.slice(i)}`
|
|
117
|
+
isLastCharLower = false
|
|
118
|
+
isLastLastCharUpper = isLastCharUpper
|
|
119
|
+
isLastCharUpper = true
|
|
120
|
+
i += 1
|
|
121
|
+
} else if (
|
|
122
|
+
isLastCharUpper &&
|
|
123
|
+
isLastLastCharUpper &&
|
|
124
|
+
/[\p{Ll}]/u.test(character)
|
|
125
|
+
) {
|
|
126
|
+
result = `${result.slice(0, i - 1)}-${result.slice(i - 1)}`
|
|
127
|
+
isLastLastCharUpper = isLastCharUpper
|
|
128
|
+
isLastCharUpper = false
|
|
129
|
+
isLastCharLower = true
|
|
130
|
+
} else {
|
|
131
|
+
isLastCharLower =
|
|
132
|
+
character.toLowerCase() === character &&
|
|
133
|
+
character.toUpperCase() !== character
|
|
134
|
+
isLastLastCharUpper = isLastCharUpper
|
|
135
|
+
isLastCharUpper =
|
|
136
|
+
character.toUpperCase() === character &&
|
|
137
|
+
character.toLowerCase() !== character
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return result
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function camelCase (input) {
|
|
145
|
+
let result = input.trim()
|
|
146
|
+
|
|
147
|
+
if (result.length === 0) {
|
|
148
|
+
return ''
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (result.length === 1) {
|
|
152
|
+
return result.toLowerCase()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const hasUpperCase = result !== result.toLowerCase()
|
|
156
|
+
|
|
157
|
+
if (hasUpperCase) {
|
|
158
|
+
result = preserveCamelCase(result)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
.replace(/^[_.\- ]+/, '')
|
|
163
|
+
.toLowerCase()
|
|
164
|
+
.replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toUpperCase())
|
|
165
|
+
.replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, (m) => m.toUpperCase())
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function escape (string) {
|
|
169
|
+
let output = ''
|
|
170
|
+
let counter = 0
|
|
171
|
+
|
|
172
|
+
while (counter < string.length) {
|
|
173
|
+
// eslint-disable-next-line no-plusplus
|
|
174
|
+
const character = string.charAt(counter++)
|
|
175
|
+
|
|
176
|
+
let value
|
|
177
|
+
|
|
178
|
+
// eslint-disable-next-line no-control-regex
|
|
179
|
+
if (/[\t\n\f\r\x0B]/.test(character)) {
|
|
180
|
+
const codePoint = character.charCodeAt()
|
|
181
|
+
|
|
182
|
+
value = `\\${codePoint.toString(16).toUpperCase()} `
|
|
183
|
+
} else if (character === '\\' || regexSingleEscape.test(character)) {
|
|
184
|
+
value = `\\${character}`
|
|
185
|
+
} else {
|
|
186
|
+
value = character
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
output += value
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const firstChar = string.charAt(0)
|
|
193
|
+
|
|
194
|
+
if (/^-[-\d]/.test(output)) {
|
|
195
|
+
output = `\\-${output.slice(1)}`
|
|
196
|
+
} else if (/\d/.test(firstChar)) {
|
|
197
|
+
output = `\\3${firstChar} ${output.slice(1)}`
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
|
|
201
|
+
// since they’re redundant. Note that this is only possible if the escape
|
|
202
|
+
// sequence isn’t preceded by an odd number of backslashes.
|
|
203
|
+
output = output.replace(regexExcessiveSpaces, ($0, $1, $2) => {
|
|
204
|
+
if ($1 && $1.length % 2) {
|
|
205
|
+
// It’s not safe to remove the space, so don’t.
|
|
206
|
+
return $0
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Strip the space.
|
|
210
|
+
return ($1 || '') + $2
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
return output
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function gobbleHex (str) {
|
|
217
|
+
const lower = str.toLowerCase()
|
|
218
|
+
let hex = ''
|
|
219
|
+
let spaceTerminated = false
|
|
220
|
+
|
|
221
|
+
// eslint-disable-next-line no-undefined
|
|
222
|
+
for (let i = 0; i < 6 && lower[i] !== undefined; i++) {
|
|
223
|
+
const code = lower.charCodeAt(i)
|
|
224
|
+
// check to see if we are dealing with a valid hex char [a-f|0-9]
|
|
225
|
+
const valid = (code >= 97 && code <= 102) || (code >= 48 && code <= 57)
|
|
226
|
+
// https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
|
|
227
|
+
spaceTerminated = code === 32
|
|
228
|
+
|
|
229
|
+
if (!valid) {
|
|
230
|
+
break
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
hex += lower[i]
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (hex.length === 0) {
|
|
237
|
+
// eslint-disable-next-line no-undefined
|
|
238
|
+
return undefined
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const codePoint = parseInt(hex, 16)
|
|
242
|
+
|
|
243
|
+
const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff
|
|
244
|
+
// Add special case for
|
|
245
|
+
// "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
|
|
246
|
+
// https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
|
|
247
|
+
if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
|
|
248
|
+
return ['\uFFFD', hex.length + (spaceTerminated ? 1 : 0)]
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return [
|
|
252
|
+
String.fromCodePoint(codePoint),
|
|
253
|
+
hex.length + (spaceTerminated ? 1 : 0)
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const CONTAINS_ESCAPE = /\\/
|
|
258
|
+
|
|
259
|
+
function unescape (str) {
|
|
260
|
+
const needToProcess = CONTAINS_ESCAPE.test(str)
|
|
261
|
+
|
|
262
|
+
if (!needToProcess) {
|
|
263
|
+
return str
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
let ret = ''
|
|
267
|
+
|
|
268
|
+
for (let i = 0; i < str.length; i++) {
|
|
269
|
+
if (str[i] === '\\') {
|
|
270
|
+
const gobbled = gobbleHex(str.slice(i + 1, i + 7))
|
|
271
|
+
|
|
272
|
+
// eslint-disable-next-line no-undefined
|
|
273
|
+
if (gobbled !== undefined) {
|
|
274
|
+
ret += gobbled[0]
|
|
275
|
+
i += gobbled[1]
|
|
276
|
+
|
|
277
|
+
// eslint-disable-next-line no-continue
|
|
278
|
+
continue
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Retain a pair of \\ if double escaped `\\\\`
|
|
282
|
+
// https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
|
|
283
|
+
if (str[i + 1] === '\\') {
|
|
284
|
+
ret += '\\'
|
|
285
|
+
i += 1
|
|
286
|
+
|
|
287
|
+
// eslint-disable-next-line no-continue
|
|
288
|
+
continue
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// if \\ is at the end of the string retain it
|
|
292
|
+
// https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
|
|
293
|
+
if (str.length === i + 1) {
|
|
294
|
+
ret += str[i]
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// eslint-disable-next-line no-continue
|
|
298
|
+
continue
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
ret += str[i]
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return ret
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function normalizePath (file) {
|
|
308
|
+
return path.sep === '\\' ? file.replace(/\\/g, '/') : file
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// eslint-disable-next-line no-control-regex
|
|
312
|
+
const filenameReservedRegex = /[<>:"/\\|?*]/g
|
|
313
|
+
// eslint-disable-next-line no-control-regex
|
|
314
|
+
const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g
|
|
315
|
+
|
|
316
|
+
function escapeLocalIdent (localident) {
|
|
317
|
+
// TODO simplify in the next major release
|
|
318
|
+
return escape(
|
|
319
|
+
localident
|
|
320
|
+
// For `[hash]` placeholder
|
|
321
|
+
.replace(/^((-?[0-9])|--)/, '_$1')
|
|
322
|
+
.replace(filenameReservedRegex, '-')
|
|
323
|
+
.replace(reControlChars, '-')
|
|
324
|
+
.replace(/\./g, '-')
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function defaultGetLocalIdent (
|
|
329
|
+
loaderContext,
|
|
330
|
+
localIdentName,
|
|
331
|
+
localName,
|
|
332
|
+
options
|
|
333
|
+
) {
|
|
334
|
+
const { context, hashSalt, hashStrategy } = options
|
|
335
|
+
const { resourcePath } = loaderContext
|
|
336
|
+
const relativeResourcePath = normalizePath(
|
|
337
|
+
path.relative(context, resourcePath)
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
// eslint-disable-next-line no-param-reassign
|
|
341
|
+
options.content =
|
|
342
|
+
hashStrategy === 'minimal-subset' && /\[local\]/.test(localIdentName)
|
|
343
|
+
? relativeResourcePath
|
|
344
|
+
: `${relativeResourcePath}\x00${localName}`
|
|
345
|
+
|
|
346
|
+
let { hashFunction, hashDigest, hashDigestLength } = options
|
|
347
|
+
const matches = localIdentName.match(
|
|
348
|
+
/\[(?:([^:\]]+):)?(?:(hash|contenthash|fullhash))(?::([a-z]+\d*))?(?::(\d+))?\]/i
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
if (matches) {
|
|
352
|
+
const hashName = matches[2] || hashFunction
|
|
353
|
+
|
|
354
|
+
hashFunction = matches[1] || hashFunction
|
|
355
|
+
hashDigest = matches[3] || hashDigest
|
|
356
|
+
hashDigestLength = matches[4] || hashDigestLength
|
|
357
|
+
|
|
358
|
+
// `hash` and `contenthash` are same in `loader-utils` context
|
|
359
|
+
// let's keep `hash` for backward compatibility
|
|
360
|
+
|
|
361
|
+
// eslint-disable-next-line no-param-reassign
|
|
362
|
+
localIdentName = localIdentName.replace(
|
|
363
|
+
/\[(?:([^:\]]+):)?(?:hash|contenthash|fullhash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
|
|
364
|
+
() => (hashName === 'fullhash' ? '[fullhash]' : '[contenthash]')
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
let localIdentHash = ''
|
|
369
|
+
|
|
370
|
+
for (let tier = 0; localIdentHash.length < hashDigestLength; tier++) {
|
|
371
|
+
// TODO remove this in the next major release
|
|
372
|
+
const hash =
|
|
373
|
+
loaderContext.utils &&
|
|
374
|
+
typeof loaderContext.utils.createHash === 'function'
|
|
375
|
+
? loaderContext.utils.createHash(hashFunction)
|
|
376
|
+
: // eslint-disable-next-line no-underscore-dangle
|
|
377
|
+
loaderContext._compiler.webpack.util.createHash(hashFunction)
|
|
378
|
+
|
|
379
|
+
if (hashSalt) {
|
|
380
|
+
hash.update(hashSalt)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const tierSalt = Buffer.allocUnsafe(4)
|
|
384
|
+
|
|
385
|
+
tierSalt.writeUInt32LE(tier)
|
|
386
|
+
|
|
387
|
+
hash.update(tierSalt)
|
|
388
|
+
// TODO: bug in webpack with unicode characters with strings
|
|
389
|
+
hash.update(Buffer.from(options.content, 'utf8'))
|
|
390
|
+
|
|
391
|
+
localIdentHash = (localIdentHash + hash.digest(hashDigest))
|
|
392
|
+
// Remove all leading digits
|
|
393
|
+
.replace(/^\d+/, '')
|
|
394
|
+
// Replace all slashes with underscores (same as in base64url)
|
|
395
|
+
.replace(/\//g, '_')
|
|
396
|
+
// Remove everything that is not an alphanumeric or underscore
|
|
397
|
+
.replace(/[^A-Za-z0-9_]+/g, '')
|
|
398
|
+
.slice(0, hashDigestLength)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// TODO need improve on webpack side, we should allow to pass hash/contentHash without chunk property, also `data` for `getPath` should be looks good without chunk property
|
|
402
|
+
const ext = path.extname(resourcePath)
|
|
403
|
+
const base = path.basename(resourcePath)
|
|
404
|
+
const name = base.slice(0, base.length - ext.length)
|
|
405
|
+
const data = {
|
|
406
|
+
filename: path.relative(context, resourcePath),
|
|
407
|
+
contentHash: localIdentHash,
|
|
408
|
+
chunk: {
|
|
409
|
+
name,
|
|
410
|
+
hash: localIdentHash,
|
|
411
|
+
contentHash: localIdentHash
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
416
|
+
let result = loaderContext._compilation.getPath(localIdentName, data)
|
|
417
|
+
|
|
418
|
+
if (/\[folder\]/gi.test(result)) {
|
|
419
|
+
const dirname = path.dirname(resourcePath)
|
|
420
|
+
let directory = normalizePath(
|
|
421
|
+
path.relative(context, `${dirname + path.sep}_`)
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
directory = directory.substr(0, directory.length - 1)
|
|
425
|
+
|
|
426
|
+
let folder = ''
|
|
427
|
+
|
|
428
|
+
if (directory.length > 1) {
|
|
429
|
+
folder = path.basename(directory)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
result = result.replace(/\[folder\]/gi, () => folder)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (options.regExp) {
|
|
436
|
+
const match = resourcePath.match(options.regExp)
|
|
437
|
+
|
|
438
|
+
if (match) {
|
|
439
|
+
match.forEach((matched, i) => {
|
|
440
|
+
result = result.replace(new RegExp(`\\[${i}\\]`, 'ig'), matched)
|
|
441
|
+
})
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return result
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function fixedEncodeURIComponent (str) {
|
|
449
|
+
return str.replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16)}`)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function isDataUrl (url) {
|
|
453
|
+
if (/^data:/i.test(url)) {
|
|
454
|
+
return true
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return false
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const NATIVE_WIN32_PATH = /^[A-Z]:[/\\]|^\\\\/i
|
|
461
|
+
|
|
462
|
+
function normalizeUrl (url, isStringValue) {
|
|
463
|
+
let normalizedUrl = url
|
|
464
|
+
.replace(/^( |\t\n|\r\n|\r|\f)*/g, '')
|
|
465
|
+
.replace(/( |\t\n|\r\n|\r|\f)*$/g, '')
|
|
466
|
+
|
|
467
|
+
if (isStringValue && /\\(\n|\r\n|\r|\f)/.test(normalizedUrl)) {
|
|
468
|
+
normalizedUrl = normalizedUrl.replace(/\\(\n|\r\n|\r|\f)/g, '')
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (NATIVE_WIN32_PATH.test(url)) {
|
|
472
|
+
try {
|
|
473
|
+
normalizedUrl = decodeURI(normalizedUrl)
|
|
474
|
+
} catch (error) {
|
|
475
|
+
// Ignore
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return normalizedUrl
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
normalizedUrl = unescape(normalizedUrl)
|
|
482
|
+
|
|
483
|
+
if (isDataUrl(url)) {
|
|
484
|
+
// Todo fixedEncodeURIComponent is workaround. Webpack resolver shouldn't handle "!" in dataURL
|
|
485
|
+
return fixedEncodeURIComponent(normalizedUrl)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
normalizedUrl = decodeURI(normalizedUrl)
|
|
490
|
+
} catch (error) {
|
|
491
|
+
// Ignore
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return normalizedUrl
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function requestify (url, rootContext, needToResolveURL = true) {
|
|
498
|
+
if (needToResolveURL) {
|
|
499
|
+
if (/^file:/i.test(url)) {
|
|
500
|
+
return fileURLToPath(url)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return url.charAt(0) === '/'
|
|
504
|
+
? urlToRequest(url, rootContext)
|
|
505
|
+
: urlToRequest(url)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (url.charAt(0) === '/' || /^file:/i.test(url)) {
|
|
509
|
+
return url
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// A `~` makes the url an module
|
|
513
|
+
if (IS_MODULE_REQUEST.test(url)) {
|
|
514
|
+
return url.replace(IS_MODULE_REQUEST, '')
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return url
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function getFilter (filter, resourcePath) {
|
|
521
|
+
return (...args) => {
|
|
522
|
+
if (typeof filter === 'function') {
|
|
523
|
+
return filter(...args, resourcePath)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return true
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function getValidLocalName (localName, exportLocalsConvention) {
|
|
531
|
+
const result = exportLocalsConvention(localName)
|
|
532
|
+
|
|
533
|
+
return Array.isArray(result) ? result[0] : result
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const IS_MODULES = /\.module(s)?\.\w+$/i
|
|
537
|
+
const IS_ICSS = /\.icss\.\w+$/i
|
|
538
|
+
|
|
539
|
+
function getModulesOptions (rawOptions, exportType, loaderContext) {
|
|
540
|
+
if (typeof rawOptions.modules === 'boolean' && rawOptions.modules === false) {
|
|
541
|
+
return false
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const resourcePath =
|
|
545
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
546
|
+
(loaderContext._module && loaderContext._module.matchResource) ||
|
|
547
|
+
loaderContext.resourcePath
|
|
548
|
+
|
|
549
|
+
let auto
|
|
550
|
+
let rawModulesOptions
|
|
551
|
+
|
|
552
|
+
if (typeof rawOptions.modules === 'undefined') {
|
|
553
|
+
rawModulesOptions = {}
|
|
554
|
+
auto = true
|
|
555
|
+
} else if (typeof rawOptions.modules === 'boolean') {
|
|
556
|
+
rawModulesOptions = {}
|
|
557
|
+
} else if (typeof rawOptions.modules === 'string') {
|
|
558
|
+
rawModulesOptions = { mode: rawOptions.modules }
|
|
559
|
+
} else {
|
|
560
|
+
rawModulesOptions = rawOptions.modules;
|
|
561
|
+
({ auto } = rawModulesOptions)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
565
|
+
const { outputOptions } = loaderContext._compilation
|
|
566
|
+
const needNamedExport =
|
|
567
|
+
exportType === 'css-style-sheet' || exportType === 'string'
|
|
568
|
+
const modulesOptions = {
|
|
569
|
+
auto,
|
|
570
|
+
mode: 'local',
|
|
571
|
+
exportGlobals: false,
|
|
572
|
+
localIdentName: '[hash:base64]',
|
|
573
|
+
localIdentContext: loaderContext.rootContext,
|
|
574
|
+
localIdentHashSalt: outputOptions.hashSalt,
|
|
575
|
+
localIdentHashFunction: outputOptions.hashFunction,
|
|
576
|
+
localIdentHashDigest: outputOptions.hashDigest,
|
|
577
|
+
localIdentHashDigestLength: outputOptions.hashDigestLength,
|
|
578
|
+
// eslint-disable-next-line no-undefined
|
|
579
|
+
localIdentRegExp: undefined,
|
|
580
|
+
// eslint-disable-next-line no-undefined
|
|
581
|
+
getLocalIdent: undefined,
|
|
582
|
+
namedExport: needNamedExport || false,
|
|
583
|
+
exportLocalsConvention:
|
|
584
|
+
(rawModulesOptions.namedExport === true || needNamedExport) &&
|
|
585
|
+
typeof rawModulesOptions.exportLocalsConvention === 'undefined'
|
|
586
|
+
? 'camelCaseOnly'
|
|
587
|
+
: 'asIs',
|
|
588
|
+
exportOnlyLocals: false,
|
|
589
|
+
...rawModulesOptions
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
let exportLocalsConventionType
|
|
593
|
+
|
|
594
|
+
if (typeof modulesOptions.exportLocalsConvention === 'string') {
|
|
595
|
+
exportLocalsConventionType = modulesOptions.exportLocalsConvention
|
|
596
|
+
|
|
597
|
+
modulesOptions.exportLocalsConvention = (name) => {
|
|
598
|
+
switch (exportLocalsConventionType) {
|
|
599
|
+
case 'camelCase': {
|
|
600
|
+
return [name, camelCase(name)]
|
|
601
|
+
}
|
|
602
|
+
case 'camelCaseOnly': {
|
|
603
|
+
return camelCase(name)
|
|
604
|
+
}
|
|
605
|
+
case 'dashes': {
|
|
606
|
+
return [name, dashesCamelCase(name)]
|
|
607
|
+
}
|
|
608
|
+
case 'dashesOnly': {
|
|
609
|
+
return dashesCamelCase(name)
|
|
610
|
+
}
|
|
611
|
+
case 'asIs':
|
|
612
|
+
default:
|
|
613
|
+
return name
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (typeof modulesOptions.auto === 'boolean') {
|
|
619
|
+
const isModules = modulesOptions.auto && IS_MODULES.test(resourcePath)
|
|
620
|
+
|
|
621
|
+
let isIcss
|
|
622
|
+
|
|
623
|
+
if (!isModules) {
|
|
624
|
+
isIcss = IS_ICSS.test(resourcePath)
|
|
625
|
+
|
|
626
|
+
if (isIcss) {
|
|
627
|
+
modulesOptions.mode = 'icss'
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (!isModules && !isIcss) {
|
|
632
|
+
return false
|
|
633
|
+
}
|
|
634
|
+
} else if (modulesOptions.auto instanceof RegExp) {
|
|
635
|
+
const isModules = modulesOptions.auto.test(resourcePath)
|
|
636
|
+
|
|
637
|
+
if (!isModules) {
|
|
638
|
+
return false
|
|
639
|
+
}
|
|
640
|
+
} else if (typeof modulesOptions.auto === 'function') {
|
|
641
|
+
const isModule = modulesOptions.auto(resourcePath)
|
|
642
|
+
|
|
643
|
+
if (!isModule) {
|
|
644
|
+
return false
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (typeof modulesOptions.mode === 'function') {
|
|
649
|
+
modulesOptions.mode = modulesOptions.mode(loaderContext.resourcePath)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (needNamedExport) {
|
|
653
|
+
if (rawOptions.esModule === false) {
|
|
654
|
+
throw new Error(
|
|
655
|
+
"The 'exportType' option with the 'css-style-sheet' or 'string' value requires the 'esModules' option to be enabled"
|
|
656
|
+
)
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (modulesOptions.namedExport === false) {
|
|
660
|
+
throw new Error(
|
|
661
|
+
"The 'exportType' option with the 'css-style-sheet' or 'string' value requires the 'modules.namedExport' option to be enabled"
|
|
662
|
+
)
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (modulesOptions.namedExport === true) {
|
|
667
|
+
if (rawOptions.esModule === false) {
|
|
668
|
+
throw new Error(
|
|
669
|
+
"The 'modules.namedExport' option requires the 'esModules' option to be enabled"
|
|
670
|
+
)
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (
|
|
674
|
+
typeof exportLocalsConventionType === 'string' &&
|
|
675
|
+
exportLocalsConventionType !== 'camelCaseOnly' &&
|
|
676
|
+
exportLocalsConventionType !== 'dashesOnly'
|
|
677
|
+
) {
|
|
678
|
+
throw new Error(
|
|
679
|
+
'The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly" or "dashesOnly"'
|
|
680
|
+
)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return modulesOptions
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function normalizeOptions (rawOptions, loaderContext) {
|
|
688
|
+
const exportType =
|
|
689
|
+
typeof rawOptions.exportType === 'undefined'
|
|
690
|
+
? 'array'
|
|
691
|
+
: rawOptions.exportType
|
|
692
|
+
const modulesOptions = getModulesOptions(
|
|
693
|
+
rawOptions,
|
|
694
|
+
exportType,
|
|
695
|
+
loaderContext
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
return {
|
|
699
|
+
url: typeof rawOptions.url === 'undefined' ? true : rawOptions.url,
|
|
700
|
+
import: typeof rawOptions.import === 'undefined' ? true : rawOptions.import,
|
|
701
|
+
modules: modulesOptions,
|
|
702
|
+
sourceMap:
|
|
703
|
+
typeof rawOptions.sourceMap === 'boolean'
|
|
704
|
+
? rawOptions.sourceMap
|
|
705
|
+
: loaderContext.sourceMap,
|
|
706
|
+
importLoaders:
|
|
707
|
+
typeof rawOptions.importLoaders === 'string'
|
|
708
|
+
? parseInt(rawOptions.importLoaders, 10)
|
|
709
|
+
: rawOptions.importLoaders,
|
|
710
|
+
esModule:
|
|
711
|
+
typeof rawOptions.esModule === 'undefined' ? false : rawOptions.esModule, // 默认改为 false
|
|
712
|
+
exportType
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function shouldUseImportPlugin (options) {
|
|
717
|
+
if (options.modules.exportOnlyLocals) {
|
|
718
|
+
return false
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (typeof options.import === 'boolean') {
|
|
722
|
+
return options.import
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return true
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function shouldUseURLPlugin (options) {
|
|
729
|
+
if (options.modules.exportOnlyLocals) {
|
|
730
|
+
return false
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (typeof options.url === 'boolean') {
|
|
734
|
+
return options.url
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return true
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function shouldUseModulesPlugins (options) {
|
|
741
|
+
if (typeof options.modules === 'boolean' && options.modules === false) {
|
|
742
|
+
return false
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return options.modules.mode !== 'icss'
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function shouldUseIcssPlugin (options) {
|
|
749
|
+
return Boolean(options.modules)
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
function getModulesPlugins (options, loaderContext) {
|
|
753
|
+
const {
|
|
754
|
+
mode,
|
|
755
|
+
getLocalIdent,
|
|
756
|
+
localIdentName,
|
|
757
|
+
localIdentContext,
|
|
758
|
+
localIdentHashSalt,
|
|
759
|
+
localIdentHashFunction,
|
|
760
|
+
localIdentHashDigest,
|
|
761
|
+
localIdentHashDigestLength,
|
|
762
|
+
localIdentRegExp,
|
|
763
|
+
hashStrategy
|
|
764
|
+
} = options.modules
|
|
765
|
+
|
|
766
|
+
let plugins = []
|
|
767
|
+
|
|
768
|
+
try {
|
|
769
|
+
plugins = [
|
|
770
|
+
modulesValues,
|
|
771
|
+
localByDefault({ mode }),
|
|
772
|
+
extractImports(),
|
|
773
|
+
modulesScope({
|
|
774
|
+
generateScopedName (exportName) {
|
|
775
|
+
let localIdent
|
|
776
|
+
|
|
777
|
+
if (typeof getLocalIdent !== 'undefined') {
|
|
778
|
+
localIdent = getLocalIdent(
|
|
779
|
+
loaderContext,
|
|
780
|
+
localIdentName,
|
|
781
|
+
unescape(exportName),
|
|
782
|
+
{
|
|
783
|
+
context: localIdentContext,
|
|
784
|
+
hashSalt: localIdentHashSalt,
|
|
785
|
+
hashFunction: localIdentHashFunction,
|
|
786
|
+
hashDigest: localIdentHashDigest,
|
|
787
|
+
hashDigestLength: localIdentHashDigestLength,
|
|
788
|
+
hashStrategy,
|
|
789
|
+
regExp: localIdentRegExp
|
|
790
|
+
}
|
|
791
|
+
)
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// A null/undefined value signals that we should invoke the default
|
|
795
|
+
// getLocalIdent method.
|
|
796
|
+
if (typeof localIdent === 'undefined' || localIdent === null) {
|
|
797
|
+
localIdent = defaultGetLocalIdent(
|
|
798
|
+
loaderContext,
|
|
799
|
+
localIdentName,
|
|
800
|
+
unescape(exportName),
|
|
801
|
+
{
|
|
802
|
+
context: localIdentContext,
|
|
803
|
+
hashSalt: localIdentHashSalt,
|
|
804
|
+
hashFunction: localIdentHashFunction,
|
|
805
|
+
hashDigest: localIdentHashDigest,
|
|
806
|
+
hashDigestLength: localIdentHashDigestLength,
|
|
807
|
+
hashStrategy,
|
|
808
|
+
regExp: localIdentRegExp
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
return escapeLocalIdent(localIdent).replace(
|
|
813
|
+
/\\\[local\\]/gi,
|
|
814
|
+
exportName
|
|
815
|
+
)
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return escapeLocalIdent(localIdent)
|
|
819
|
+
},
|
|
820
|
+
exportGlobals: options.modules.exportGlobals
|
|
821
|
+
})
|
|
822
|
+
]
|
|
823
|
+
} catch (error) {
|
|
824
|
+
loaderContext.emitError(error)
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
return plugins
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const ABSOLUTE_SCHEME = /^[a-z0-9+\-.]+:/i
|
|
831
|
+
|
|
832
|
+
function getURLType (source) {
|
|
833
|
+
if (source[0] === '/') {
|
|
834
|
+
if (source[1] === '/') {
|
|
835
|
+
return 'scheme-relative'
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return 'path-absolute'
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (IS_NATIVE_WIN32_PATH.test(source)) {
|
|
842
|
+
return 'path-absolute'
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
return ABSOLUTE_SCHEME.test(source) ? 'absolute' : 'path-relative'
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
function normalizeSourceMap (map, resourcePath) {
|
|
849
|
+
let newMap = map
|
|
850
|
+
|
|
851
|
+
// Some loader emit source map as string
|
|
852
|
+
// Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
|
|
853
|
+
if (typeof newMap === 'string') {
|
|
854
|
+
newMap = JSON.parse(newMap)
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
delete newMap.file
|
|
858
|
+
|
|
859
|
+
const { sourceRoot } = newMap
|
|
860
|
+
|
|
861
|
+
delete newMap.sourceRoot
|
|
862
|
+
|
|
863
|
+
if (newMap.sources) {
|
|
864
|
+
// Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
|
|
865
|
+
// We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
|
|
866
|
+
newMap.sources = newMap.sources.map((source) => {
|
|
867
|
+
// Non-standard syntax from `postcss`
|
|
868
|
+
if (source.indexOf('<') === 0) {
|
|
869
|
+
return source
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const sourceType = getURLType(source)
|
|
873
|
+
|
|
874
|
+
// Do no touch `scheme-relative` and `absolute` URLs
|
|
875
|
+
if (sourceType === 'path-relative' || sourceType === 'path-absolute') {
|
|
876
|
+
const absoluteSource =
|
|
877
|
+
sourceType === 'path-relative' && sourceRoot
|
|
878
|
+
? path.resolve(sourceRoot, normalizePath(source))
|
|
879
|
+
: normalizePath(source)
|
|
880
|
+
|
|
881
|
+
return path.relative(path.dirname(resourcePath), absoluteSource)
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return source
|
|
885
|
+
})
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
return newMap
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
function getPreRequester ({ loaders, loaderIndex }) {
|
|
892
|
+
const cache = Object.create(null)
|
|
893
|
+
|
|
894
|
+
return (number) => {
|
|
895
|
+
if (cache[number]) {
|
|
896
|
+
return cache[number]
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (number === false) {
|
|
900
|
+
cache[number] = ''
|
|
901
|
+
} else {
|
|
902
|
+
const loadersRequest = loaders
|
|
903
|
+
.slice(
|
|
904
|
+
loaderIndex,
|
|
905
|
+
loaderIndex + 1 + (typeof number !== 'number' ? 0 : number + 1) // 与css-loader 不同,需要增加 1,因为 css 文件会经过 style-compiler loader 进行处理。
|
|
906
|
+
)
|
|
907
|
+
.map((x) => x.request)
|
|
908
|
+
.join('!')
|
|
909
|
+
|
|
910
|
+
cache[number] = `-!${loadersRequest}!`
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return cache[number]
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function getImportCode (imports, options) {
|
|
918
|
+
let code = ''
|
|
919
|
+
|
|
920
|
+
for (const item of imports) {
|
|
921
|
+
const { importName, url, icss, type } = item
|
|
922
|
+
|
|
923
|
+
if (options.esModule) {
|
|
924
|
+
if (icss && options.modules.namedExport) {
|
|
925
|
+
code += `import ${
|
|
926
|
+
options.modules.exportOnlyLocals ? '' : `${importName}, `
|
|
927
|
+
}* as ${importName}_NAMED___ from ${url};\n`
|
|
928
|
+
} else {
|
|
929
|
+
code +=
|
|
930
|
+
type === 'url'
|
|
931
|
+
? `var ${importName} = new URL(${url}, import.meta.url);\n`
|
|
932
|
+
: `import ${importName} from ${url};\n`
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
code += `var ${importName} = require(${url});\n`
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return code ? `// Imports\n${code}` : ''
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
function normalizeSourceMapForRuntime (map, loaderContext) {
|
|
943
|
+
const resultMap = map ? map.toJSON() : null
|
|
944
|
+
|
|
945
|
+
if (resultMap) {
|
|
946
|
+
delete resultMap.file
|
|
947
|
+
|
|
948
|
+
/* eslint-disable no-underscore-dangle */
|
|
949
|
+
if (
|
|
950
|
+
loaderContext._compilation &&
|
|
951
|
+
loaderContext._compilation.options &&
|
|
952
|
+
loaderContext._compilation.options.devtool &&
|
|
953
|
+
loaderContext._compilation.options.devtool.includes('nosources')
|
|
954
|
+
) {
|
|
955
|
+
/* eslint-enable no-underscore-dangle */
|
|
956
|
+
|
|
957
|
+
delete resultMap.sourcesContent
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
resultMap.sourceRoot = ''
|
|
961
|
+
resultMap.sources = resultMap.sources.map((source) => {
|
|
962
|
+
// Non-standard syntax from `postcss`
|
|
963
|
+
if (source.indexOf('<') === 0) {
|
|
964
|
+
return source
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const sourceType = getURLType(source)
|
|
968
|
+
|
|
969
|
+
if (sourceType !== 'path-relative') {
|
|
970
|
+
return source
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const resourceDirname = path.dirname(loaderContext.resourcePath)
|
|
974
|
+
const absoluteSource = path.resolve(resourceDirname, source)
|
|
975
|
+
const contextifyPath = normalizePath(
|
|
976
|
+
path.relative(loaderContext.rootContext, absoluteSource)
|
|
977
|
+
)
|
|
978
|
+
|
|
979
|
+
return `webpack://./${contextifyPath}`
|
|
980
|
+
})
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
return JSON.stringify(resultMap)
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
function printParams (media, dedupe, supports, layer) {
|
|
987
|
+
let result = ''
|
|
988
|
+
|
|
989
|
+
if (typeof layer !== 'undefined') {
|
|
990
|
+
result = `, ${JSON.stringify(layer)}`
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (typeof supports !== 'undefined') {
|
|
994
|
+
result = `, ${JSON.stringify(supports)}${result}`
|
|
995
|
+
} else if (result.length > 0) {
|
|
996
|
+
result = `, undefined${result}`
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (dedupe) {
|
|
1000
|
+
result = `, true${result}`
|
|
1001
|
+
} else if (result.length > 0) {
|
|
1002
|
+
result = `, false${result}`
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
if (media) {
|
|
1006
|
+
result = `${JSON.stringify(media)}${result}`
|
|
1007
|
+
} else if (result.length > 0) {
|
|
1008
|
+
result = `""${result}`
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
return result
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function getModuleCode (
|
|
1015
|
+
result,
|
|
1016
|
+
api,
|
|
1017
|
+
replacements,
|
|
1018
|
+
options,
|
|
1019
|
+
loaderContext
|
|
1020
|
+
) {
|
|
1021
|
+
if (options.modules.exportOnlyLocals === true) {
|
|
1022
|
+
return ''
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
let sourceMapValue = ''
|
|
1026
|
+
|
|
1027
|
+
if (options.sourceMap) {
|
|
1028
|
+
const sourceMap = result.map
|
|
1029
|
+
|
|
1030
|
+
sourceMapValue = `,${normalizeSourceMapForRuntime(
|
|
1031
|
+
sourceMap,
|
|
1032
|
+
loaderContext
|
|
1033
|
+
)}`
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
let code = JSON.stringify(result.css)
|
|
1037
|
+
|
|
1038
|
+
let beforeCode = `var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(${
|
|
1039
|
+
options.sourceMap
|
|
1040
|
+
? '___CSS_LOADER_API_SOURCEMAP_IMPORT___'
|
|
1041
|
+
: '___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___'
|
|
1042
|
+
});\n`
|
|
1043
|
+
|
|
1044
|
+
for (const item of api) {
|
|
1045
|
+
const { url, layer, supports, media, dedupe } = item
|
|
1046
|
+
|
|
1047
|
+
if (url) {
|
|
1048
|
+
// eslint-disable-next-line no-undefined
|
|
1049
|
+
const printedParam = printParams(media, undefined, supports, layer)
|
|
1050
|
+
|
|
1051
|
+
beforeCode += `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(
|
|
1052
|
+
`@import url(${url});`
|
|
1053
|
+
)}${printedParam.length > 0 ? `, ${printedParam}` : ''}]);\n`
|
|
1054
|
+
} else {
|
|
1055
|
+
// 符合css后缀名的文件经过mpx处理后会带上相应的后缀防止使用 WebPack 的默认解析规则,此时 require/import 相应路径时,导出的不是一段 css 代码了,事实上是一个文件路径。
|
|
1056
|
+
const printedParam = printParams(media, dedupe, supports, layer)
|
|
1057
|
+
const otherParams = printedParam.length > 0 ? printedParam : ''
|
|
1058
|
+
beforeCode += `___CSS_LOADER_EXPORT___.push([module.id, '@import "' + ${item.importName} + '";', ${JSON.stringify(otherParams)} ]);\n`
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
for (const item of replacements) {
|
|
1063
|
+
const { replacementName, importName, localName } = item
|
|
1064
|
+
|
|
1065
|
+
if (localName) {
|
|
1066
|
+
code = code.replace(new RegExp(replacementName, 'g'), () =>
|
|
1067
|
+
options.modules.namedExport
|
|
1068
|
+
? `" + ${importName}_NAMED___[${JSON.stringify(
|
|
1069
|
+
getValidLocalName(
|
|
1070
|
+
localName,
|
|
1071
|
+
options.modules.exportLocalsConvention
|
|
1072
|
+
)
|
|
1073
|
+
)}] + "`
|
|
1074
|
+
: `" + ${importName}.locals[${JSON.stringify(localName)}] + "`
|
|
1075
|
+
)
|
|
1076
|
+
} else {
|
|
1077
|
+
const { hash, needQuotes } = item
|
|
1078
|
+
const getUrlOptions = []
|
|
1079
|
+
.concat(hash ? [`hash: ${JSON.stringify(hash)}`] : [])
|
|
1080
|
+
.concat(needQuotes ? 'needQuotes: true' : [])
|
|
1081
|
+
const preparedOptions =
|
|
1082
|
+
getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(', ')} }` : ''
|
|
1083
|
+
|
|
1084
|
+
beforeCode += `var ${replacementName} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});\n`
|
|
1085
|
+
code = code.replace(
|
|
1086
|
+
new RegExp(replacementName, 'g'),
|
|
1087
|
+
() => `" + ${replacementName} + "`
|
|
1088
|
+
)
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// Indexes description:
|
|
1093
|
+
// 0 - module id
|
|
1094
|
+
// 1 - CSS code
|
|
1095
|
+
// 2 - media
|
|
1096
|
+
// 3 - source map
|
|
1097
|
+
// 4 - supports
|
|
1098
|
+
// 5 - layer
|
|
1099
|
+
return `${beforeCode}// Module\n___CSS_LOADER_EXPORT___.push([module.id, ${code}, ""${sourceMapValue}]);\n`
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function dashesCamelCase (str) {
|
|
1103
|
+
return str.replace(/-+(\w)/g, (match, firstLetter) =>
|
|
1104
|
+
firstLetter.toUpperCase()
|
|
1105
|
+
)
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function getExportCode (exports, replacements, icssPluginUsed, options) {
|
|
1109
|
+
let code = '// Exports\n'
|
|
1110
|
+
|
|
1111
|
+
if (icssPluginUsed) {
|
|
1112
|
+
let localsCode = ''
|
|
1113
|
+
|
|
1114
|
+
const addExportToLocalsCode = (names, value) => {
|
|
1115
|
+
const normalizedNames = Array.isArray(names)
|
|
1116
|
+
? new Set(names)
|
|
1117
|
+
: new Set([names])
|
|
1118
|
+
|
|
1119
|
+
for (const name of normalizedNames) {
|
|
1120
|
+
if (options.modules.namedExport) {
|
|
1121
|
+
localsCode += `export var ${name} = ${JSON.stringify(value)};\n`
|
|
1122
|
+
} else {
|
|
1123
|
+
if (localsCode) {
|
|
1124
|
+
localsCode += ',\n'
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
localsCode += `\t${JSON.stringify(name)}: ${JSON.stringify(value)}`
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
for (const { name, value } of exports) {
|
|
1133
|
+
addExportToLocalsCode(
|
|
1134
|
+
options.modules.exportLocalsConvention(name),
|
|
1135
|
+
value
|
|
1136
|
+
)
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
for (const item of replacements) {
|
|
1140
|
+
const { replacementName, localName } = item
|
|
1141
|
+
|
|
1142
|
+
if (localName) {
|
|
1143
|
+
const { importName } = item
|
|
1144
|
+
|
|
1145
|
+
localsCode = localsCode.replace(
|
|
1146
|
+
new RegExp(replacementName, 'g'),
|
|
1147
|
+
() => {
|
|
1148
|
+
if (options.modules.namedExport) {
|
|
1149
|
+
return `" + ${importName}_NAMED___[${JSON.stringify(
|
|
1150
|
+
getValidLocalName(
|
|
1151
|
+
localName,
|
|
1152
|
+
options.modules.exportLocalsConvention
|
|
1153
|
+
)
|
|
1154
|
+
)}] + "`
|
|
1155
|
+
} else if (options.modules.exportOnlyLocals) {
|
|
1156
|
+
return `" + ${importName}[${JSON.stringify(localName)}] + "`
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return `" + ${importName}.locals[${JSON.stringify(localName)}] + "`
|
|
1160
|
+
}
|
|
1161
|
+
)
|
|
1162
|
+
} else {
|
|
1163
|
+
localsCode = localsCode.replace(
|
|
1164
|
+
new RegExp(replacementName, 'g'),
|
|
1165
|
+
() => `" + ${replacementName} + "`
|
|
1166
|
+
)
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (options.modules.exportOnlyLocals) {
|
|
1171
|
+
code += options.modules.namedExport
|
|
1172
|
+
? localsCode
|
|
1173
|
+
: `${
|
|
1174
|
+
options.esModule ? 'export default' : 'module.exports ='
|
|
1175
|
+
} {\n${localsCode}\n};\n`
|
|
1176
|
+
|
|
1177
|
+
return code
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
code += options.modules.namedExport
|
|
1181
|
+
? localsCode
|
|
1182
|
+
: `___CSS_LOADER_EXPORT___.locals = {${
|
|
1183
|
+
localsCode ? `\n${localsCode}\n` : ''
|
|
1184
|
+
}};\n`
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
const isCSSStyleSheetExport = options.exportType === 'css-style-sheet'
|
|
1188
|
+
|
|
1189
|
+
if (isCSSStyleSheetExport) {
|
|
1190
|
+
code += 'var ___CSS_LOADER_STYLE_SHEET___ = new CSSStyleSheet();\n'
|
|
1191
|
+
code +=
|
|
1192
|
+
'___CSS_LOADER_STYLE_SHEET___.replaceSync(___CSS_LOADER_EXPORT___.toString());\n'
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
let finalExport
|
|
1196
|
+
|
|
1197
|
+
switch (options.exportType) {
|
|
1198
|
+
case 'string':
|
|
1199
|
+
finalExport = '___CSS_LOADER_EXPORT___.toString()'
|
|
1200
|
+
break
|
|
1201
|
+
case 'css-style-sheet':
|
|
1202
|
+
finalExport = '___CSS_LOADER_STYLE_SHEET___'
|
|
1203
|
+
break
|
|
1204
|
+
/* eslint-disable default-case-last */
|
|
1205
|
+
default:
|
|
1206
|
+
case 'array':
|
|
1207
|
+
finalExport = '___CSS_LOADER_EXPORT___'
|
|
1208
|
+
break
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
code += `${
|
|
1212
|
+
options.esModule ? 'export default ' : 'module.exports ='
|
|
1213
|
+
} ${finalExport};\n`
|
|
1214
|
+
|
|
1215
|
+
return code
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
async function resolveRequests (resolve, context, possibleRequests) {
|
|
1219
|
+
return resolve(context, possibleRequests[0])
|
|
1220
|
+
.then((result) => result)
|
|
1221
|
+
.catch((error) => {
|
|
1222
|
+
const [, ...tailPossibleRequests] = possibleRequests
|
|
1223
|
+
|
|
1224
|
+
if (tailPossibleRequests.length === 0) {
|
|
1225
|
+
throw error
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
return resolveRequests(resolve, context, tailPossibleRequests)
|
|
1229
|
+
})
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function isURLRequestable (url, options = {}) {
|
|
1233
|
+
// 先用 mpx 内部维护方法判断
|
|
1234
|
+
if (!isUrlRequest(url, options.root, options.externals)) {
|
|
1235
|
+
return { requestable: false, needResolve: false }
|
|
1236
|
+
}
|
|
1237
|
+
// Protocol-relative URLs
|
|
1238
|
+
if (/^\/\//.test(url)) {
|
|
1239
|
+
return { requestable: false, needResolve: false }
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// `#` URLs
|
|
1243
|
+
if (/^#/.test(url)) {
|
|
1244
|
+
return { requestable: false, needResolve: false }
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// Data URI
|
|
1248
|
+
if (isDataUrl(url) && options.isSupportDataURL) {
|
|
1249
|
+
try {
|
|
1250
|
+
decodeURIComponent(url)
|
|
1251
|
+
} catch (ignoreError) {
|
|
1252
|
+
return { requestable: false, needResolve: false }
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
return { requestable: true, needResolve: false }
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// `file:` protocol
|
|
1259
|
+
if (/^file:/i.test(url)) {
|
|
1260
|
+
return { requestable: true, needResolve: true }
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// Absolute URLs
|
|
1264
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !NATIVE_WIN32_PATH.test(url)) {
|
|
1265
|
+
if (options.isSupportAbsoluteURL && /^https?:/i.test(url)) {
|
|
1266
|
+
return { requestable: true, needResolve: false }
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
return { requestable: false, needResolve: false }
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return { requestable: true, needResolve: true }
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
function sort (a, b) {
|
|
1276
|
+
return a.index - b.index
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
function combineRequests (preRequest, url) {
|
|
1280
|
+
const idx = url.indexOf('!=!')
|
|
1281
|
+
|
|
1282
|
+
return idx !== -1
|
|
1283
|
+
? url.slice(0, idx + 3) + preRequest + url.slice(idx + 3)
|
|
1284
|
+
: preRequest + url
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
module.exports = {
|
|
1288
|
+
normalizeOptions,
|
|
1289
|
+
shouldUseModulesPlugins,
|
|
1290
|
+
shouldUseImportPlugin,
|
|
1291
|
+
shouldUseURLPlugin,
|
|
1292
|
+
shouldUseIcssPlugin,
|
|
1293
|
+
normalizeUrl,
|
|
1294
|
+
requestify,
|
|
1295
|
+
getFilter,
|
|
1296
|
+
getModulesOptions,
|
|
1297
|
+
getModulesPlugins,
|
|
1298
|
+
normalizeSourceMap,
|
|
1299
|
+
getPreRequester,
|
|
1300
|
+
getImportCode,
|
|
1301
|
+
getModuleCode,
|
|
1302
|
+
getExportCode,
|
|
1303
|
+
resolveRequests,
|
|
1304
|
+
isURLRequestable,
|
|
1305
|
+
sort,
|
|
1306
|
+
WEBPACK_IGNORE_COMMENT_REGEXP,
|
|
1307
|
+
combineRequests,
|
|
1308
|
+
camelCase,
|
|
1309
|
+
stringifyRequest,
|
|
1310
|
+
isDataUrl,
|
|
1311
|
+
defaultGetLocalIdent
|
|
1312
|
+
}
|