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 '