diff --git a/package.json b/package.json
index 1f9482514e443de397dcaa99fed0a3fc887ea060..a07ab35eec2e73c561d3c288bd5a9e45627cb77e 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,7 @@
"module-alias": "^2.2.2",
"postcss": "^8.3.6",
"postcss-load-config": "^3.1.0",
- "prettier": "^2.2.1",
+ "prettier": "^2.4.1",
"rollup": "^2.35.1",
"rollup-plugin-jscc": "^2.0.0",
"rollup-plugin-node-builtins": "^2.1.2",
diff --git a/packages/uni-cli-shared/package.json b/packages/uni-cli-shared/package.json
index ae6d596b883dc9325e81a84b8f2c391db07d3db1..6f725ccb1bf62e8107fa35ce0dfb0eb470510f84 100644
--- a/packages/uni-cli-shared/package.json
+++ b/packages/uni-cli-shared/package.json
@@ -21,6 +21,7 @@
"@babel/parser": "^7.15.0",
"@babel/types": "^7.15.0",
"@rollup/pluginutils": "^4.1.1",
+ "@vue/compiler-core": "^3.2.20",
"chokidar": "^3.5.2",
"compare-versions": "^3.6.0",
"debug": "^4.3.1",
diff --git a/packages/uni-cli-shared/src/vue/transforms/index.ts b/packages/uni-cli-shared/src/vue/transforms/index.ts
index 27ab8ef2a7236906b94abd6497b97daef5e69341..a0bca40e19b6083b6c4eb2918a51883f67a95ce2 100644
--- a/packages/uni-cli-shared/src/vue/transforms/index.ts
+++ b/packages/uni-cli-shared/src/vue/transforms/index.ts
@@ -1,2 +1,3 @@
-export * from './transformComponent'
+export * from './transformRef'
export * from './transformPageHead'
+export * from './transformComponent'
diff --git a/packages/uni-cli-shared/src/vue/transforms/transformComponent.ts b/packages/uni-cli-shared/src/vue/transforms/transformComponent.ts
index 4324ac1d9147ae96d18f8f8a7d44a46aa0775546..eb83e94607f4c79aaa43bc94c0b16010d9d1223a 100644
--- a/packages/uni-cli-shared/src/vue/transforms/transformComponent.ts
+++ b/packages/uni-cli-shared/src/vue/transforms/transformComponent.ts
@@ -7,10 +7,11 @@ import {
TransformContext,
} from '@vue/compiler-core'
import { COMPONENT_BIND_LINK, COMPONENT_ON_LINK } from '../../mp/constants'
-import { isUserComponent } from '../utils'
+import { isUserComponent, createAttributeNode } from '../utils'
export function createTransformComponentLink(
- name: typeof COMPONENT_BIND_LINK | typeof COMPONENT_ON_LINK
+ name: typeof COMPONENT_BIND_LINK | typeof COMPONENT_ON_LINK,
+ type: NodeTypes.ATTRIBUTE | NodeTypes.DIRECTIVE = NodeTypes.DIRECTIVE
) {
return function transformComponentLink(
node: RootNode | TemplateChildNode,
@@ -19,13 +20,17 @@ export function createTransformComponentLink(
if (!isUserComponent(node, context)) {
return
}
- node.props.push({
- type: NodeTypes.DIRECTIVE,
- name: 'on',
- modifiers: [],
- loc: locStub,
- arg: createSimpleExpression(name, true),
- exp: createSimpleExpression('__l', true),
- })
+ if (type === NodeTypes.DIRECTIVE) {
+ node.props.push({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ modifiers: [],
+ loc: locStub,
+ arg: createSimpleExpression(name, true),
+ exp: createSimpleExpression('__l', true),
+ })
+ } else {
+ node.props.push(createAttributeNode(name, '__l'))
+ }
}
}
diff --git a/packages/uni-cli-shared/src/vue/transforms/transformRef.ts b/packages/uni-cli-shared/src/vue/transforms/transformRef.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cad3fd175ca1318d05a0d65239f110fd58343eb2
--- /dev/null
+++ b/packages/uni-cli-shared/src/vue/transforms/transformRef.ts
@@ -0,0 +1,47 @@
+import {
+ ComponentNode,
+ findProp,
+ NodeTypes,
+ RootNode,
+ SimpleExpressionNode,
+ TemplateChildNode,
+ TransformContext,
+} from '@vue/compiler-core'
+import {
+ addStaticClass,
+ VUE_REF,
+ VUE_REF_IN_FOR,
+ isUserComponent,
+} from '../utils'
+
+export function transformRef(
+ node: RootNode | TemplateChildNode,
+ context: TransformContext
+) {
+ if (!isUserComponent(node, context)) {
+ return
+ }
+ addVueRef(node, context)
+}
+
+function addVueRef(node: ComponentNode, context: TransformContext) {
+ // 仅配置了 ref 属性的,才需要增补 vue-ref
+ const refProp = findProp(node, 'ref')
+ if (!refProp) {
+ return
+ }
+ if (refProp.type === NodeTypes.ATTRIBUTE) {
+ refProp.name = 'data-' + VUE_REF
+ } else {
+ ;(refProp.arg as SimpleExpressionNode).content = 'data-' + VUE_REF
+ }
+
+ return addStaticClass(
+ node,
+ // ref-in-for
+ // ref
+ (context as unknown as { inVFor: boolean }).inVFor
+ ? VUE_REF_IN_FOR
+ : VUE_REF
+ )
+}
diff --git a/packages/uni-cli-shared/src/vue/utils.ts b/packages/uni-cli-shared/src/vue/utils.ts
index 5e8fc1844a494b4864d0f864c3529639f0357844..37842feb7cf4f4bfe868d387e2d648fef8b00f3a 100644
--- a/packages/uni-cli-shared/src/vue/utils.ts
+++ b/packages/uni-cli-shared/src/vue/utils.ts
@@ -1,14 +1,20 @@
import { isComponentTag } from '@dcloudio/uni-shared'
import {
+ AttributeNode,
ComponentNode,
+ ElementNode,
ElementTypes,
isCoreComponent,
+ locStub,
NodeTypes,
RootNode,
TemplateChildNode,
TransformContext,
} from '@vue/compiler-core'
+export const VUE_REF = 'r'
+export const VUE_REF_IN_FOR = 'r-i-f'
+
export function isUserComponent(
node: RootNode | TemplateChildNode,
context: TransformContext
@@ -21,3 +27,42 @@ export function isUserComponent(
!context.isBuiltInComponent(node.tag)
)
}
+
+export function createAttributeNode(
+ name: string,
+ content: string
+): AttributeNode {
+ return {
+ type: NodeTypes.ATTRIBUTE,
+ loc: locStub,
+ name,
+ value: {
+ type: NodeTypes.TEXT,
+ loc: locStub,
+ content,
+ },
+ }
+}
+
+function createClassAttribute(clazz: string): AttributeNode {
+ return createAttributeNode('class', clazz)
+}
+
+export function addStaticClass(node: ElementNode, clazz: string) {
+ const classProp = node.props.find(
+ (prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === 'class'
+ ) as AttributeNode | undefined
+
+ if (!classProp) {
+ return node.props.unshift(createClassAttribute(clazz))
+ }
+
+ if (classProp.value) {
+ return (classProp.value.content = classProp.value.content + ' ' + clazz)
+ }
+ classProp.value = {
+ type: NodeTypes.TEXT,
+ loc: locStub,
+ content: clazz,
+ }
+}
diff --git a/packages/uni-mp-alipay/__tests__/ref.spec.ts b/packages/uni-mp-alipay/__tests__/ref.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bfa37724a6569b19e5ebf603531da439936a6388
--- /dev/null
+++ b/packages/uni-mp-alipay/__tests__/ref.spec.ts
@@ -0,0 +1,52 @@
+import { assert } from './testUtils'
+
+describe('compiler: transform ref', () => {
+ test('without ref', () => {
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return {}
+}`
+ )
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return {}
+}`
+ )
+ })
+ test('static ref', () => {
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return {}
+}`
+ )
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return { a: _f(_ctx.items, (item, k0, i0) => { return { a: '2a9ec0b0-0' + '-' + i0 }; }) }
+}`
+ )
+ })
+ test('dynamic ref', () => {
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return { a: _ctx.custom }
+}`
+ )
+ assert(
+ ``,
+ ``,
+ `(_ctx, _cache) => {
+ return { a: _f(_ctx.items, (item, k0, i0) => { return { a: '2a9ec0b0-0' + '-' + i0 }; }), b: _ctx.custom }
+}`
+ )
+ })
+})
diff --git a/packages/uni-mp-alipay/__tests__/testUtils.ts b/packages/uni-mp-alipay/__tests__/testUtils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f546e2a9a34290896d4c89d61d87e40ed5633193
--- /dev/null
+++ b/packages/uni-mp-alipay/__tests__/testUtils.ts
@@ -0,0 +1,38 @@
+import { isCustomElement, isNativeTag } from '@dcloudio/uni-shared'
+import { compile, CompilerOptions } from '@dcloudio/uni-mp-compiler'
+
+import { miniProgram, nodeTransforms } from '../src/compiler/options'
+
+export function assert(
+ template: string,
+ templateCode: string,
+ renderCode: string,
+ options: CompilerOptions = {}
+) {
+ const res = compile(template, {
+ mode: 'module',
+ filename: 'foo.vue',
+ prefixIdentifiers: true,
+ inline: true,
+ isNativeTag,
+ isCustomElement,
+ generatorOpts: {
+ concise: true,
+ },
+ nodeTransforms,
+ miniProgram: {
+ ...miniProgram,
+ emitFile({ source }) {
+ // console.log(source)
+ if (!options.onError) {
+ expect(source).toBe(templateCode)
+ }
+ return ''
+ },
+ },
+ ...options,
+ })
+ if (!options.onError) {
+ expect(res.code).toBe(renderCode)
+ }
+}
diff --git a/packages/uni-mp-alipay/dist/uni.compiler.js b/packages/uni-mp-alipay/dist/uni.compiler.js
index 3b1e76658d69729c3d242c2b94e1fd9dd8216322..a21e73b634e9e627affa1f5cf00a554fe76202e6 100644
--- a/packages/uni-mp-alipay/dist/uni.compiler.js
+++ b/packages/uni-mp-alipay/dist/uni.compiler.js
@@ -16,7 +16,1139 @@ var source = {
enableAppxNg: enableAppxNg
};
+/**
+ * Make a map and return a function for checking if a key
+ * is in that map.
+ * IMPORTANT: all calls of this function must be prefixed with
+ * \/\*#\_\_PURE\_\_\*\/
+ * So that rollup can tree-shake them if necessary.
+ */
+
+/**
+ * dev only flag -> name mapping
+ */
+const PatchFlagNames = {
+ [1 /* TEXT */]: `TEXT`,
+ [2 /* CLASS */]: `CLASS`,
+ [4 /* STYLE */]: `STYLE`,
+ [8 /* PROPS */]: `PROPS`,
+ [16 /* FULL_PROPS */]: `FULL_PROPS`,
+ [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`,
+ [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`,
+ [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`,
+ [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`,
+ [512 /* NEED_PATCH */]: `NEED_PATCH`,
+ [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`,
+ [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`,
+ [-1 /* HOISTED */]: `HOISTED`,
+ [-2 /* BAIL */]: `BAIL`
+};
+
+(process.env.NODE_ENV !== 'production')
+ ? Object.freeze({})
+ : {};
+(process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];
+const NOOP = () => { };
+/**
+ * Always return false.
+ */
+const NO = () => false;
+const extend = Object.assign;
+const isArray = Array.isArray;
+const isString = (val) => typeof val === 'string';
+const cacheStringFunction = (fn) => {
+ const cache = Object.create(null);
+ return ((str) => {
+ const hit = cache[str];
+ return hit || (cache[str] = fn(str));
+ });
+};
+const hyphenateRE = /\B([A-Z])/g;
+/**
+ * @private
+ */
+const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, '-$1').toLowerCase());
+
+function defaultOnError(error) {
+ throw error;
+}
+function defaultOnWarn(msg) {
+ (process.env.NODE_ENV !== 'production') && console.warn(`[Vue warn] ${msg.message}`);
+}
+function createCompilerError(code, loc, messages, additionalMessage) {
+ const msg = (process.env.NODE_ENV !== 'production') || !true
+ ? (messages || errorMessages)[code] + (additionalMessage || ``)
+ : code;
+ const error = new SyntaxError(String(msg));
+ error.code = code;
+ error.loc = loc;
+ return error;
+}
+const errorMessages = {
+ // parse errors
+ [0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */]: 'Illegal comment.',
+ [1 /* CDATA_IN_HTML_CONTENT */]: 'CDATA section is allowed only in XML context.',
+ [2 /* DUPLICATE_ATTRIBUTE */]: 'Duplicate attribute.',
+ [3 /* END_TAG_WITH_ATTRIBUTES */]: 'End tag cannot have attributes.',
+ [4 /* END_TAG_WITH_TRAILING_SOLIDUS */]: "Illegal '/' in tags.",
+ [5 /* EOF_BEFORE_TAG_NAME */]: 'Unexpected EOF in tag.',
+ [6 /* EOF_IN_CDATA */]: 'Unexpected EOF in CDATA section.',
+ [7 /* EOF_IN_COMMENT */]: 'Unexpected EOF in comment.',
+ [8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */]: 'Unexpected EOF in script.',
+ [9 /* EOF_IN_TAG */]: 'Unexpected EOF in tag.',
+ [10 /* INCORRECTLY_CLOSED_COMMENT */]: 'Incorrectly closed comment.',
+ [11 /* INCORRECTLY_OPENED_COMMENT */]: 'Incorrectly opened comment.',
+ [12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */]: "Illegal tag name. Use '<' to print '<'.",
+ [13 /* MISSING_ATTRIBUTE_VALUE */]: 'Attribute value was expected.',
+ [14 /* MISSING_END_TAG_NAME */]: 'End tag name was expected.',
+ [15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */]: 'Whitespace was expected.',
+ [16 /* NESTED_COMMENT */]: "Unexpected '