@mpxjs/webpack-plugin 2.8.1 → 2.8.7
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/platform/template/wx/component-config/map.js +1 -1
- package/lib/resolver/FixDescriptionInfoPlugin.js +1 -0
- package/lib/runtime/animation.js +60 -0
- package/lib/runtime/optionProcessor.js +9 -107
- 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,124 @@
|
|
|
1
|
+
const { extractICSS, replaceValueSymbols, replaceSymbols } = require('icss-utils')
|
|
2
|
+
|
|
3
|
+
const { normalizeUrl, resolveRequests, requestify } = require('../utils')
|
|
4
|
+
|
|
5
|
+
const plugin = (options = {}) => {
|
|
6
|
+
return {
|
|
7
|
+
postcssPlugin: 'postcss-icss-parser',
|
|
8
|
+
async OnceExit (root) {
|
|
9
|
+
const importReplacements = Object.create(null)
|
|
10
|
+
const { icssImports, icssExports } = extractICSS(root)
|
|
11
|
+
const imports = new Map()
|
|
12
|
+
const tasks = []
|
|
13
|
+
|
|
14
|
+
const { loaderContext } = options
|
|
15
|
+
const resolver = loaderContext.getResolve({
|
|
16
|
+
dependencyType: 'icss',
|
|
17
|
+
conditionNames: ['style'],
|
|
18
|
+
extensions: ['...'],
|
|
19
|
+
mainFields: ['css', 'style', 'main', '...'],
|
|
20
|
+
mainFiles: ['index', '...'],
|
|
21
|
+
preferRelative: true
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// eslint-disable-next-line guard-for-in
|
|
25
|
+
for (const url in icssImports) {
|
|
26
|
+
const tokens = icssImports[url]
|
|
27
|
+
|
|
28
|
+
if (Object.keys(tokens).length === 0) {
|
|
29
|
+
// eslint-disable-next-line no-continue
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let normalizedUrl = url
|
|
34
|
+
let prefix = ''
|
|
35
|
+
|
|
36
|
+
const queryParts = normalizedUrl.split('!')
|
|
37
|
+
|
|
38
|
+
if (queryParts.length > 1) {
|
|
39
|
+
normalizedUrl = queryParts.pop()
|
|
40
|
+
prefix = queryParts.join('!')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const request = requestify(
|
|
44
|
+
normalizeUrl(normalizedUrl, true),
|
|
45
|
+
loaderContext.rootContext
|
|
46
|
+
)
|
|
47
|
+
const doResolve = async () => {
|
|
48
|
+
const resolvedUrl = await resolveRequests(
|
|
49
|
+
resolver,
|
|
50
|
+
loaderContext.context,
|
|
51
|
+
[...new Set([normalizedUrl, request])]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if (!resolvedUrl) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line consistent-return
|
|
59
|
+
return { url: resolvedUrl, prefix, tokens }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
tasks.push(doResolve())
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const results = await Promise.all(tasks)
|
|
66
|
+
|
|
67
|
+
for (let index = 0; index <= results.length - 1; index++) {
|
|
68
|
+
const item = results[index]
|
|
69
|
+
|
|
70
|
+
if (!item) {
|
|
71
|
+
// eslint-disable-next-line no-continue
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const newUrl = item.prefix ? `${item.prefix}!${item.url}` : item.url
|
|
76
|
+
const importKey = newUrl
|
|
77
|
+
let importName = imports.get(importKey)
|
|
78
|
+
|
|
79
|
+
if (!importName) {
|
|
80
|
+
importName = `___CSS_LOADER_ICSS_IMPORT_${imports.size}___`
|
|
81
|
+
imports.set(importKey, importName)
|
|
82
|
+
|
|
83
|
+
options.imports.push({
|
|
84
|
+
type: 'icss_import',
|
|
85
|
+
importName,
|
|
86
|
+
url: options.urlHandler(newUrl),
|
|
87
|
+
icss: true,
|
|
88
|
+
index
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
options.api.push({ importName, dedupe: true, index })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const [replacementIndex, token] of Object.keys(
|
|
95
|
+
item.tokens
|
|
96
|
+
).entries()) {
|
|
97
|
+
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${index}_REPLACEMENT_${replacementIndex}___`
|
|
98
|
+
const localName = item.tokens[token]
|
|
99
|
+
|
|
100
|
+
importReplacements[token] = replacementName
|
|
101
|
+
|
|
102
|
+
options.replacements.push({ replacementName, importName, localName })
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (Object.keys(importReplacements).length > 0) {
|
|
107
|
+
replaceSymbols(root, importReplacements)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const name of Object.keys(icssExports)) {
|
|
111
|
+
const value = replaceValueSymbols(
|
|
112
|
+
icssExports[name],
|
|
113
|
+
importReplacements
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
options.exports.push({ name, value })
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
plugin.postcss = true
|
|
123
|
+
|
|
124
|
+
module.exports = plugin
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
const valueParser = require('postcss-value-parser')
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
normalizeUrl,
|
|
5
|
+
resolveRequests,
|
|
6
|
+
isURLRequestable,
|
|
7
|
+
requestify,
|
|
8
|
+
WEBPACK_IGNORE_COMMENT_REGEXP
|
|
9
|
+
} = require('../utils')
|
|
10
|
+
|
|
11
|
+
const MPX_IMPORT_REGEXP = /^(@mpx-import\s+)/ // 例如匹配: ' @mpx-import "xxx"'
|
|
12
|
+
|
|
13
|
+
function parseNode (atRule, key, options) {
|
|
14
|
+
// Convert only top-level @import
|
|
15
|
+
|
|
16
|
+
if (atRule.parent.type !== 'root') {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (
|
|
21
|
+
atRule.raws &&
|
|
22
|
+
atRule.raws.afterName &&
|
|
23
|
+
atRule.raws.afterName.trim().length > 0
|
|
24
|
+
) {
|
|
25
|
+
const lastCommentIndex = atRule.raws.afterName.lastIndexOf('/*')
|
|
26
|
+
|
|
27
|
+
const matched = atRule.raws.afterName
|
|
28
|
+
.slice(lastCommentIndex)
|
|
29
|
+
.match(WEBPACK_IGNORE_COMMENT_REGEXP)
|
|
30
|
+
|
|
31
|
+
if (matched && matched[2] === 'true') {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const prevNode = atRule.prev()
|
|
37
|
+
|
|
38
|
+
if (prevNode && prevNode.type === 'comment') {
|
|
39
|
+
const matched = prevNode.text.match(WEBPACK_IGNORE_COMMENT_REGEXP)
|
|
40
|
+
|
|
41
|
+
if (matched && matched[2] === 'true') {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Nodes do not exists - `@import url('http://') :root {}`
|
|
47
|
+
if (atRule.nodes) {
|
|
48
|
+
const error = new Error(
|
|
49
|
+
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
error.node = atRule
|
|
53
|
+
|
|
54
|
+
throw error
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const rawParams =
|
|
58
|
+
atRule.raws &&
|
|
59
|
+
atRule.raws[key] &&
|
|
60
|
+
typeof atRule.raws[key].raw !== 'undefined'
|
|
61
|
+
? atRule.raws[key].raw
|
|
62
|
+
: atRule[key]
|
|
63
|
+
const { nodes: paramsNodes } = valueParser(rawParams)
|
|
64
|
+
|
|
65
|
+
// No nodes - `@import ;`
|
|
66
|
+
// Invalid type - `@import foo-bar;`
|
|
67
|
+
if (
|
|
68
|
+
paramsNodes.length === 0 ||
|
|
69
|
+
(paramsNodes[0].type !== 'string' && paramsNodes[0].type !== 'function')
|
|
70
|
+
) {
|
|
71
|
+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`)
|
|
72
|
+
|
|
73
|
+
error.node = atRule
|
|
74
|
+
|
|
75
|
+
throw error
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let isStringValue
|
|
79
|
+
let url
|
|
80
|
+
|
|
81
|
+
if (paramsNodes[0].type === 'string') {
|
|
82
|
+
isStringValue = true
|
|
83
|
+
url = paramsNodes[0].value
|
|
84
|
+
} else {
|
|
85
|
+
// Invalid function - `@import nourl(test.css);`
|
|
86
|
+
if (paramsNodes[0].value.toLowerCase() !== 'url') {
|
|
87
|
+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`)
|
|
88
|
+
|
|
89
|
+
error.node = atRule
|
|
90
|
+
|
|
91
|
+
throw error
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
isStringValue =
|
|
95
|
+
paramsNodes[0].nodes.length !== 0 &&
|
|
96
|
+
paramsNodes[0].nodes[0].type === 'string'
|
|
97
|
+
url = isStringValue
|
|
98
|
+
? paramsNodes[0].nodes[0].value
|
|
99
|
+
: valueParser.stringify(paramsNodes[0].nodes)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
url = normalizeUrl(url, isStringValue)
|
|
103
|
+
|
|
104
|
+
const { requestable, needResolve } = isURLRequestable(url, options)
|
|
105
|
+
|
|
106
|
+
let prefix
|
|
107
|
+
|
|
108
|
+
if (requestable && needResolve) {
|
|
109
|
+
const queryParts = url.split('!')
|
|
110
|
+
|
|
111
|
+
if (queryParts.length > 1) {
|
|
112
|
+
url = queryParts.pop()
|
|
113
|
+
prefix = queryParts.join('!')
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Empty url - `@import "";` or `@import url();`
|
|
118
|
+
if (url.trim().length === 0) {
|
|
119
|
+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`)
|
|
120
|
+
|
|
121
|
+
error.node = atRule
|
|
122
|
+
|
|
123
|
+
throw error
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const additionalNodes = paramsNodes.slice(1)
|
|
127
|
+
|
|
128
|
+
let supports
|
|
129
|
+
let layer
|
|
130
|
+
let media
|
|
131
|
+
|
|
132
|
+
if (additionalNodes.length > 0) {
|
|
133
|
+
let nodes = []
|
|
134
|
+
|
|
135
|
+
for (const node of additionalNodes) {
|
|
136
|
+
nodes.push(node)
|
|
137
|
+
|
|
138
|
+
const isLayerFunction =
|
|
139
|
+
node.type === 'function' && node.value.toLowerCase() === 'layer'
|
|
140
|
+
const isLayerWord =
|
|
141
|
+
node.type === 'word' && node.value.toLowerCase() === 'layer'
|
|
142
|
+
|
|
143
|
+
if (isLayerFunction || isLayerWord) {
|
|
144
|
+
if (isLayerFunction) {
|
|
145
|
+
nodes.splice(nodes.length - 1, 1, ...node.nodes)
|
|
146
|
+
} else {
|
|
147
|
+
nodes.splice(nodes.length - 1, 1, {
|
|
148
|
+
type: 'string',
|
|
149
|
+
value: '',
|
|
150
|
+
unclosed: false
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
layer = valueParser.stringify(nodes).trim().toLowerCase()
|
|
155
|
+
nodes = []
|
|
156
|
+
} else if (
|
|
157
|
+
node.type === 'function' &&
|
|
158
|
+
node.value.toLowerCase() === 'supports'
|
|
159
|
+
) {
|
|
160
|
+
nodes.splice(nodes.length - 1, 1, ...node.nodes)
|
|
161
|
+
|
|
162
|
+
supports = valueParser.stringify(nodes).trim().toLowerCase()
|
|
163
|
+
nodes = []
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (nodes.length > 0) {
|
|
168
|
+
media = valueParser.stringify(nodes).trim().toLowerCase()
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// eslint-disable-next-line consistent-return
|
|
173
|
+
return {
|
|
174
|
+
atRule,
|
|
175
|
+
prefix,
|
|
176
|
+
url,
|
|
177
|
+
layer,
|
|
178
|
+
supports,
|
|
179
|
+
media,
|
|
180
|
+
requestable,
|
|
181
|
+
needResolve
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const plugin = (options = {}) => {
|
|
186
|
+
return {
|
|
187
|
+
postcssPlugin: 'postcss-import-parser',
|
|
188
|
+
prepare (result) {
|
|
189
|
+
const parsedAtRules = []
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
Once (root, { AtRule }) {
|
|
193
|
+
// Calls once per file, since every file has single Root
|
|
194
|
+
// 遍历AST 找到注释节点(/* @mpx-import "xxx" */)进行@import 替换
|
|
195
|
+
root.walkComments((comment) => {
|
|
196
|
+
if (MPX_IMPORT_REGEXP.test(comment.text)) {
|
|
197
|
+
const importStatement = comment.text.replace(MPX_IMPORT_REGEXP, (matchStr, $1) => {
|
|
198
|
+
return matchStr.replace($1, '')
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
const matched = importStatement.match(/(["'].+["'])/)
|
|
202
|
+
|
|
203
|
+
if (matched && matched[1]) {
|
|
204
|
+
const url = matched[1]
|
|
205
|
+
const importNode = new AtRule({ name: 'import', params: url, source: comment.source })
|
|
206
|
+
comment.before(importNode)
|
|
207
|
+
comment.remove()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
},
|
|
212
|
+
AtRule: {
|
|
213
|
+
import (atRule) {
|
|
214
|
+
if (options.isCSSStyleSheet) {
|
|
215
|
+
options.loaderContext.emitError(
|
|
216
|
+
new Error(
|
|
217
|
+
atRule.error(
|
|
218
|
+
"'@import' rules are not allowed here and will not be processed"
|
|
219
|
+
).message
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const { isSupportDataURL, isSupportAbsoluteURL } = options
|
|
227
|
+
|
|
228
|
+
let parsedAtRule
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
parsedAtRule = parseNode(atRule, 'params', {
|
|
232
|
+
isSupportAbsoluteURL,
|
|
233
|
+
isSupportDataURL,
|
|
234
|
+
externals: options.externals
|
|
235
|
+
})
|
|
236
|
+
} catch (error) {
|
|
237
|
+
result.warn(error.message, { node: error.node })
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!parsedAtRule) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
parsedAtRules.push(parsedAtRule)
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
async OnceExit () {
|
|
248
|
+
if (parsedAtRules.length === 0) {
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const { loaderContext } = options
|
|
253
|
+
const resolver = loaderContext.getResolve({
|
|
254
|
+
dependencyType: 'css',
|
|
255
|
+
conditionNames: ['style'],
|
|
256
|
+
mainFields: ['css', 'style', 'main', '...'],
|
|
257
|
+
mainFiles: ['index', '...'],
|
|
258
|
+
extensions: ['.css', '...'],
|
|
259
|
+
preferRelative: true
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const resolvedAtRules = await Promise.all(
|
|
263
|
+
parsedAtRules.map(async (parsedAtRule) => {
|
|
264
|
+
const {
|
|
265
|
+
atRule,
|
|
266
|
+
requestable,
|
|
267
|
+
needResolve,
|
|
268
|
+
prefix,
|
|
269
|
+
url,
|
|
270
|
+
layer,
|
|
271
|
+
supports,
|
|
272
|
+
media
|
|
273
|
+
} = parsedAtRule
|
|
274
|
+
|
|
275
|
+
if (options.filter) {
|
|
276
|
+
const needKeep = await options.filter(
|
|
277
|
+
url,
|
|
278
|
+
media,
|
|
279
|
+
loaderContext.resourcePath,
|
|
280
|
+
supports,
|
|
281
|
+
layer
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
if (!needKeep) {
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (needResolve) {
|
|
290
|
+
const request = requestify(url, loaderContext.rootContext)
|
|
291
|
+
const resolvedUrl = await resolveRequests(
|
|
292
|
+
resolver,
|
|
293
|
+
loaderContext.context,
|
|
294
|
+
[...new Set([request, url])]
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if (!resolvedUrl) {
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (resolvedUrl === loaderContext.resourcePath) {
|
|
302
|
+
atRule.remove()
|
|
303
|
+
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
atRule.remove()
|
|
308
|
+
|
|
309
|
+
// eslint-disable-next-line consistent-return
|
|
310
|
+
return {
|
|
311
|
+
url: resolvedUrl,
|
|
312
|
+
layer,
|
|
313
|
+
supports,
|
|
314
|
+
media,
|
|
315
|
+
prefix,
|
|
316
|
+
requestable
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
atRule.remove()
|
|
321
|
+
|
|
322
|
+
// eslint-disable-next-line consistent-return
|
|
323
|
+
return { url, layer, supports, media, prefix, requestable }
|
|
324
|
+
})
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
const urlToNameMap = new Map()
|
|
328
|
+
|
|
329
|
+
for (let index = 0; index <= resolvedAtRules.length - 1; index++) {
|
|
330
|
+
const resolvedAtRule = resolvedAtRules[index]
|
|
331
|
+
|
|
332
|
+
if (!resolvedAtRule) {
|
|
333
|
+
// eslint-disable-next-line no-continue
|
|
334
|
+
continue
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const { url, requestable, layer, supports, media } = resolvedAtRule
|
|
338
|
+
|
|
339
|
+
if (!requestable) {
|
|
340
|
+
options.api.push({ url, layer, supports, media, index })
|
|
341
|
+
|
|
342
|
+
// eslint-disable-next-line no-continue
|
|
343
|
+
continue
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const { prefix } = resolvedAtRule
|
|
347
|
+
const newUrl = prefix ? `${prefix}!${url}` : url
|
|
348
|
+
let importName = urlToNameMap.get(newUrl)
|
|
349
|
+
|
|
350
|
+
if (!importName) {
|
|
351
|
+
importName = `___CSS_LOADER_AT_RULE_IMPORT_${urlToNameMap.size}___`
|
|
352
|
+
urlToNameMap.set(newUrl, importName)
|
|
353
|
+
|
|
354
|
+
options.imports.push({
|
|
355
|
+
type: 'rule_import',
|
|
356
|
+
importName,
|
|
357
|
+
url: options.urlHandler(newUrl),
|
|
358
|
+
index
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
options.api.push({ importName, layer, supports, media, index })
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
plugin.postcss = true
|
|
371
|
+
|
|
372
|
+
module.exports = plugin
|