From 7c3876c1d20e4c81ed14d7411f0d946e28165e77 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Tue, 26 Oct 2021 21:16:57 +0800 Subject: [PATCH] wip(mp): mp-baidu --- packages/uni-mp-baidu/__tests__/testUtils.ts | 4 + packages/uni-mp-baidu/__tests__/vOn.spec.ts | 33 ++++++ packages/uni-mp-baidu/dist/uni.compiler.js | 72 +++++++++++++ packages/uni-mp-baidu/dist/uni.mp.esm.js | 9 ++ packages/uni-mp-baidu/src/plugin/index.ts | 4 + .../uni-mp-baidu/src/plugin/transforms/vOn.ts | 101 ++++++++++++++++++ .../src/runtime/parseComponentOptions.ts | 26 +++++ packages/uni-mp-compiler/src/compile.ts | 5 +- packages/uni-mp-compiler/src/index.ts | 4 +- .../uni-mp-compiler/src/transforms/utils.ts | 3 +- .../uni-mp-compiler/src/transforms/vOn.ts | 6 +- 11 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 packages/uni-mp-baidu/__tests__/vOn.spec.ts create mode 100644 packages/uni-mp-baidu/src/plugin/transforms/vOn.ts diff --git a/packages/uni-mp-baidu/__tests__/testUtils.ts b/packages/uni-mp-baidu/__tests__/testUtils.ts index a8e9f1dd9..6e314b67c 100644 --- a/packages/uni-mp-baidu/__tests__/testUtils.ts +++ b/packages/uni-mp-baidu/__tests__/testUtils.ts @@ -1,6 +1,7 @@ import { isCustomElement, isNativeTag } from '@dcloudio/uni-shared' import { compile, CompilerOptions } from '@dcloudio/uni-mp-compiler' import { transformFor } from '../src/plugin/transforms/vFor' +import { transformOn } from '../src/plugin/transforms/vOn' export function assert( template: string, @@ -19,6 +20,9 @@ export function assert( concise: true, }, nodeTransforms: [transformFor], + directiveTransforms: { + on: transformOn, + }, miniProgram: { slot: { fallback: false, diff --git a/packages/uni-mp-baidu/__tests__/vOn.spec.ts b/packages/uni-mp-baidu/__tests__/vOn.spec.ts new file mode 100644 index 000000000..baddb5a98 --- /dev/null +++ b/packages/uni-mp-baidu/__tests__/vOn.spec.ts @@ -0,0 +1,33 @@ +import { assert } from './testUtils' + +describe('mp-baidu: transform v-on', () => { + describe('component', () => { + test(`built-in event`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: _o(_ctx.tap) } +}` + ) + }) + test(`custom event`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'click': _o(_ctx.click) } } +}` + ) + }), + test(`multi custom event`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'custom-mount': _o($event => { _ctx.mount(); _ctx.created(); }), 'unmount': _o(_ctx.unmount) } } +}` + ) + }) + }) +}) diff --git a/packages/uni-mp-baidu/dist/uni.compiler.js b/packages/uni-mp-baidu/dist/uni.compiler.js index deaf2fecc..1e0ba6658 100644 --- a/packages/uni-mp-baidu/dist/uni.compiler.js +++ b/packages/uni-mp-baidu/dist/uni.compiler.js @@ -3,6 +3,7 @@ var uniCliShared = require('@dcloudio/uni-cli-shared'); var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); var uniMpCompiler = require('@dcloudio/uni-mp-compiler'); +var compilerCore = require('@vue/compiler-core'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } @@ -48,6 +49,74 @@ const transformFor = (node) => { } }; +/** + * 百度小程序的自定义组件,不支持动态事件绑定,故转换为静态事件 + dataset + * @param dir + * @param node + * @param context + * @param augmentor + * @returns + */ +const transformOn = (dir, node, context, augmentor) => { + const res = uniMpCompiler.transformOn(dir, node, context, augmentor); + const { name, arg, exp } = dir; + if (name !== 'on' || + !arg || + !exp || + !compilerCore.isStaticExp(arg) || + !isCustomEvent(arg.content) || + !uniMpCompiler.isUserComponent(node, context)) { + return res; + } + // data-event-opts + const opts = compilerCore.findProp(node, ATTR_DATA_EVENT_OPTS, true); + const value = res.props[0].value; + res.props[0].value = compilerCore.createSimpleExpression('__e', true); + if (!opts) { + node.props.push(createDataEventOptsProp(arg.content, value)); + } + else { + const children = opts.exp.children; + children.splice(children.length - 2, 0, createDataEventOptsProperty(arg.content, value)); + } + return res; +}; +const ATTR_DATA_EVENT_OPTS = 'data-e-o'; +function createDataEventOptsProperty(event, exp) { + return compilerCore.createCompoundExpression([`'${event}'`, ': ', exp, ',']); +} +function createDataEventOptsProp(event, exp) { + return { + type: 7 /* DIRECTIVE */, + name: 'bind', + loc: compilerCore.locStub, + modifiers: [], + arg: compilerCore.createSimpleExpression(ATTR_DATA_EVENT_OPTS, true), + exp: compilerCore.createCompoundExpression([ + '{', + createDataEventOptsProperty(event, exp), + '}', + ]), + }; +} +const builtInEvents = [ + 'tap', + 'longtap', + 'longpress', + 'touchstart', + 'touchmove', + 'touchcancel', + 'touchend', + 'touchforcechange', + 'transitionend', + 'animationstart', + 'animationiteration', + 'animationend', +]; +function isCustomEvent(name) { + return !builtInEvents.includes(name); +} + const uniMiniProgramBaiduPlugin = { name: 'vite:uni-mp-baidu', config() { @@ -103,6 +172,9 @@ ${filter.code} directive: 's-', compilerOptions: { nodeTransforms: [transformFor], + directiveTransforms: { + on: transformOn, + }, }, }, style: { diff --git a/packages/uni-mp-baidu/dist/uni.mp.esm.js b/packages/uni-mp-baidu/dist/uni.mp.esm.js index b1d1fe69b..dbc450c0c 100644 --- a/packages/uni-mp-baidu/dist/uni.mp.esm.js +++ b/packages/uni-mp-baidu/dist/uni.mp.esm.js @@ -871,6 +871,15 @@ function parse$1(componentOptions) { __l: methods.__l, }; delete methods.__l; + methods.__e = handleCustomEvent; +} +function handleCustomEvent(event) { + const { type, target: { dataset: { eO: eventOpts }, }, } = event; + const methodName = (eventOpts || {})[type]; + if (!methodName) { + return console.warn(type + ' not found'); + } + this[methodName](event); } var parseComponentOptions = /*#__PURE__*/Object.freeze({ diff --git a/packages/uni-mp-baidu/src/plugin/index.ts b/packages/uni-mp-baidu/src/plugin/index.ts index c8c363cb1..52ab8177b 100644 --- a/packages/uni-mp-baidu/src/plugin/index.ts +++ b/packages/uni-mp-baidu/src/plugin/index.ts @@ -6,6 +6,7 @@ import initMiniProgramPlugin, { import source from './project.swan.json' import { transformFor } from './transforms/vFor' +import { transformOn } from './transforms/vOn' const uniMiniProgramBaiduPlugin: Plugin = { name: 'vite:uni-mp-baidu', @@ -66,6 +67,9 @@ ${filter.code} directive: 's-', compilerOptions: { nodeTransforms: [transformFor], + directiveTransforms: { + on: transformOn, + }, }, }, style: { diff --git a/packages/uni-mp-baidu/src/plugin/transforms/vOn.ts b/packages/uni-mp-baidu/src/plugin/transforms/vOn.ts new file mode 100644 index 000000000..afdf67ac4 --- /dev/null +++ b/packages/uni-mp-baidu/src/plugin/transforms/vOn.ts @@ -0,0 +1,101 @@ +import { + DirectiveTransform, + isUserComponent, + transformOn as baseTransformOn, +} from '@dcloudio/uni-mp-compiler' +import { + ExpressionNode, + DirectiveNode, + findProp, + isStaticExp, + NodeTypes, + locStub, + createSimpleExpression, + createCompoundExpression, + CompoundExpressionNode, +} from '@vue/compiler-core' +/** + * 百度小程序的自定义组件,不支持动态事件绑定,故转换为静态事件 + dataset + * @param dir + * @param node + * @param context + * @param augmentor + * @returns + */ +export const transformOn: DirectiveTransform = ( + dir, + node, + context, + augmentor +) => { + const res = baseTransformOn(dir, node, context, augmentor) + const { name, arg, exp } = dir + if ( + name !== 'on' || + !arg || + !exp || + !isStaticExp(arg) || + !isCustomEvent(arg.content) || + !isUserComponent(node, context) + ) { + return res + } + // data-event-opts + const opts = findProp(node, ATTR_DATA_EVENT_OPTS, true) as DirectiveNode + const value = res.props[0].value as ExpressionNode + res.props[0].value = createSimpleExpression('__e', true) + if (!opts) { + node.props.push(createDataEventOptsProp(arg.content, value)) + } else { + const children = (opts.exp as CompoundExpressionNode).children + children.splice( + children.length - 2, + 0, + createDataEventOptsProperty(arg.content, value) + ) + } + return res +} + +const ATTR_DATA_EVENT_OPTS = 'data-e-o' + +function createDataEventOptsProperty(event: string, exp: ExpressionNode) { + return createCompoundExpression([`'${event}'`, ': ', exp, ',']) +} + +function createDataEventOptsProp( + event: string, + exp: ExpressionNode +): DirectiveNode { + return { + type: NodeTypes.DIRECTIVE, + name: 'bind', + loc: locStub, + modifiers: [], + arg: createSimpleExpression(ATTR_DATA_EVENT_OPTS, true), + exp: createCompoundExpression([ + '{', + createDataEventOptsProperty(event, exp), + '}', + ]), + } +} + +const builtInEvents = [ + 'tap', + 'longtap', + 'longpress', + 'touchstart', + 'touchmove', + 'touchcancel', + 'touchend', + 'touchforcechange', + 'transitionend', + 'animationstart', + 'animationiteration', + 'animationend', +] + +function isCustomEvent(name: string) { + return !builtInEvents.includes(name) +} diff --git a/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts b/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts index 0d11ebdbb..ba629137f 100644 --- a/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts +++ b/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts @@ -10,6 +10,7 @@ import { fixSetDataStart, fixSetDataEnd, } from '../../../uni-mp-weixin/src/runtime/fixSetData' +import { ComponentPublicInstance } from 'vue' export { handleLink, initLifetimes } from '@dcloudio/uni-mp-weixin' @@ -83,4 +84,29 @@ export function parse(componentOptions: MPComponentOptions) { __l: methods.__l, } delete methods.__l + + methods.__e = handleCustomEvent +} + +function handleCustomEvent( + this: MPComponentInstance, + event: { + type: string + target: { dataset: { eO: { [name: string]: string } } } + detail: { + __args__: any[] + } + } +) { + const { + type, + target: { + dataset: { eO: eventOpts }, + }, + } = event + const methodName = (eventOpts || {})[type] + if (!methodName) { + return console.warn(type + ' not found') + } + ;(this as any)[methodName](event) } diff --git a/packages/uni-mp-compiler/src/compile.ts b/packages/uni-mp-compiler/src/compile.ts index 0f44279c9..6caf7af27 100644 --- a/packages/uni-mp-compiler/src/compile.ts +++ b/packages/uni-mp-compiler/src/compile.ts @@ -38,7 +38,10 @@ export function getBaseTransformPreset({ if (prefixIdentifiers) { nodeTransforms.push(transformExpression) } - return [nodeTransforms, { on: transformOn, bind: transformBind }] + return [ + nodeTransforms, + { on: transformOn as unknown as DirectiveTransform, bind: transformBind }, + ] } export function baseCompile(template: string, options: CompilerOptions = {}) { diff --git a/packages/uni-mp-compiler/src/index.ts b/packages/uni-mp-compiler/src/index.ts index 7f19ceebe..bc65fa386 100644 --- a/packages/uni-mp-compiler/src/index.ts +++ b/packages/uni-mp-compiler/src/index.ts @@ -15,13 +15,15 @@ export type { CompilerOptions, DirectiveNode, NodeTransform, + DirectiveTransform, TransformContext, SimpleExpressionNode, } from '@vue/compiler-core' export { genExpr } from './codegen' export { isForElementNode } from './transforms/vFor' - +export { isUserComponent } from './transforms/utils' +export { transformOn } from './transforms/vOn' export * from './runtimeHelpers' export function parse(template: string, options: ParserOptions = {}): RootNode { diff --git a/packages/uni-mp-compiler/src/transforms/utils.ts b/packages/uni-mp-compiler/src/transforms/utils.ts index 82ed18897..e88a09db0 100644 --- a/packages/uni-mp-compiler/src/transforms/utils.ts +++ b/packages/uni-mp-compiler/src/transforms/utils.ts @@ -21,6 +21,7 @@ import { RootNode, SourceLocation, TemplateChildNode, + TransformContext as VueTransformContext, } from '@vue/compiler-core' import { walk, BaseNode } from 'estree-walker' import { isUndefined, parseExpr } from '../ast' @@ -36,7 +37,7 @@ export const SCOPED_SLOT_IDENTIFIER = '__SCOPED_SLOT__' export function isUserComponent( node: RootNode | TemplateChildNode, - context: TransformContext + context: TransformContext | VueTransformContext ): node is ComponentNode { return ( node.type === NodeTypes.ELEMENT && diff --git a/packages/uni-mp-compiler/src/transforms/vOn.ts b/packages/uni-mp-compiler/src/transforms/vOn.ts index a01472c46..9ae434b69 100644 --- a/packages/uni-mp-compiler/src/transforms/vOn.ts +++ b/packages/uni-mp-compiler/src/transforms/vOn.ts @@ -12,10 +12,11 @@ import { NodeTypes, SimpleExpressionNode, TO_HANDLER_KEY, + DirectiveTransform, } from '@vue/compiler-core' import { camelize, toHandlerKey } from '@vue/shared' import { V_ON } from '../runtimeHelpers' -import { DirectiveTransform, TransformContext } from '../transform' +import { TransformContext } from '../transform' import { DirectiveTransformResult } from './transformElement' import { isBuiltInIdentifier, processExpression } from './transformExpression' @@ -35,9 +36,10 @@ export interface VOnDirectiveNode extends DirectiveNode { export const transformOn: DirectiveTransform = ( dir, node, - context, + _context, augmentor ) => { + const context = _context as unknown as TransformContext const { loc, modifiers, arg } = dir as VOnDirectiveNode if (!dir.exp && !modifiers.length) { context.onError(createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc)) -- GitLab