@dcloudio/uni-cli-shared 3.0.0-alpha-5010320260611001 → 3.0.0-alpha-5010420260626001
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/dist/dom2/index.d.ts +1 -0
- package/dist/dom2/index.js +1 -0
- package/dist/dom2/rootScrollView.d.ts +47 -0
- package/dist/dom2/rootScrollView.js +283 -0
- package/dist/messages/en.d.ts +1 -0
- package/dist/messages/en.js +1 -0
- package/dist/messages/index.d.ts +2 -0
- package/dist/messages/zh_CN.d.ts +1 -0
- package/dist/messages/zh_CN.js +1 -0
- package/dist/postcss/plugins/stylePluginExternal.d.ts +9 -10
- package/dist/postcss/plugins/stylePluginExternal.js +51 -45
- package/dist/uni_modules.cloud.d.ts +1 -0
- package/dist/uni_modules.cloud.js +23 -1
- package/dist/vite/plugins/pre.js +2 -0
- package/dist/vite/plugins/stats.d.ts +5 -1
- package/dist/vite/plugins/stats.js +45 -2
- package/dist/vue/transforms/index.d.ts +1 -0
- package/dist/vue/transforms/index.js +1 -0
- package/dist/vue/transforms/transformTeleport.d.ts +2 -0
- package/dist/vue/transforms/transformTeleport.js +63 -0
- package/lib/dom2/app/@vue/compiler-vapor-dom2/dist/compiler-vapor-dom2.cjs.js +1 -1
- package/package.json +5 -5
package/dist/dom2/index.d.ts
CHANGED
package/dist/dom2/index.js
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface VueCodePosition {
|
|
2
|
+
line: number;
|
|
3
|
+
column: number;
|
|
4
|
+
}
|
|
5
|
+
export interface VueCodeEditRange {
|
|
6
|
+
start: VueCodePosition;
|
|
7
|
+
end: VueCodePosition;
|
|
8
|
+
/**
|
|
9
|
+
* 调用方替换时建议只移除非换行字符,用于尽量保持错误定位和调试行号不变。
|
|
10
|
+
*/
|
|
11
|
+
preserveLineBreaks: true;
|
|
12
|
+
/**
|
|
13
|
+
* 开始范围包含首个子节点前的缩进,调用方需要保留这段缩进,避免改变子节点格式。
|
|
14
|
+
*/
|
|
15
|
+
preserveEndIndent?: true;
|
|
16
|
+
}
|
|
17
|
+
export type VueCodeEditRangesResult = Record<string, VueCodeEditRange[]>;
|
|
18
|
+
/**
|
|
19
|
+
* 批量定位由 `#ifdef APP` 包裹的根 scroll-view 需要移除的范围。
|
|
20
|
+
* 只返回需要修改的行列号,不修改文件,也不返回修改后的文件内容。
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveAppRootScrollViewEditRanges(vueFiles: string[], inputDir: string): VueCodeEditRangesResult;
|
|
23
|
+
/**
|
|
24
|
+
* 蒸汽模式下,页面根节点会自动补一个 scroll-view。
|
|
25
|
+
* 这里仅用正则做精确匹配:命中范围宁可保守,也不能误报。
|
|
26
|
+
*/
|
|
27
|
+
export declare function hasAppRootScrollViewWrappedByIfdef(code: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* 仅在 dom2 页面整文件预处理时定位需要提示优化建议的根 scroll-view 节点。
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveDom2RootScrollViewWarnLocation(code: string, filename: string, isVueSubRequest: boolean): {
|
|
32
|
+
loc: import("@vue/compiler-core").SourceLocation | {
|
|
33
|
+
start: {
|
|
34
|
+
line: number;
|
|
35
|
+
column: number;
|
|
36
|
+
offset: number;
|
|
37
|
+
};
|
|
38
|
+
end: {
|
|
39
|
+
line: number;
|
|
40
|
+
column: number;
|
|
41
|
+
offset: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
source: string;
|
|
45
|
+
} | undefined;
|
|
46
|
+
export declare function warnDom2RootScrollView(code: string, filename: string, isVueSubRequest: boolean): void;
|
|
47
|
+
export declare function resolveAppRootScrollViewEditRangesByCode(code: string, filename: string): VueCodeEditRange[];
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveAppRootScrollViewEditRangesByCode = exports.warnDom2RootScrollView = exports.resolveDom2RootScrollViewWarnLocation = exports.hasAppRootScrollViewWrappedByIfdef = exports.resolveAppRootScrollViewEditRanges = void 0;
|
|
4
|
+
const fs_extra_1 = require("fs-extra");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const compiler_sfc_1 = require("@vue/compiler-sfc");
|
|
7
|
+
const json_1 = require("../json");
|
|
8
|
+
const logs_1 = require("../logs");
|
|
9
|
+
const messages_1 = require("../messages");
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const utils_2 = require("../vite/plugins/vitejs/utils");
|
|
12
|
+
const { preprocess: preprocessHtml } = require('../../lib/preprocess');
|
|
13
|
+
const TEMPLATE_BLOCK_RE = /<template\b[^>]*>([\s\S]*?)<\/template>/i;
|
|
14
|
+
const ROOT_SCROLL_VIEW_ATTR_RE = /^\s+style\s*=\s*(["'])\s*flex\s*:\s*1\s*;?\s*\1\s*$/;
|
|
15
|
+
const APP_ROOT_SCROLL_VIEW_RE = /^\s*<!--\s*#ifdef APP\s*-->\s*<scroll-view([^>]*)>[\s\S]*<\/scroll-view>\s*<!--\s*#endif\s*-->\s*$/;
|
|
16
|
+
const SPLIT_APP_ROOT_SCROLL_VIEW_RE = /^\s*<!--\s*#ifdef APP\s*-->\s*<scroll-view([^>]*)>\s*<!--\s*#endif\s*-->[\s\S]*<!--\s*#ifdef APP\s*-->\s*<\/scroll-view>\s*<!--\s*#endif\s*-->\s*$/;
|
|
17
|
+
/**
|
|
18
|
+
* 批量定位由 `#ifdef APP` 包裹的根 scroll-view 需要移除的范围。
|
|
19
|
+
* 只返回需要修改的行列号,不修改文件,也不返回修改后的文件内容。
|
|
20
|
+
*/
|
|
21
|
+
function resolveAppRootScrollViewEditRanges(vueFiles, inputDir) {
|
|
22
|
+
const result = {};
|
|
23
|
+
vueFiles.forEach((file) => {
|
|
24
|
+
const filename = resolveVueFilename(inputDir, file);
|
|
25
|
+
if (!(0, fs_extra_1.existsSync)(filename)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const content = (0, fs_extra_1.readFileSync)(filename, 'utf8');
|
|
29
|
+
const ranges = resolveAppRootScrollViewEditRangesByCode(content, filename);
|
|
30
|
+
if (ranges.length) {
|
|
31
|
+
result[file] = ranges;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
exports.resolveAppRootScrollViewEditRanges = resolveAppRootScrollViewEditRanges;
|
|
37
|
+
/**
|
|
38
|
+
* 蒸汽模式下,页面根节点会自动补一个 scroll-view。
|
|
39
|
+
* 这里仅用正则做精确匹配:命中范围宁可保守,也不能误报。
|
|
40
|
+
*/
|
|
41
|
+
function hasAppRootScrollViewWrappedByIfdef(code) {
|
|
42
|
+
const templateContent = getTemplateContent(code);
|
|
43
|
+
if (!templateContent) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return (matchesAppRootScrollViewTemplate(templateContent, APP_ROOT_SCROLL_VIEW_RE) ||
|
|
47
|
+
matchesAppRootScrollViewTemplate(templateContent, SPLIT_APP_ROOT_SCROLL_VIEW_RE));
|
|
48
|
+
}
|
|
49
|
+
exports.hasAppRootScrollViewWrappedByIfdef = hasAppRootScrollViewWrappedByIfdef;
|
|
50
|
+
/**
|
|
51
|
+
* 仅在 dom2 页面整文件预处理时定位需要提示优化建议的根 scroll-view 节点。
|
|
52
|
+
*/
|
|
53
|
+
function resolveDom2RootScrollViewWarnLocation(code, filename, isVueSubRequest) {
|
|
54
|
+
if (process.env.UNI_PLATFORM !== 'app' ||
|
|
55
|
+
process.env.UNI_APP_X_DOM2 !== 'true' ||
|
|
56
|
+
isVueSubRequest ||
|
|
57
|
+
!(0, json_1.parseUniXPageOptions)(filename) ||
|
|
58
|
+
!code.includes('scroll-view') ||
|
|
59
|
+
!code.includes('#ifdef APP')) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!hasAppRootScrollViewWrappedByIfdef(code)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
return resolveAppRootScrollViewNodeLocByCode(code, filename);
|
|
66
|
+
}
|
|
67
|
+
exports.resolveDom2RootScrollViewWarnLocation = resolveDom2RootScrollViewWarnLocation;
|
|
68
|
+
function warnDom2RootScrollView(code, filename, isVueSubRequest) {
|
|
69
|
+
const location = resolveDom2RootScrollViewWarnLocation(code, filename, isVueSubRequest);
|
|
70
|
+
if (!location) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
(0, logs_1.onCompileLog)('warn', {
|
|
74
|
+
message: messages_1.M['dom2.root.scroll.view'],
|
|
75
|
+
name: 'Warn',
|
|
76
|
+
loc: location.loc,
|
|
77
|
+
}, createWarnCodeFrameSource(location), (0, utils_1.normalizePath)((0, path_1.relative)(process.env.UNI_INPUT_DIR, filename)));
|
|
78
|
+
}
|
|
79
|
+
exports.warnDom2RootScrollView = warnDom2RootScrollView;
|
|
80
|
+
function resolveVueFilename(inputDir, file) {
|
|
81
|
+
if ((0, path_1.isAbsolute)(file)) {
|
|
82
|
+
const root = (0, path_1.parse)(file).root;
|
|
83
|
+
// HBuilderX/uni-app 里页面路径可能写成 `/pages/a/b.uvue`,
|
|
84
|
+
// 这种是项目内绝对路径,不是磁盘绝对路径,需要仍然基于 inputDir 解析。
|
|
85
|
+
if (root === '/' || root === '\\') {
|
|
86
|
+
return (0, path_1.resolve)(inputDir, removeLeadingRootSlash(file));
|
|
87
|
+
}
|
|
88
|
+
return file;
|
|
89
|
+
}
|
|
90
|
+
return (0, path_1.resolve)(inputDir, file);
|
|
91
|
+
}
|
|
92
|
+
function removeLeadingRootSlash(file) {
|
|
93
|
+
let index = 0;
|
|
94
|
+
while (file.charAt(index) === '/' || file.charAt(index) === '\\') {
|
|
95
|
+
index++;
|
|
96
|
+
}
|
|
97
|
+
return file.slice(index);
|
|
98
|
+
}
|
|
99
|
+
function getTemplateContent(code) {
|
|
100
|
+
return code.match(TEMPLATE_BLOCK_RE)?.[1];
|
|
101
|
+
}
|
|
102
|
+
function matchesAppRootScrollViewTemplate(template, regex) {
|
|
103
|
+
const match = template.match(regex);
|
|
104
|
+
return !!match && ROOT_SCROLL_VIEW_ATTR_RE.test(match[1]);
|
|
105
|
+
}
|
|
106
|
+
function resolveAppRootScrollViewNodeLocByCode(code, filename) {
|
|
107
|
+
const template = parseSfcTemplate(code, filename);
|
|
108
|
+
if (!template) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const children = template.ast.children;
|
|
112
|
+
if (children.length !== 3) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const [, scrollViewNode] = children;
|
|
116
|
+
if (!isRootScrollView(scrollViewNode)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
loc: createStartTagLoc(code, scrollViewNode),
|
|
121
|
+
source: resolveStartTagSource(scrollViewNode),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function createStartTagLoc(code, node) {
|
|
125
|
+
const source = node.loc.source || '';
|
|
126
|
+
const endOffsetInSource = source.indexOf('>');
|
|
127
|
+
if (endOffsetInSource === -1) {
|
|
128
|
+
return {
|
|
129
|
+
start: node.loc.start,
|
|
130
|
+
end: node.loc.end,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return (0, utils_2.offsetToStartAndEnd)(code, node.loc.start.offset, node.loc.start.offset + endOffsetInSource + 1);
|
|
134
|
+
}
|
|
135
|
+
function resolveStartTagSource(node) {
|
|
136
|
+
const source = node.loc.source || '';
|
|
137
|
+
const endOffsetInSource = source.indexOf('>');
|
|
138
|
+
if (endOffsetInSource === -1) {
|
|
139
|
+
return source;
|
|
140
|
+
}
|
|
141
|
+
return source.slice(0, endOffsetInSource + 1);
|
|
142
|
+
}
|
|
143
|
+
function createWarnCodeFrameSource(location) {
|
|
144
|
+
return `${'\n'.repeat(Math.max(location.loc.start.line - 1, 0))}${location.source}`;
|
|
145
|
+
}
|
|
146
|
+
function resolveAppRootScrollViewEditRangesByCode(code, filename) {
|
|
147
|
+
const template = parseSfcTemplate(code, filename);
|
|
148
|
+
if (!template) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
const children = template.ast.children;
|
|
152
|
+
if (children.length !== 3) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
const [ifdefNode, scrollViewNode, endifNode] = children;
|
|
156
|
+
if (!isAppIfdefComment(ifdefNode) ||
|
|
157
|
+
!isRootScrollView(scrollViewNode) ||
|
|
158
|
+
!isEndifComment(endifNode)) {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
// 使用项目既有的条件编译实现先跑一遍,再交给 Vue 编译器确认 APP 分支根节点。
|
|
162
|
+
if (!isPreprocessedRootScrollView(template.content, filename)) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
return createRootScrollViewEditRanges(ifdefNode, scrollViewNode, endifNode);
|
|
166
|
+
}
|
|
167
|
+
exports.resolveAppRootScrollViewEditRangesByCode = resolveAppRootScrollViewEditRangesByCode;
|
|
168
|
+
function parseSfcTemplate(code, filename) {
|
|
169
|
+
const { descriptor, errors } = (0, compiler_sfc_1.parse)(code, {
|
|
170
|
+
filename,
|
|
171
|
+
sourceMap: false,
|
|
172
|
+
});
|
|
173
|
+
if (errors.length || !descriptor.template?.ast) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
content: descriptor.template.content,
|
|
178
|
+
ast: descriptor.template.ast,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function isPreprocessedRootScrollView(content, filename) {
|
|
182
|
+
try {
|
|
183
|
+
const preprocessed = preprocessHtml(content, createAppPreContext(), {
|
|
184
|
+
type: 'html',
|
|
185
|
+
});
|
|
186
|
+
const template = parseSfcTemplate(`<template>${preprocessed}</template>`, filename);
|
|
187
|
+
const root = template?.ast.children[0];
|
|
188
|
+
return (!!root && template.ast.children.length === 1 && root.tag === 'scroll-view');
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function createAppPreContext() {
|
|
195
|
+
// 这里只声明本函数需要的 APP/UVue 上下文,避免改动全局条件编译上下文。
|
|
196
|
+
return {
|
|
197
|
+
APP: true,
|
|
198
|
+
APP_UVUE: true,
|
|
199
|
+
UNI_APP_X: true,
|
|
200
|
+
VUE3: true,
|
|
201
|
+
VUE3_VAPOR: true,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function isAppIfdefComment(node) {
|
|
205
|
+
return (node.type === 3 /* NodeTypes.COMMENT */ && node.content?.trim() === '#ifdef APP');
|
|
206
|
+
}
|
|
207
|
+
function isEndifComment(node) {
|
|
208
|
+
return node.type === 3 /* NodeTypes.COMMENT */ && node.content?.trim() === '#endif';
|
|
209
|
+
}
|
|
210
|
+
function isRootScrollView(node) {
|
|
211
|
+
return (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
212
|
+
node.tag === 'scroll-view' &&
|
|
213
|
+
hasOnlyFlexStyle(node));
|
|
214
|
+
}
|
|
215
|
+
function hasOnlyFlexStyle(node) {
|
|
216
|
+
if (!node.props || node.props.length !== 1) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
const style = node.props[0];
|
|
220
|
+
return (style.type === 6 /* NodeTypes.ATTRIBUTE */ &&
|
|
221
|
+
style.name === 'style' &&
|
|
222
|
+
!!style.value &&
|
|
223
|
+
normalizeFlexStyle(style.value.content) === 'flex:1');
|
|
224
|
+
}
|
|
225
|
+
function normalizeFlexStyle(style) {
|
|
226
|
+
let normalized = '';
|
|
227
|
+
for (let i = 0; i < style.length; i++) {
|
|
228
|
+
const char = style.charAt(i);
|
|
229
|
+
if (char !== ' ' && char !== '\t' && char !== '\n' && char !== '\r') {
|
|
230
|
+
normalized += char;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (normalized.endsWith(';')) {
|
|
234
|
+
return normalized.slice(0, -1);
|
|
235
|
+
}
|
|
236
|
+
return normalized;
|
|
237
|
+
}
|
|
238
|
+
function createRootScrollViewEditRanges(ifdefNode, scrollViewNode, endifNode) {
|
|
239
|
+
const children = scrollViewNode.children || [];
|
|
240
|
+
if (!children.length) {
|
|
241
|
+
return [createEditRange(ifdefNode, endifNode)];
|
|
242
|
+
}
|
|
243
|
+
const firstChild = children[0];
|
|
244
|
+
const lastChild = children[children.length - 1];
|
|
245
|
+
// 兼容如下写法:条件编译分别包裹 scroll-view 的开始标签和结束标签。
|
|
246
|
+
// <!-- #ifdef APP -->
|
|
247
|
+
// <scroll-view style="flex:1">
|
|
248
|
+
// <!-- #endif -->
|
|
249
|
+
// ...
|
|
250
|
+
// <!-- #ifdef APP -->
|
|
251
|
+
// </scroll-view>
|
|
252
|
+
// <!-- #endif -->
|
|
253
|
+
if (isEndifComment(firstChild) && isAppIfdefComment(lastChild)) {
|
|
254
|
+
return [
|
|
255
|
+
createEditRangeByLoc(ifdefNode.loc.start, firstChild.loc.end),
|
|
256
|
+
createEditRangeByLoc(lastChild.loc.start, endifNode.loc.end),
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
return [
|
|
260
|
+
createEditRangeByLoc(ifdefNode.loc.start, firstChild.loc.start, true),
|
|
261
|
+
createEditRangeByLoc(lastChild.loc.end, endifNode.loc.end),
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
function createEditRange(startNode, endNode) {
|
|
265
|
+
return createEditRangeByLoc(startNode.loc.start, endNode.loc.end);
|
|
266
|
+
}
|
|
267
|
+
function createEditRangeByLoc(start, end, preserveEndIndent = false) {
|
|
268
|
+
const range = {
|
|
269
|
+
start: toPosition(start),
|
|
270
|
+
end: toPosition(end),
|
|
271
|
+
preserveLineBreaks: true,
|
|
272
|
+
};
|
|
273
|
+
if (preserveEndIndent) {
|
|
274
|
+
range.preserveEndIndent = true;
|
|
275
|
+
}
|
|
276
|
+
return range;
|
|
277
|
+
}
|
|
278
|
+
function toPosition(loc) {
|
|
279
|
+
return {
|
|
280
|
+
line: loc.line,
|
|
281
|
+
column: loc.column,
|
|
282
|
+
};
|
|
283
|
+
}
|
package/dist/messages/en.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ declare const _default: {
|
|
|
25
25
|
readonly 'i18n.fallbackLocale.missing': "./local/{locale}.json is missing";
|
|
26
26
|
readonly 'easycom.conflict': "easycom component conflict: ";
|
|
27
27
|
readonly 'dom2.compatible.component': "Vapor mode does not support the uni-app compatibility component {name}. The implementation file {file} was detected. Please use the standard UTS component implementation for this purpose.";
|
|
28
|
+
readonly 'dom2.root.scroll.view': "Pages are scrollable in Vapor mode. Remove the root scroll-view to avoid nested scrolling. Details: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll";
|
|
28
29
|
readonly 'mp.component.args[0]': "The first parameter of {0} must be a static string";
|
|
29
30
|
readonly 'mp.component.args[1]': "{0} requires two parameters";
|
|
30
31
|
readonly 'mp.360.unsupported': "360 is unsupported";
|
package/dist/messages/en.js
CHANGED
|
@@ -27,6 +27,7 @@ exports.default = {
|
|
|
27
27
|
'i18n.fallbackLocale.missing': './local/{locale}.json is missing',
|
|
28
28
|
'easycom.conflict': 'easycom component conflict: ',
|
|
29
29
|
'dom2.compatible.component': 'Vapor mode does not support the uni-app compatibility component {name}. The implementation file {file} was detected. Please use the standard UTS component implementation for this purpose.',
|
|
30
|
+
'dom2.root.scroll.view': 'Pages are scrollable in Vapor mode. Remove the root scroll-view to avoid nested scrolling. Details: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll',
|
|
30
31
|
'mp.component.args[0]': 'The first parameter of {0} must be a static string',
|
|
31
32
|
'mp.component.args[1]': '{0} requires two parameters',
|
|
32
33
|
'mp.360.unsupported': '360 is unsupported',
|
package/dist/messages/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare const M: {
|
|
|
25
25
|
readonly 'i18n.fallbackLocale.missing': "当前应用配置的 fallbackLocale 或 locale 为:{locale},但 locale 目录缺少该语言文件";
|
|
26
26
|
readonly 'easycom.conflict': "easycom组件冲突:";
|
|
27
27
|
readonly 'dom2.compatible.component': "蒸汽模式不支持 uni-app 兼容模式组件 {name},检测到其实现文件为 {file}。请改用标准模式的UTS组件实现来实现。";
|
|
28
|
+
readonly 'dom2.root.scroll.view': "蒸汽模式下页面可滚动,建议移除根节点 scroll-view,以避免嵌套滚动。详情: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll";
|
|
28
29
|
readonly 'mp.component.args[0]': "{0}的第一个参数必须为静态字符串";
|
|
29
30
|
readonly 'mp.component.args[1]': "{0}需要两个参数";
|
|
30
31
|
readonly 'mp.360.unsupported': "vue3暂不支持360小程序";
|
|
@@ -82,6 +83,7 @@ export declare const M: {
|
|
|
82
83
|
readonly 'i18n.fallbackLocale.missing': "./local/{locale}.json is missing";
|
|
83
84
|
readonly 'easycom.conflict': "easycom component conflict: ";
|
|
84
85
|
readonly 'dom2.compatible.component': "Vapor mode does not support the uni-app compatibility component {name}. The implementation file {file} was detected. Please use the standard UTS component implementation for this purpose.";
|
|
86
|
+
readonly 'dom2.root.scroll.view': "Pages are scrollable in Vapor mode. Remove the root scroll-view to avoid nested scrolling. Details: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll";
|
|
85
87
|
readonly 'mp.component.args[0]': "The first parameter of {0} must be a static string";
|
|
86
88
|
readonly 'mp.component.args[1]': "{0} requires two parameters";
|
|
87
89
|
readonly 'mp.360.unsupported': "360 is unsupported";
|
package/dist/messages/zh_CN.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ declare const _default: {
|
|
|
25
25
|
readonly 'i18n.fallbackLocale.missing': "当前应用配置的 fallbackLocale 或 locale 为:{locale},但 locale 目录缺少该语言文件";
|
|
26
26
|
readonly 'easycom.conflict': "easycom组件冲突:";
|
|
27
27
|
readonly 'dom2.compatible.component': "蒸汽模式不支持 uni-app 兼容模式组件 {name},检测到其实现文件为 {file}。请改用标准模式的UTS组件实现来实现。";
|
|
28
|
+
readonly 'dom2.root.scroll.view': "蒸汽模式下页面可滚动,建议移除根节点 scroll-view,以避免嵌套滚动。详情: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll";
|
|
28
29
|
readonly 'mp.component.args[0]': "{0}的第一个参数必须为静态字符串";
|
|
29
30
|
readonly 'mp.component.args[1]': "{0}需要两个参数";
|
|
30
31
|
readonly 'mp.360.unsupported': "vue3暂不支持360小程序";
|
package/dist/messages/zh_CN.js
CHANGED
|
@@ -27,6 +27,7 @@ exports.default = {
|
|
|
27
27
|
'i18n.fallbackLocale.missing': '当前应用配置的 fallbackLocale 或 locale 为:{locale},但 locale 目录缺少该语言文件',
|
|
28
28
|
'easycom.conflict': 'easycom组件冲突:',
|
|
29
29
|
'dom2.compatible.component': '蒸汽模式不支持 uni-app 兼容模式组件 {name},检测到其实现文件为 {file}。请改用标准模式的UTS组件实现来实现。',
|
|
30
|
+
'dom2.root.scroll.view': '蒸汽模式下页面可滚动,建议移除根节点 scroll-view,以避免嵌套滚动。详情: https://doc.dcloud.net.cn/uni-app-x/page.html#disablescroll',
|
|
30
31
|
'mp.component.args[0]': '{0}的第一个参数必须为静态字符串',
|
|
31
32
|
'mp.component.args[1]': '{0}需要两个参数',
|
|
32
33
|
'mp.360.unsupported': 'vue3暂不支持360小程序',
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { PluginCreator } from 'postcss';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* 基于页面 externalClasses 使用情况提升页面样式优先级
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* .a ->
|
|
9
|
-
* -
|
|
10
|
-
* .foo ->
|
|
11
|
-
* .bar -> .bar
|
|
5
|
+
* 小程序平台(mp-*):
|
|
6
|
+
* - 页面没有使用 externalClasses:不做转换
|
|
7
|
+
* - 页面存在动态 externalClasses:选择器最后一个 class 追加 [class]
|
|
8
|
+
* .a -> .a[class]
|
|
9
|
+
* - 页面只有静态 externalClasses:仅命中静态 class 的选择器追加 [class]
|
|
10
|
+
* .foo -> .foo[class](foo 在 staticClasses 中)
|
|
11
|
+
* .bar -> .bar(bar 不在 staticClasses 中)
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* while minimizing unnecessary transformations for performance
|
|
13
|
+
* 追加 [class] 可以提升 class 选择器优先级,同时避免原先插入 page 带来的结构影响。
|
|
15
14
|
*/
|
|
16
15
|
declare const externalPlugin: PluginCreator<void>;
|
|
17
16
|
export default externalPlugin;
|
|
@@ -7,18 +7,17 @@ const postcss_selector_parser_1 = __importDefault(require("postcss-selector-pars
|
|
|
7
7
|
const pages_1 = require("../../json/pages");
|
|
8
8
|
const externalClasses_1 = require("../../mp/externalClasses");
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* 基于页面 externalClasses 使用情况提升页面样式优先级
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
* .a ->
|
|
16
|
-
* -
|
|
17
|
-
* .foo ->
|
|
18
|
-
* .bar -> .bar
|
|
12
|
+
* 小程序平台(mp-*):
|
|
13
|
+
* - 页面没有使用 externalClasses:不做转换
|
|
14
|
+
* - 页面存在动态 externalClasses:选择器最后一个 class 追加 [class]
|
|
15
|
+
* .a -> .a[class]
|
|
16
|
+
* - 页面只有静态 externalClasses:仅命中静态 class 的选择器追加 [class]
|
|
17
|
+
* .foo -> .foo[class](foo 在 staticClasses 中)
|
|
18
|
+
* .bar -> .bar(bar 不在 staticClasses 中)
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
* while minimizing unnecessary transformations for performance
|
|
20
|
+
* 追加 [class] 可以提升 class 选择器优先级,同时避免原先插入 page 带来的结构影响。
|
|
22
21
|
*/
|
|
23
22
|
const externalPlugin = () => {
|
|
24
23
|
return {
|
|
@@ -27,21 +26,21 @@ const externalPlugin = () => {
|
|
|
27
26
|
const processedRules = new WeakSet();
|
|
28
27
|
return {
|
|
29
28
|
OnceExit(root) {
|
|
30
|
-
//
|
|
29
|
+
// 只有小程序平台需要处理 externalClasses 的样式优先级
|
|
31
30
|
const platform = process.env.UNI_PLATFORM || '';
|
|
32
31
|
if (!platform.startsWith('mp-')) {
|
|
33
32
|
return;
|
|
34
33
|
}
|
|
35
|
-
//
|
|
34
|
+
// 从 postcss source 中获取当前样式所属文件
|
|
36
35
|
const filePath = root.source?.input?.file;
|
|
37
36
|
if (!filePath) {
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
|
-
//
|
|
39
|
+
// 只处理页面文件,组件文件保持原样
|
|
41
40
|
if (!(0, pages_1.isUniPageFile)(filePath)) {
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
|
-
//
|
|
43
|
+
// 获取页面中收集到的 externalClasses 使用信息
|
|
45
44
|
const externalClassesInfo = (0, externalClasses_1.findPageExternalClasses)(filePath);
|
|
46
45
|
let staticClasses = new Set();
|
|
47
46
|
let hasDynamic = false;
|
|
@@ -55,7 +54,7 @@ const externalPlugin = () => {
|
|
|
55
54
|
hasDynamic = true;
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
|
-
//
|
|
57
|
+
// 没有静态 class,也没有动态绑定时,直接跳过,避免无意义遍历
|
|
59
58
|
if (staticClasses.size === 0 && !hasDynamic) {
|
|
60
59
|
return;
|
|
61
60
|
}
|
|
@@ -68,60 +67,67 @@ const externalPlugin = () => {
|
|
|
68
67
|
};
|
|
69
68
|
};
|
|
70
69
|
function processRule(rule, processedRules, staticClasses, hasDynamic) {
|
|
71
|
-
//
|
|
70
|
+
// 同一个 Rule 只处理一次,避免被重复追加 [class]
|
|
72
71
|
if (processedRules.has(rule)) {
|
|
73
72
|
return;
|
|
74
73
|
}
|
|
75
|
-
//
|
|
74
|
+
// keyframes 内部的 from/to 不是普通选择器,不能处理
|
|
76
75
|
if (rule.parent &&
|
|
77
76
|
rule.parent.type === 'atrule' &&
|
|
78
77
|
/-?keyframes$/.test(rule.parent.name)) {
|
|
79
78
|
return;
|
|
80
79
|
}
|
|
81
80
|
processedRules.add(rule);
|
|
82
|
-
//
|
|
81
|
+
// 根据 externalClasses 情况处理选择器
|
|
83
82
|
rule.selector = (0, postcss_selector_parser_1.default)((selectorRoot) => {
|
|
84
83
|
selectorRoot.each((selector) => {
|
|
84
|
+
let classNode;
|
|
85
85
|
if (hasDynamic) {
|
|
86
|
-
//
|
|
87
|
-
|
|
86
|
+
// 动态绑定无法提前知道具体 class,所有包含 class 的选择器都提升优先级
|
|
87
|
+
classNode = findLastClassNode(selector);
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
// 静态绑定只处理命中 staticClasses 的选择器,减少无关 CSS 变更
|
|
91
|
+
classNode = findLastClassNode(selector, staticClasses);
|
|
92
|
+
}
|
|
93
|
+
if (classNode) {
|
|
94
|
+
appendClassAttribute(selector, classNode);
|
|
94
95
|
}
|
|
95
96
|
});
|
|
96
97
|
}).processSync(rule.selector);
|
|
97
98
|
}
|
|
98
99
|
/**
|
|
99
|
-
*
|
|
100
|
+
* 找到选择器最右侧的 class 节点。
|
|
101
|
+
* 传入 classes 时,仅在选择器包含目标 class 后才返回最右侧 class,
|
|
102
|
+
* 这样 .a .b 在命中 .a 时也能输出 .a .b[class],符合整体提权预期。
|
|
100
103
|
*/
|
|
101
|
-
function
|
|
102
|
-
let
|
|
103
|
-
selector.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
function findLastClassNode(selector, classes) {
|
|
105
|
+
let lastClassNode;
|
|
106
|
+
for (let i = selector.nodes.length - 1; i >= 0; i--) {
|
|
107
|
+
const node = selector.nodes[i];
|
|
108
|
+
if (node.type !== 'class') {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (!lastClassNode) {
|
|
112
|
+
lastClassNode = node;
|
|
113
|
+
}
|
|
114
|
+
if (!classes || classes.has(node.value)) {
|
|
115
|
+
return lastClassNode;
|
|
107
116
|
}
|
|
108
|
-
}
|
|
109
|
-
return found;
|
|
117
|
+
}
|
|
110
118
|
}
|
|
111
119
|
/**
|
|
112
|
-
*
|
|
113
|
-
* .a ->
|
|
114
|
-
* .
|
|
120
|
+
* 在 class 后追加 [class] 提升优先级。
|
|
121
|
+
* .a -> .a[class]
|
|
122
|
+
* .a[class] -> .a[class][class]
|
|
123
|
+
* .a .b -> .a .b[class]
|
|
115
124
|
*/
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
// Insert 'page' tag and a combinator (space) at the beginning
|
|
123
|
-
selector.prepend(postcss_selector_parser_1.default.combinator({ value: ' ' }));
|
|
124
|
-
selector.prepend(postcss_selector_parser_1.default.tag({ value: 'page' }));
|
|
125
|
+
function appendClassAttribute(selector, classNode) {
|
|
126
|
+
selector.insertAfter(classNode, postcss_selector_parser_1.default.attribute({
|
|
127
|
+
attribute: 'class',
|
|
128
|
+
value: undefined,
|
|
129
|
+
raws: {},
|
|
130
|
+
}));
|
|
125
131
|
}
|
|
126
132
|
externalPlugin.postcss = true;
|
|
127
133
|
exports.default = externalPlugin;
|
|
@@ -62,6 +62,7 @@ export interface CloudCompileParams {
|
|
|
62
62
|
vaporRenderTarget?: VaporRenderTarget;
|
|
63
63
|
env: Record<string, string>;
|
|
64
64
|
}
|
|
65
|
+
export declare function validateCloudCompileAppInfo(params: Pick<CloudCompileParams, 'appid' | 'appname'>): string;
|
|
65
66
|
export declare function checkEncryptUniModules(inputDir: string, params: CloudCompileParams, sdkType?: CloudCompileSdkType): Promise<{} | undefined>;
|
|
66
67
|
export declare function getUniModulesEncryptType(pluginId: string): "" | "utssdk" | "easycom" | undefined;
|
|
67
68
|
export declare function parseUniModulesArtifacts(): {
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.virtualComponentPath = exports.copyEncryptUniModulesDom2Bytes = exports.parseUniModulesArtifacts = exports.getUniModulesEncryptType = exports.checkEncryptUniModules = exports.resolveEncryptUniModule = exports.initCheckEnv = exports.packUploadEncryptUniModules = exports.findUploadEncryptUniModulesFiles = exports.findCloudEncryptUniModules = exports.parseEasyComComponents = exports.parseUniModulesWithComponents = exports.genEncryptUTSModuleCode = exports.genEncryptEasyComModuleCode = void 0;
|
|
6
|
+
exports.virtualComponentPath = exports.copyEncryptUniModulesDom2Bytes = exports.parseUniModulesArtifacts = exports.getUniModulesEncryptType = exports.checkEncryptUniModules = exports.validateCloudCompileAppInfo = exports.resolveEncryptUniModule = exports.initCheckEnv = exports.packUploadEncryptUniModules = exports.findUploadEncryptUniModulesFiles = exports.findCloudEncryptUniModules = exports.parseEasyComComponents = exports.parseUniModulesWithComponents = exports.genEncryptUTSModuleCode = exports.genEncryptEasyComModuleCode = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
9
|
const fast_glob_1 = require("fast-glob");
|
|
@@ -381,6 +381,20 @@ function resolveEncryptUniModule(id, platform, isX = true) {
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
exports.resolveEncryptUniModule = resolveEncryptUniModule;
|
|
384
|
+
function validateCloudCompileAppInfo(params) {
|
|
385
|
+
const missingFields = [];
|
|
386
|
+
if (!String(params.appid || '').trim()) {
|
|
387
|
+
missingFields.push('appid');
|
|
388
|
+
}
|
|
389
|
+
if (!String(params.appname || '').trim()) {
|
|
390
|
+
missingFields.push('name');
|
|
391
|
+
}
|
|
392
|
+
if (missingFields.length) {
|
|
393
|
+
return `云编译插件失败:manifest.json 缺少 ${missingFields.join('、')},请先配置后重新编译。`;
|
|
394
|
+
}
|
|
395
|
+
return '';
|
|
396
|
+
}
|
|
397
|
+
exports.validateCloudCompileAppInfo = validateCloudCompileAppInfo;
|
|
384
398
|
async function checkEncryptUniModules(inputDir, params, sdkType = 'all') {
|
|
385
399
|
const isHarmonySplitCompile = params.platform === 'app-harmony' && sdkType !== 'all';
|
|
386
400
|
// 初始化指定 sdk 类型的加密插件
|
|
@@ -399,6 +413,14 @@ async function checkEncryptUniModules(inputDir, params, sdkType = 'all') {
|
|
|
399
413
|
return {};
|
|
400
414
|
}
|
|
401
415
|
const cacheDir = process.env.UNI_MODULES_ENCRYPT_CACHE_DIR;
|
|
416
|
+
const needsCloudCompile = Object.keys(curEncryptUniModules).some((uniModuleId) => !curEncryptUniModules[uniModuleId]);
|
|
417
|
+
if (params.vapor && needsCloudCompile) {
|
|
418
|
+
const validateAppInfoError = validateCloudCompileAppInfo(params);
|
|
419
|
+
if (validateAppInfoError) {
|
|
420
|
+
console.error(validateAppInfoError);
|
|
421
|
+
return process.exit(0);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
402
424
|
const { zipFile, modules } = packUploadEncryptUniModules(curEncryptUniModules, params.platform, inputDir, cacheDir);
|
|
403
425
|
if (zipFile) {
|
|
404
426
|
const downloadFile = path_1.default.resolve(cacheDir, 'uni_modules.download.zip');
|
package/dist/vite/plugins/pre.js
CHANGED
|
@@ -8,6 +8,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const debug_1 = __importDefault(require("debug"));
|
|
9
9
|
const pluginutils_1 = require("@rollup/pluginutils");
|
|
10
10
|
const constants_1 = require("../../constants");
|
|
11
|
+
const dom2_1 = require("../../dom2");
|
|
11
12
|
const preprocess_1 = require("../../preprocess");
|
|
12
13
|
const utils_1 = require("../utils");
|
|
13
14
|
const debugPreJs = (0, debug_1.default)('uni:pre-js');
|
|
@@ -41,6 +42,7 @@ function uniPrePlugin(config, options) {
|
|
|
41
42
|
if (!hasEndif) {
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
45
|
+
(0, dom2_1.warnDom2RootScrollView)(code, filename, !!query.vue);
|
|
44
46
|
// 因为完整的 vue 会先条件编译,而 vue&type=template 等会再次条件编译,如果走error模式会报两次错误,且第二次错误没有正确的位置映射
|
|
45
47
|
const unbalanced = query.vue ? 'skip' : 'error';
|
|
46
48
|
if (isHtml) {
|