diff --git a/packages/shims-uni-app.d.ts b/packages/shims-uni-app.d.ts index ee998aa38a601fb520035683528d3a38c01ee4dc..64b03779f85d869d21d06d7c0c78744bdb8885d4 100644 --- a/packages/shims-uni-app.d.ts +++ b/packages/shims-uni-app.d.ts @@ -171,6 +171,7 @@ declare namespace UniApp { 'mp-toutiao'?: PagesJsonPageStyle 'mp-weixin'?: PagesJsonPageStyle 'mp-kuaishou'?: PagesJsonPageStyle + 'mp-lark'?: PagesJsonPageStyle 'quickapp-webview'?: PagesJsonPageStyle 'quickapp-webview-huawei'?: PagesJsonPageStyle 'quickapp-webview-union'?: PagesJsonPageStyle diff --git a/packages/uni-cli-shared/src/json/mp/pages.ts b/packages/uni-cli-shared/src/json/mp/pages.ts index 288bfee4cc2f0600455e91ed2a534791b76a5d29..063f4fc34f939e9e56514c0b4617c0b2f1ed8ea2 100644 --- a/packages/uni-cli-shared/src/json/mp/pages.ts +++ b/packages/uni-cli-shared/src/json/mp/pages.ts @@ -59,10 +59,14 @@ function parsePagesJson( ) { nvuePages.push(pagePath) } + const windowOptions: PageWindowOptions = {} + if (platform === 'mp-baidu') { + // 仅百度小程序需要页面配置 component:true + // 快手小程序反而不能配置 component:true,故不能统一添加,目前硬编码处理 + windowOptions.component = true + } pageJsons[pagePath] = extend( - { - component: true, - }, + windowOptions, parseWindowOptions(style, platform, windowOptionsMap) as PageWindowOptions ) } diff --git a/packages/uni-cli-shared/src/json/mp/types.ts b/packages/uni-cli-shared/src/json/mp/types.ts index 08fbd8e65364063bbd54867ed9a7a6e4d3932f80..c63d57a731be636c8cc8dc559962fede4844fc9b 100644 --- a/packages/uni-cli-shared/src/json/mp/types.ts +++ b/packages/uni-cli-shared/src/json/mp/types.ts @@ -21,7 +21,7 @@ type Style = 'v2' | string type RestartStrategy = 'homePage' | 'homePageAndLatestPage' | string export interface PageWindowOptions extends ShareWindowOptions { - component: true // 百度小程序页面必须配置component: true + component?: true // 百度小程序页面必须配置component: true disableScroll?: boolean // false usingComponents?: UsingComponents initialRenderingCache?: 'static' | string diff --git a/packages/uni-cli-shared/src/mp/template.ts b/packages/uni-cli-shared/src/mp/template.ts index aaafb5bfdd1d85bf8f81a175d712cb58eaf0cc27..0b1fad8623f1d0e18b93cac18c43182fea9fecf0 100644 --- a/packages/uni-cli-shared/src/mp/template.ts +++ b/packages/uni-cli-shared/src/mp/template.ts @@ -4,6 +4,12 @@ import { LINEFEED } from '@dcloudio/uni-shared' import { normalizeMiniProgramFilename } from '../utils' export interface MiniProgramCompilerOptions { + /** + * 需要延迟渲染的组件,通常是某个组件的某个事件会立刻触发,需要延迟到首次 render 之后,比如微信 editor 的 ready 事件,快手 switch 的 change + */ + lazyElement?: { + [name: string]: string[] + } event?: { format( name: string, diff --git a/packages/uni-cli-shared/src/vue/transforms/index.ts b/packages/uni-cli-shared/src/vue/transforms/index.ts index 26b4ad4f97e9379995a5051a90c885c7e0a0cfd1..ddbd04fe27dd764bf7331325dc7a0c67cc58ae51 100644 --- a/packages/uni-cli-shared/src/vue/transforms/index.ts +++ b/packages/uni-cli-shared/src/vue/transforms/index.ts @@ -8,6 +8,15 @@ export * from './transformPageHead' export * from './transformComponent' export * from './transformEvent' export * from './transformTag' +export { + ATTR_DATASET_EVENT_OPTS, + createTransformOn, + defaultMatch as matchTransformOn, +} from './vOn' +export { + createTransformModel, + defaultMatch as matchTransformModel, +} from './vModel' export const transformMatchMedia = createTransformTag({ 'match-media': 'uni-match-media', diff --git a/packages/uni-cli-shared/src/vue/transforms/vModel.ts b/packages/uni-cli-shared/src/vue/transforms/vModel.ts new file mode 100644 index 0000000000000000000000000000000000000000..27b4c392eaae1186ae9f3b6fc325740d2cc89fb2 --- /dev/null +++ b/packages/uni-cli-shared/src/vue/transforms/vModel.ts @@ -0,0 +1,47 @@ +import { + ComponentNode, + DirectiveNode, + DirectiveTransform, + ElementNode, + SimpleExpressionNode, + TransformContext, +} from '@vue/compiler-core' +import { isUserComponent } from '../utils' +import { addEventOpts, createCustomEventExpr } from './vOn' +export function defaultMatch(node: ElementNode, context: TransformContext) { + return isUserComponent(node, context) +} +interface CreateTransformModelOptions { + match: typeof defaultMatch +} + +/** + * 百度、快手小程序的自定义组件,不支持动态事件绑定,故 v-model 也需要调整 + * @param baseTransformModel + * @returns + */ +export function createTransformModel( + baseTransformModel: DirectiveTransform, + { match }: CreateTransformModelOptions = { + match: defaultMatch, + } +): DirectiveTransform { + return (dir, node, context, augmentor) => { + const res = baseTransformModel(dir, node, context, augmentor) + if (!match(node, context)) { + return res + } + const props = res.props as unknown as DirectiveNode[] + if (props[1]) { + // input,textarea 的 v-model 事件可能会被合并到已有的 input 中 + const { arg, exp } = props[1] + addEventOpts( + (arg as SimpleExpressionNode).content, + exp as SimpleExpressionNode, + node as ComponentNode + ) + props[1].exp = createCustomEventExpr() + } + return res + } +} diff --git a/packages/uni-cli-shared/src/vue/transforms/vOn.ts b/packages/uni-cli-shared/src/vue/transforms/vOn.ts new file mode 100644 index 0000000000000000000000000000000000000000..65b13e1c9bf580b2dda8a82e0cb2d13c1fda9533 --- /dev/null +++ b/packages/uni-cli-shared/src/vue/transforms/vOn.ts @@ -0,0 +1,124 @@ +import { + ExpressionNode, + DirectiveNode, + findProp, + isStaticExp, + NodeTypes, + locStub, + createSimpleExpression, + createCompoundExpression, + CompoundExpressionNode, + DirectiveTransform, + ElementNode, + TransformContext, + ElementTypes, +} from '@vue/compiler-core' +import { isUserComponent } from '../utils' +export function defaultMatch( + name: string, + node: ElementNode, + context: TransformContext +) { + return isCustomEvent(name) && isUserComponent(node, context) +} +interface CreateTransformOnOptions { + match: typeof defaultMatch +} +/** + * 百度、快手小程序的自定义组件,不支持动态事件绑定,故转换为静态事件 + dataset + * @param baseTransformOn + * @returns + */ +export function createTransformOn( + baseTransformOn: DirectiveTransform, + { match }: CreateTransformOnOptions = { + match: defaultMatch, + } +): DirectiveTransform { + return (dir, node, context, augmentor) => { + const res = baseTransformOn(dir, node, context, augmentor) + const { name, arg, exp } = dir + if (name !== 'on' || !arg || !exp || !isStaticExp(arg)) { + return res + } + if (!match(arg.content, node, context)) { + return res + } + const value = res.props[0].value as ExpressionNode + res.props[0].value = createCustomEventExpr() + addEventOpts(arg.content, value, node) + return res + } +} + +export function createCustomEventExpr() { + return createSimpleExpression('__e', true) +} + +export function addEventOpts( + event: string, + value: ExpressionNode, + node: ElementNode +) { + const attrName = + node.tagType === ElementTypes.COMPONENT + ? ATTR_DATA_EVENT_OPTS + : ATTR_DATASET_EVENT_OPTS + const opts = findProp(node, attrName, true) as DirectiveNode + if (!opts) { + node.props.push(createDataEventOptsProp(attrName, event, value)) + } else { + const children = (opts.exp as CompoundExpressionNode).children + children.splice( + children.length - 2, + 0, + createDataEventOptsProperty(event, value) + ) + } +} + +const ATTR_DATA_EVENT_OPTS = 'eO' +export const ATTR_DATASET_EVENT_OPTS = 'data-e-o' + +function createDataEventOptsProperty(event: string, exp: ExpressionNode) { + return createCompoundExpression([`'${event}'`, ': ', exp, ',']) +} + +function createDataEventOptsProp( + name: string, + event: string, + exp: ExpressionNode +): DirectiveNode { + return { + type: NodeTypes.DIRECTIVE, + name: 'bind', + loc: locStub, + modifiers: [], + arg: createSimpleExpression(name, true), + exp: createCompoundExpression([ + '{', + createDataEventOptsProperty(event, exp), + '}', + ]), + } +} + +const builtInEvents = [ + '__l', // 快手使用了该事件 + '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/dist/uni.compiler.js b/packages/uni-mp-baidu/dist/uni.compiler.js index 32c907e16f117c208afe8f81538965fec4356332..fb9570863c92c8f73eb270b2644f29d4936e64fa 100644 --- a/packages/uni-mp-baidu/dist/uni.compiler.js +++ b/packages/uni-mp-baidu/dist/uni.compiler.js @@ -5,7 +5,6 @@ var path = require('path'); var uniShared = require('@dcloudio/uni-shared'); var uniCliShared = require('@dcloudio/uni-cli-shared'); 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 }; } @@ -57,97 +56,14 @@ const transformFor = (node, context) => { }; /** - * 百度小程序的自定义组件,不支持动态事件绑定,故转换为静态事件 + 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) || - !uniCliShared.isUserComponent(node, context)) { - return res; - } - const value = res.props[0].value; - res.props[0].value = createCustomEventExpr(); - addEventOpts(arg.content, value, node); - return res; -}; -function createCustomEventExpr() { - return compilerCore.createSimpleExpression('__e', true); -} -function addEventOpts(event, value, node) { - const opts = compilerCore.findProp(node, ATTR_DATA_EVENT_OPTS, true); - if (!opts) { - node.props.push(createDataEventOptsProp(event, value)); - } - else { - const children = opts.exp.children; - children.splice(children.length - 2, 0, createDataEventOptsProperty(event, value)); - } -} -const ATTR_DATA_EVENT_OPTS = 'eO'; -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 transformOn = uniCliShared.createTransformOn(uniMpCompiler.transformOn); /** * 百度小程序的自定义组件,不支持动态事件绑定,故 v-model 也需要调整 - * @param dir - * @param node - * @param context - * @param augmentor - * @returns */ -const transformModel = (dir, node, context, augmentor) => { - const res = uniMpCompiler.transformModel(dir, node, context, augmentor); - const props = res.props; - if (props.length < 2 || !uniCliShared.isUserComponent(node, context)) { - return res; - } - const { arg, exp } = props[1]; - addEventOpts(arg.content, exp, node); - props[1].exp = createCustomEventExpr(); - return res; -}; +const transformModel = uniCliShared.createTransformModel(uniMpCompiler.transformModel); const nodeTransforms = [uniCliShared.transformRef, transformFor, uniCliShared.transformMatchMedia]; const directiveTransforms = { diff --git a/packages/uni-mp-baidu/dist/uni.mp.esm.js b/packages/uni-mp-baidu/dist/uni.mp.esm.js index 2056a52719e7afbcc4fd0cdb31e44d7dd2f01e90..0f6455f7dc9ba4a61a10ce82f8696509cb19792e 100644 --- a/packages/uni-mp-baidu/dist/uni.mp.esm.js +++ b/packages/uni-mp-baidu/dist/uni.mp.esm.js @@ -132,6 +132,7 @@ function createEmitFn(oldEmit, ctx) { const scope = ctx.$scope; if (scope && event) { const detail = { __args__: args }; + // 百度小程序,快手小程序,自定义组件不能绑定动态事件 { detail.__ins__ = scope; } @@ -406,6 +407,32 @@ function findVmByVueId(instance, vuePid) { return parentVm; } } +} +const EVENT_OPTS = 'eO'; +/** + * 需要搭配: + * ./componentInstance/index.ts:24 triggerEvent 时传递 __ins__ + * ./componentProps.ts:49 增加 properties eO + * @param this + * @param event + * @returns + */ +function handleEvent(event) { + const { type, target: { dataset }, detail: { __ins__ }, } = event; + let methodName = type; + // 快手小程序的 __l 方法也会走此处逻辑,但没有 __ins__ + if (__ins__) { + // 自定义事件,通过 triggerEvent 传递 __ins__ + methodName = (__ins__.properties[EVENT_OPTS] || {})[type]; + } + else if (dataset && dataset[EVENT_OPTS]) { + // 快手小程序 input 等内置组件的 input 事件也会走此逻辑,所以从 dataset 中读取 + methodName = dataset[EVENT_OPTS][type]; + } + if (!this[methodName]) { + return console.warn(type + ' not found'); + } + this[methodName](event); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; @@ -890,15 +917,7 @@ function parse$1(componentOptions) { }; delete methods.__l; // 百度小程序自定义组件,不支持绑定动态事件,故由 __e 分发 - methods.__e = handleCustomEvent; -} -function handleCustomEvent(event) { - const { type, detail: { __ins__ }, } = event; - const methodName = (__ins__.properties.eO || {})[type]; - if (!methodName) { - return console.warn(type + ' not found'); - } - this[methodName](event); + methods.__e = handleEvent; } var parseComponentOptions = /*#__PURE__*/Object.freeze({ diff --git a/packages/uni-mp-baidu/src/compiler/transforms/vModel.ts b/packages/uni-mp-baidu/src/compiler/transforms/vModel.ts index 2a7b3fc91d22f0809241c64a947c80b0c236ab7a..4bce65334ebcb5c988973c7c03ad5157089aa1a6 100644 --- a/packages/uni-mp-baidu/src/compiler/transforms/vModel.ts +++ b/packages/uni-mp-baidu/src/compiler/transforms/vModel.ts @@ -1,38 +1,6 @@ -import { isUserComponent } from '@dcloudio/uni-cli-shared' -import { - DirectiveNode, - DirectiveTransform, - SimpleExpressionNode, - transformModel as baseTransformModel, -} from '@dcloudio/uni-mp-compiler' -import { ComponentNode } from '@vue/compiler-core' -import { addEventOpts, createCustomEventExpr } from './vOn' +import { createTransformModel } from '@dcloudio/uni-cli-shared' +import { transformModel as baseTransformModel } from '@dcloudio/uni-mp-compiler' /** * 百度小程序的自定义组件,不支持动态事件绑定,故 v-model 也需要调整 - * @param dir - * @param node - * @param context - * @param augmentor - * @returns */ -export const transformModel: DirectiveTransform = ( - dir, - node, - context, - augmentor -) => { - const res = baseTransformModel(dir, node, context, augmentor) - const props = res.props as unknown as DirectiveNode[] - if (props.length < 2 || !isUserComponent(node, context)) { - return res - } - const { arg, exp } = props[1] - - addEventOpts( - (arg as SimpleExpressionNode).content, - exp as SimpleExpressionNode, - node as ComponentNode - ) - props[1].exp = createCustomEventExpr() - return res -} +export const transformModel = createTransformModel(baseTransformModel) diff --git a/packages/uni-mp-baidu/src/compiler/transforms/vOn.ts b/packages/uni-mp-baidu/src/compiler/transforms/vOn.ts index 821dd514d5958eaf142147ae268c79801f4cd12a..cb78dcf09b3619c9170ea77e0eeec2b3418d26d6 100644 --- a/packages/uni-mp-baidu/src/compiler/transforms/vOn.ts +++ b/packages/uni-mp-baidu/src/compiler/transforms/vOn.ts @@ -1,113 +1,6 @@ -import { isUserComponent } from '@dcloudio/uni-cli-shared' -import { - DirectiveTransform, - transformOn as baseTransformOn, -} from '@dcloudio/uni-mp-compiler' -import { - ExpressionNode, - DirectiveNode, - findProp, - isStaticExp, - NodeTypes, - locStub, - createSimpleExpression, - createCompoundExpression, - CompoundExpressionNode, - ComponentNode, -} from '@vue/compiler-core' +import { createTransformOn } from '@dcloudio/uni-cli-shared' +import { transformOn as baseTransformOn } from '@dcloudio/uni-mp-compiler' /** - * 百度小程序的自定义组件,不支持动态事件绑定,故转换为静态事件 + 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 - } - const value = res.props[0].value as ExpressionNode - res.props[0].value = createCustomEventExpr() - addEventOpts(arg.content, value, node) - return res -} - -export function createCustomEventExpr() { - return createSimpleExpression('__e', true) -} - -export function addEventOpts( - event: string, - value: ExpressionNode, - node: ComponentNode -) { - const opts = findProp(node, ATTR_DATA_EVENT_OPTS, true) as DirectiveNode - if (!opts) { - node.props.push(createDataEventOptsProp(event, value)) - } else { - const children = (opts.exp as CompoundExpressionNode).children - children.splice( - children.length - 2, - 0, - createDataEventOptsProperty(event, value) - ) - } -} - -const ATTR_DATA_EVENT_OPTS = 'eO' - -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) -} +export const transformOn = createTransformOn(baseTransformOn) diff --git a/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts b/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts index 8a72b0e1698c3edc12a1891cfe5f2710b6efd8ea..7ecd10cc2ebe41c0bce2bbf22cf836b72d1abe51 100644 --- a/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts +++ b/packages/uni-mp-baidu/src/runtime/parseComponentOptions.ts @@ -4,12 +4,13 @@ import { MPComponentInstance, MPComponentOptions, initMocks, + handleEvent, } from '@dcloudio/uni-mp-core' import { ON_LOAD, ON_SHOW } from '@dcloudio/uni-shared' import { fixSetDataStart, fixSetDataEnd, -} from '../../../uni-mp-weixin/src/runtime/fixSetData' +} from '@dcloudio/uni-mp-weixin/src/runtime/fixSetData' export { handleLink, initLifetimes } from '@dcloudio/uni-mp-weixin' @@ -84,25 +85,5 @@ export function parse(componentOptions: MPComponentOptions) { } delete methods.__l // 百度小程序自定义组件,不支持绑定动态事件,故由 __e 分发 - methods.__e = handleCustomEvent -} - -function handleCustomEvent( - this: MPComponentInstance, - event: { - type: string - detail: { - __ins__: MPComponentInstance & { eO: Record } - } - } -) { - const { - type, - detail: { __ins__ }, - } = event - const methodName = (__ins__.properties.eO || {})[type] - if (!methodName) { - return console.warn(type + ' not found') - } - ;(this as any)[methodName](event) + methods.__e = handleEvent } diff --git a/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts b/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts index fa45c33c0f2fdaa6a0cd273a4c5b6352287d309a..29d12ee370276edcdd580cae76124bbbefbc7f88 100644 --- a/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts @@ -2,7 +2,6 @@ import { ElementNode } from '@vue/compiler-core' import { compile } from '../src' import { MPErrorCodes } from '../src/errors' import { CompilerOptions } from '../src/options' -import { assert } from './testUtils' function parseWithVOn(template: string, options: CompilerOptions = {}) { const { ast } = compile(template, { @@ -18,22 +17,6 @@ function parseWithVOn(template: string, options: CompilerOptions = {}) { } describe('compiler(mp): transform v-on', () => { - test('lazy element', () => { - assert( - ``, - ``, - `(_ctx, _cache) => { - return {} -}` - ) - assert( - ``, - ``, - `(_ctx, _cache) => { - return { a: _o(_ctx.ready) } -}` - ) - }) test('should error if dynamic event', () => { const onError = jest.fn() parseWithVOn(`
`, { onError }) diff --git a/packages/uni-mp-compiler/src/compile.ts b/packages/uni-mp-compiler/src/compile.ts index 736bd152d037394fa747fa90e40e6f01810ebe48..a84f94b71241b6c8af53aeb0330507cb704faceb 100644 --- a/packages/uni-mp-compiler/src/compile.ts +++ b/packages/uni-mp-compiler/src/compile.ts @@ -93,6 +93,7 @@ export function baseCompile(template: string, options: CompilerOptions = {}) { emitFile, event, slot, + lazyElement, } = options.miniProgram genTemplate(ast, { class: clazz, @@ -102,6 +103,7 @@ export function baseCompile(template: string, options: CompilerOptions = {}) { emitFile, event, slot, + lazyElement, }) } diff --git a/packages/uni-mp-compiler/src/template/codegen.ts b/packages/uni-mp-compiler/src/template/codegen.ts index dda1080d862d536c821bbdbb23995ff46115f1d0..e2c450a5944885f2a64b6240c581e1b4ecb9dc73 100644 --- a/packages/uni-mp-compiler/src/template/codegen.ts +++ b/packages/uni-mp-compiler/src/template/codegen.ts @@ -29,6 +29,7 @@ interface TemplateCodegenContext { scopeId?: string | null event: MiniProgramCompilerOptions['event'] slot: MiniProgramCompilerOptions['slot'] + lazyElement: MiniProgramCompilerOptions['lazyElement'] push(code: string): void } @@ -41,6 +42,7 @@ export function generate( emitFile, filename, directive, + lazyElement, }: TemplateCodegenOptions ) { const context: TemplateCodegenContext = { @@ -49,6 +51,7 @@ export function generate( code: '', scopeId, directive, + lazyElement, push(code) { context.code += code }, @@ -79,7 +82,7 @@ export function genNode( return genComponent(node, context) } else if (node.tagType === ElementTypes.TEMPLATE) { return genTemplate(node, context) - } else if (isLazyElement(node)) { + } else if (isLazyElement(node, context)) { return genLazyElement(node, context) } return genElement(node, context) @@ -189,12 +192,11 @@ function genComponent(node: ComponentNode, context: TemplateCodegenContext) { return genElement(node, context) } -const lazyElementMap: Record = { - editor: ['ready'], -} - -function isLazyElement(node: ElementNode) { - const events = lazyElementMap[node.tag] +function isLazyElement(node: ElementNode, context: TemplateCodegenContext) { + if (!context.lazyElement) { + return false + } + const events = context.lazyElement[node.tag] return ( events && node.props.some( diff --git a/packages/uni-mp-compiler/src/transforms/vModel.ts b/packages/uni-mp-compiler/src/transforms/vModel.ts index d6420170463e8aae3a616e42130028884fb9f528..7e765d51fdf9f9f566e86a1a6e32f292ab1190a0 100644 --- a/packages/uni-mp-compiler/src/transforms/vModel.ts +++ b/packages/uni-mp-compiler/src/transforms/vModel.ts @@ -1,4 +1,4 @@ -import { camelize } from '@vue/shared' +import { camelize, isString, isSymbol } from '@vue/shared' import { Property, transformModel as baseTransform, @@ -18,6 +18,7 @@ import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom' import { createBindDirectiveNode, createOnDirectiveNode, + ATTR_DATASET_EVENT_OPTS, } from '@dcloudio/uni-cli-shared' import { V_ON } from '../runtimeHelpers' import { genExpr } from '../codegen' @@ -103,16 +104,100 @@ function transformElementVModel( }, }) if (dirs.length === 2) { - const inputDir = findInputDirectiveNode(node.props) - if (inputDir && inputDir.exp) { - // 合并到已有的 input 事件中 - inputDir.exp = combineVOn(dirs[1].exp!, inputDir.exp, context) + // 快手小程序的 input v-model 被转换到 data-e-o 中,补充到 data-e-o 中 + const inputExp = findDatasetEventOpts(node) + if (inputExp) { + inputExp.children[2] = combineVOn( + dirs[1].exp!, + inputExp.children[2] as ExpressionNode, + context + ) dirs.length = 1 + } else { + const inputDir = findInputDirectiveNode(node.props) + if (inputDir && inputDir.exp) { + // 合并到已有的 input 事件中 + inputDir.exp = combineVOn(dirs[1].exp!, inputDir.exp, context) + dirs.length = 1 + } } } return { props: dirs } } +/** + * { + * "type": 7, + * "name": "bind", + * "loc": {}, + * "modifiers": [], + * "arg": { + * "type": 4, + * "loc": {}, + * "content": "data-e-o", + * "isStatic": true, + * "constType": 3 + * }, + * "exp": { + * "type": 8, + * "loc": {}, + * "children": ["{", { + * "type": 8, + * "loc": {}, + * "children": ["'input'", ": ", { + * "type": 8, + * "loc": {}, + * "children": ["_o(", { + * "type": 4, + * "content": "_ctx.input", + * "isStatic": false, + * "constType": 0, + * "loc": {} + * }, ")"] + * }, ","] + * }, "}"] + * } + * } + * @param node + * @returns + */ +function findDatasetEventOpts(node: ElementNode) { + const eventOptsProp = findProp( + node, + ATTR_DATASET_EVENT_OPTS, + true, + false + ) as DirectiveNode + if (!eventOptsProp) { + return + } + const { exp } = eventOptsProp + if (exp?.type !== NodeTypes.COMPOUND_EXPRESSION) { + return + } + for (let i = 0; i < exp.children.length; i++) { + const childExp = exp.children[i] + if (isSymbol(childExp) || isString(childExp)) { + continue + } + if (childExp.type !== NodeTypes.COMPOUND_EXPRESSION) { + continue + } + if (childExp.children[0] !== `'input'`) { + continue + } + const inputExp = childExp.children[2] + if ( + isSymbol(inputExp) || + isString(inputExp) || + inputExp.type !== NodeTypes.COMPOUND_EXPRESSION + ) { + continue + } + return childExp + } +} + function parseVOn(exp: ExpressionNode, context: TransformContext) { return genExpr(exp).slice(context.helperString(V_ON).length + 1, -1) } diff --git a/packages/uni-mp-core/src/index.ts b/packages/uni-mp-core/src/index.ts index e0b7c9e4be032d21ce246d5881ec9d67ef8a5ee5..5b714482fb5cb35aa75b3f53c0ed0442c012f0d9 100644 --- a/packages/uni-mp-core/src/index.ts +++ b/packages/uni-mp-core/src/index.ts @@ -29,6 +29,7 @@ export { initVueIds, initWxsCallMethods, findVmByVueId, + handleEvent, } from './runtime/util' // protocols diff --git a/packages/uni-mp-core/src/runtime/componentInstance/index.ts b/packages/uni-mp-core/src/runtime/componentInstance/index.ts index d0e9965ad157de75bc4a564569468b0371142c1e..387d8598d5aa3a6b6e64d016f23e764828e078c6 100644 --- a/packages/uni-mp-core/src/runtime/componentInstance/index.ts +++ b/packages/uni-mp-core/src/runtime/componentInstance/index.ts @@ -20,7 +20,8 @@ function createEmitFn(oldEmit: Function, ctx: Record) { const scope = ctx.$scope as MPComponentInstance if (scope && event) { const detail: Record = { __args__: args } - if (__PLATFORM__ === 'mp-baidu') { + // 百度小程序,快手小程序,自定义组件不能绑定动态事件 + if (__PLATFORM__ === 'mp-baidu' || __PLATFORM__ === 'mp-kuaishou') { detail.__ins__ = scope } scope.triggerEvent(event, detail) diff --git a/packages/uni-mp-core/src/runtime/componentProps.ts b/packages/uni-mp-core/src/runtime/componentProps.ts index c58678de2784a2913317870908ade680b72476ef..3bbd379ee184943c2eb468610fa3a3cf79b74c32 100644 --- a/packages/uni-mp-core/src/runtime/componentProps.ts +++ b/packages/uni-mp-core/src/runtime/componentProps.ts @@ -46,7 +46,7 @@ function normalizePropType(type: unknown, defaultValue: unknown) { function initDefaultProps(isBehavior: boolean = false) { const properties: Component.PropertyOption = {} if (!isBehavior) { - if (__PLATFORM__ === 'mp-baidu') { + if (__PLATFORM__ === 'mp-baidu' || __PLATFORM__ === 'mp-kuaishou') { // 百度小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息 // event-opts properties.eO = { @@ -58,12 +58,6 @@ function initDefaultProps(isBehavior: boolean = false) { type: null, // 均不指定类型,避免 property received type-uncompatible value 警告 value: '', } - if (__PLATFORM__ === 'mp-toutiao') { - // 用于字节跳动小程序模拟抽象节点 - properties.generic = { - type: Object, - } - } // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots properties.vS = { type: null, diff --git a/packages/uni-mp-core/src/runtime/util.ts b/packages/uni-mp-core/src/runtime/util.ts index 0c4cb92dbf11b8261dfcb6c8422e70cdaa765c22..9c3518ecf104ed226fad720deb2f092883d1f531 100644 --- a/packages/uni-mp-core/src/runtime/util.ts +++ b/packages/uni-mp-core/src/runtime/util.ts @@ -124,3 +124,45 @@ export function findVmByVueId( } } } + +const EVENT_OPTS = 'eO' +/** + * 需要搭配: + * ./componentInstance/index.ts:24 triggerEvent 时传递 __ins__ + * ./componentProps.ts:49 增加 properties eO + * @param this + * @param event + * @returns + */ +export function handleEvent( + this: MPComponentInstance, + event: { + type: string + target: { + dataset: Record + } + detail: { + __ins__: MPComponentInstance & { eO: Record } + } + } +) { + const { + type, + target: { dataset }, + detail: { __ins__ }, + } = event + let methodName: string = type + // 快手小程序的 __l 方法也会走此处逻辑,但没有 __ins__ + if (__ins__) { + // 自定义事件,通过 triggerEvent 传递 __ins__ + methodName = (__ins__.properties[EVENT_OPTS] || {})[type] + } else if (dataset && dataset[EVENT_OPTS]) { + // 快手小程序 input 等内置组件的 input 事件也会走此逻辑,所以从 dataset 中读取 + methodName = dataset[EVENT_OPTS][type] + } + + if (!(this as any)[methodName]) { + return console.warn(type + ' not found') + } + ;(this as any)[methodName](event) +} diff --git a/packages/uni-mp-kuaishou/__tests__/component.spec.ts b/packages/uni-mp-kuaishou/__tests__/component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c34f5d57943ec39089ecd4dae352a39be102d94e --- /dev/null +++ b/packages/uni-mp-kuaishou/__tests__/component.spec.ts @@ -0,0 +1,20 @@ +import { assert } from './testUtils' + +describe('mp-kuaishou: transform component', () => { + test('lazy element', () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return {} +}` + ) + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: _o(_ctx.change) } +}` + ) + }) +}) diff --git a/packages/uni-mp-kuaishou/__tests__/testUtils.ts b/packages/uni-mp-kuaishou/__tests__/testUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c250ca2ad7b65b61711944385d05af7a12c216c --- /dev/null +++ b/packages/uni-mp-kuaishou/__tests__/testUtils.ts @@ -0,0 +1,37 @@ +import { isNativeTag } from '@dcloudio/uni-shared' +import { compile, CompilerOptions } from '@dcloudio/uni-mp-compiler' + +import { compilerOptions, miniProgram } 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, + generatorOpts: { + concise: true, + }, + miniProgram: { + ...miniProgram, + emitFile({ source }) { + // console.log(source) + if (!options.onError) { + expect(source).toBe(templateCode) + } + return '' + }, + }, + ...compilerOptions, + ...options, + }) + if (!options.onError) { + expect(res.code).toBe(renderCode) + } +} diff --git a/packages/uni-mp-kuaishou/__tests__/vModel.spec.ts b/packages/uni-mp-kuaishou/__tests__/vModel.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d993a007e86f3cf4764785cbb9eee5aff6a8ef06 --- /dev/null +++ b/packages/uni-mp-kuaishou/__tests__/vModel.spec.ts @@ -0,0 +1,57 @@ +import { assert } from './testUtils' + +describe('mp-kuaishou: transform v-model', () => { + test(`component v-model`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'updateModelValue': _o($event => _ctx.model = $event) }, b: _ctx.model } +}` + ) + }) + test(`component v-model with cache`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'updateModelValue': _o($event => _ctx.model = $event) }, b: _ctx.model } +}`, + { + cacheHandlers: true, + } + ) + }) + test(`input,textarea v-model`, () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'input': _o($event => _ctx.model = $event.detail.value) }, b: _ctx.model } +}` + ) + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: { 'input': _o(_ctx.input) } } +}` + ) + }) + }) + 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-kuaishou/build.json b/packages/uni-mp-kuaishou/build.json index 7627da9a95802306557694a11621caf4af53e519..36be60b7a00dbbfb80796b28475b15bee74e5938 100644 --- a/packages/uni-mp-kuaishou/build.json +++ b/packages/uni-mp-kuaishou/build.json @@ -1,24 +1,41 @@ -{ - "input": { - "src/runtime/index.ts": "dist/uni.mp.esm.js", - "src/api/index.ts": "dist/uni.api.esm.js" - }, - "alias": { - "entries": [ - { - "find": "@dcloudio/uni-platform", - "replacement": "packages/uni-mp-kuaishou/src/platform/index.ts" - }, - { - "find": "@dcloudio/uni-mp-platform", - "replacement": "packages/uni-mp-core/src/platform/index.ts" - } +[ + { + "input": { + "src/compiler/index.ts": "dist/uni.compiler.js" + }, + "output": { + "format": "cjs" + }, + "external": [ + "@vue/compiler-core", + "@dcloudio/uni-shared", + "@dcloudio/uni-cli-shared", + "@dcloudio/uni-mp-vite", + "@dcloudio/uni-mp-compiler" ] }, - "replacements": { - "__GLOBAL__": "ks", - "__PLATFORM__": "\"mp-kuaishou\"", - "__PLATFORM_TITLE__": "快手小程序" - }, - "external": ["@dcloudio/uni-i18n", "@vue/shared", "vue"] -} + { + "input": { + "src/runtime/index.ts": "dist/uni.mp.esm.js", + "src/api/index.ts": "dist/uni.api.esm.js" + }, + "alias": { + "entries": [ + { + "find": "@dcloudio/uni-platform", + "replacement": "packages/uni-mp-kuaishou/src/platform/index.ts" + }, + { + "find": "@dcloudio/uni-mp-platform", + "replacement": "packages/uni-mp-core/src/platform/index.ts" + } + ] + }, + "replacements": { + "__GLOBAL__": "ks", + "__PLATFORM__": "\"mp-kuaishou\"", + "__PLATFORM_TITLE__": "快手小程序" + }, + "external": ["@dcloudio/uni-i18n", "@vue/shared", "vue"] + } +] diff --git a/packages/uni-mp-kuaishou/dist/uni.compiler.js b/packages/uni-mp-kuaishou/dist/uni.compiler.js new file mode 100644 index 0000000000000000000000000000000000000000..c4c621ef313c7d62c9259b79af19ee1426e2d034 --- /dev/null +++ b/packages/uni-mp-kuaishou/dist/uni.compiler.js @@ -0,0 +1,200 @@ +'use strict'; + +var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); +var path = require('path'); +var uniShared = require('@dcloudio/uni-shared'); +var uniCliShared = require('@dcloudio/uni-cli-shared'); +var uniMpCompiler = require('@dcloudio/uni-mp-compiler'); + +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + +var initMiniProgramPlugin__default = /*#__PURE__*/_interopDefaultLegacy(initMiniProgramPlugin); +var path__default = /*#__PURE__*/_interopDefaultLegacy(path); + +var description = "项目配置文件"; +var packOptions = { + ignore: [ + ] +}; +var setting = { + urlCheck: false, + es6: true, + enhance: false, + postcss: true, + preloadBackgroundData: false, + minified: true, + newFeature: false, + coverView: true, + nodeModules: false, + autoAudits: false, + showShadowRootInWxmlPanel: true, + scopeDataCheck: false, + uglifyFileName: false, + checkInvalidKey: true, + checkSiteMap: true, + uploadWithSourceMap: true, + compileHotReLoad: false, + babelSetting: { + ignore: [ + ], + disablePlugins: [ + ], + outputPath: "" + }, + useIsolateContext: true, + useCompilerModule: false, + userConfirmedUseCompilerModuleSwitch: false +}; +var compileType = "miniprogram"; +var libVersion = ""; +var appid = ""; +var projectname = ""; +var debugOptions = { + hidedInDevtools: [ + ] +}; +var scripts = { +}; +var isGameTourist = false; +var simulatorPluginLibVersion = { +}; +var condition = { + search: { + current: -1, + list: [ + ] + }, + conversation: { + current: -1, + list: [ + ] + }, + game: { + current: -1, + list: [ + ] + }, + plugin: { + current: -1, + list: [ + ] + }, + gamePlugin: { + current: -1, + list: [ + ] + }, + miniprogram: { + current: -1, + list: [ + ] + } +}; +var source = { + description: description, + packOptions: packOptions, + setting: setting, + compileType: compileType, + libVersion: libVersion, + appid: appid, + projectname: projectname, + debugOptions: debugOptions, + scripts: scripts, + isGameTourist: isGameTourist, + simulatorPluginLibVersion: simulatorPluginLibVersion, + condition: condition +}; + +/** + * 快手小程序的自定义组件,不支持动态事件绑定 + */ +const transformOn = uniCliShared.createTransformOn(uniMpCompiler.transformOn, { + match: (name, node, context) => { + if (name === 'input' && (node.tag === 'input' || node.tag === 'textarea')) { + return true; + } + return uniCliShared.matchTransformOn(name, node, context); + }, +}); + +/** + * 快手小程序的自定义组件,不支持动态事件绑定,故 v-model 也需要调整,其中 input、textarea 也不支持 + */ +const transformModel = uniCliShared.createTransformModel(uniMpCompiler.transformModel, { + match: (node, context) => { + if (node.tag === 'input' || node.tag === 'textarea') { + return true; + } + return uniCliShared.matchTransformModel(node, context); + }, +}); + +const nodeTransforms = [uniCliShared.transformRef, uniCliShared.transformComponentLink]; +const directiveTransforms = { + on: transformOn, + model: transformModel, +}; +const compilerOptions = { + isNativeTag: uniShared.isNativeTag, + isCustomElement: uniShared.isCustomElement, + nodeTransforms, + directiveTransforms, +}; +const miniProgram = { + class: { + array: false, + }, + slot: { + fallbackContent: false, + dynamicSlotNames: false, + }, + directive: 'ks:', + lazyElement: { + switch: ['change'], + }, +}; +const projectConfigFilename = 'project.config.json'; +const options = { + vite: { + inject: { + uni: [path__default["default"].resolve(__dirname, 'uni.api.esm.js'), 'default'], + }, + alias: { + 'uni-mp-runtime': path__default["default"].resolve(__dirname, 'uni.mp.esm.js'), + }, + copyOptions: { + assets: ['kscomponents'], + }, + }, + global: 'ks', + app: { + darkmode: false, + subpackages: true, + }, + project: { + filename: projectConfigFilename, + source, + }, + template: Object.assign(Object.assign({}, miniProgram), { filter: undefined, extname: '.ksml', compilerOptions }), + style: { + extname: '.css', + }, +}; + +const uniMiniProgramKuaishouPlugin = { + name: 'vite:uni-mp-kuaishou', + config() { + return { + define: { + __VUE_CREATED_DEFERRED__: false, + }, + build: { + // css 中不支持引用本地资源 + assetsInlineLimit: 40 * 1024, // 40kb + }, + }; + }, +}; +var index = [uniMiniProgramKuaishouPlugin, ...initMiniProgramPlugin__default["default"](options)]; + +module.exports = index; diff --git a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js index cdd02af93ce375f5cf985b3836eb4cbebe6a2723..84d888fcfe14985505a93dd17327e2f89f91d55c 100644 --- a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js +++ b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js @@ -132,6 +132,10 @@ function createEmitFn(oldEmit, ctx) { const scope = ctx.$scope; if (scope && event) { const detail = { __args__: args }; + // 百度小程序,快手小程序,自定义组件不能绑定动态事件 + { + detail.__ins__ = scope; + } scope.triggerEvent(event, detail); } return oldEmit.apply(this, [event, ...args]); @@ -403,6 +407,32 @@ function findVmByVueId(instance, vuePid) { return parentVm; } } +} +const EVENT_OPTS = 'eO'; +/** + * 需要搭配: + * ./componentInstance/index.ts:24 triggerEvent 时传递 __ins__ + * ./componentProps.ts:49 增加 properties eO + * @param this + * @param event + * @returns + */ +function handleEvent(event) { + const { type, target: { dataset }, detail: { __ins__ }, } = event; + let methodName = type; + // 快手小程序的 __l 方法也会走此处逻辑,但没有 __ins__ + if (__ins__) { + // 自定义事件,通过 triggerEvent 传递 __ins__ + methodName = (__ins__.properties[EVENT_OPTS] || {})[type]; + } + else if (dataset && dataset[EVENT_OPTS]) { + // 快手小程序 input 等内置组件的 input 事件也会走此逻辑,所以从 dataset 中读取 + methodName = dataset[EVENT_OPTS][type]; + } + if (!this[methodName]) { + return console.warn(type + ' not found'); + } + this[methodName](event); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; @@ -427,6 +457,14 @@ function normalizePropType(type, defaultValue) { function initDefaultProps(isBehavior = false) { const properties = {}; if (!isBehavior) { + { + // 百度小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息 + // event-opts + properties.eO = { + type: null, + value: '', + }; + } properties.vI = { type: null, value: '', @@ -764,12 +802,13 @@ var baseParseOptions = /*#__PURE__*/Object.freeze({ initLifetimes: initLifetimes }); -const createApp = initCreateApp(); -const createPage = initCreatePage(baseParseOptions); -const createComponent$1 = initCreateComponent(baseParseOptions); -wx.createApp = global.createApp = createApp; -wx.createPage = createPage; -wx.createComponent = createComponent$1; +function parse$1(pageOptions) { + // 快手小程序自定义组件,不支持绑定动态事件,故由 __e 分发 + pageOptions.methods.__e = handleEvent; +} +var parsePageOptions = extend({}, baseParseOptions, { + parse: parse$1, +}); /** * 用于延迟调用 setData @@ -823,11 +862,15 @@ function parse(componentOptions) { } oldAttached.call(this); }; + // 快手小程序自定义组件,不支持绑定动态事件,故由 __e 分发 + componentOptions.methods.__e = handleEvent; } var parseComponentOptions = extend({}, baseParseOptions, { parse, }); +const createApp = initCreateApp(); +const createPage = initCreatePage(parsePageOptions); const createComponent = initCreateComponent(parseComponentOptions); ks.EventChannel = EventChannel; ks.createApp = global.createApp = createApp; diff --git a/packages/uni-mp-kuaishou/package.json b/packages/uni-mp-kuaishou/package.json index b715d5176951a92d11dd26d1e445980ec5fee861..550e4c9c78b6b38255cd6eb5302eb9ec634b341a 100644 --- a/packages/uni-mp-kuaishou/package.json +++ b/packages/uni-mp-kuaishou/package.json @@ -14,7 +14,9 @@ "license": "Apache-2.0", "uni-app": { "name": "mp-kuaishou", - "title": "快手小程序" + "title": "快手小程序", + "apply": "mp-kuaishou", + "main": "dist/uni.compiler.js" }, "gitHead": "7bcc3303c15141d377645a4995ce186f10ed6b78" } diff --git a/packages/uni-mp-kuaishou/src/compiler/index.ts b/packages/uni-mp-kuaishou/src/compiler/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0204187cfd418badca2fadc526a8bec28dd6a8ca --- /dev/null +++ b/packages/uni-mp-kuaishou/src/compiler/index.ts @@ -0,0 +1,21 @@ +import { Plugin } from 'vite' + +import initMiniProgramPlugin from '@dcloudio/uni-mp-vite' +import { options } from './options' + +const uniMiniProgramKuaishouPlugin: Plugin = { + name: 'vite:uni-mp-kuaishou', + config() { + return { + define: { + __VUE_CREATED_DEFERRED__: false, + }, + build: { + // css 中不支持引用本地资源 + assetsInlineLimit: 40 * 1024, // 40kb + }, + } + }, +} + +export default [uniMiniProgramKuaishouPlugin, ...initMiniProgramPlugin(options)] diff --git a/packages/uni-mp-kuaishou/src/compiler/options.ts b/packages/uni-mp-kuaishou/src/compiler/options.ts new file mode 100644 index 0000000000000000000000000000000000000000..afc3e79a2296dca3fad705fdfe20c12eff9235fd --- /dev/null +++ b/packages/uni-mp-kuaishou/src/compiler/options.ts @@ -0,0 +1,73 @@ +import path from 'path' +import type { CompilerOptions } from '@vue/compiler-core' +import { isNativeTag, isCustomElement } from '@dcloudio/uni-shared' +import { + MiniProgramCompilerOptions, + transformComponentLink, + transformRef, +} from '@dcloudio/uni-cli-shared' +import { UniMiniProgramPluginOptions } from '@dcloudio/uni-mp-vite' + +import source from './project.config.json' +import { transformOn } from './transforms/vOn' +import { transformModel } from './transforms/vModel' + +const nodeTransforms = [transformRef, transformComponentLink] +const directiveTransforms = { + on: transformOn, + model: transformModel, +} +export const compilerOptions: CompilerOptions = { + isNativeTag, + isCustomElement, + nodeTransforms, + directiveTransforms, +} + +export const miniProgram: MiniProgramCompilerOptions = { + class: { + array: false, + }, + slot: { + fallbackContent: false, + dynamicSlotNames: false, + }, + directive: 'ks:', + lazyElement: { + switch: ['change'], + }, +} +const projectConfigFilename = 'project.config.json' + +export const options: UniMiniProgramPluginOptions = { + vite: { + inject: { + uni: [path.resolve(__dirname, 'uni.api.esm.js'), 'default'], + }, + alias: { + 'uni-mp-runtime': path.resolve(__dirname, 'uni.mp.esm.js'), + }, + copyOptions: { + assets: ['kscomponents'], + }, + }, + global: 'ks', + app: { + darkmode: false, + subpackages: true, + }, + project: { + filename: projectConfigFilename, + source, + }, + template: { + /* eslint-disable no-restricted-syntax */ + ...miniProgram, + filter: undefined, + extname: '.ksml', + compilerOptions, + }, + style: { + extname: '.css', + }, +} diff --git a/packages/uni-mp-kuaishou/src/compiler/project.config.json b/packages/uni-mp-kuaishou/src/compiler/project.config.json new file mode 100644 index 0000000000000000000000000000000000000000..d16751515e0079713ce61df2a889ea78260b3da1 --- /dev/null +++ b/packages/uni-mp-kuaishou/src/compiler/project.config.json @@ -0,0 +1,69 @@ +{ + "description": "项目配置文件", + "packOptions": { + "ignore": [] + }, + "setting": { + "urlCheck": false, + "es6": true, + "enhance": false, + "postcss": true, + "preloadBackgroundData": false, + "minified": true, + "newFeature": false, + "coverView": true, + "nodeModules": false, + "autoAudits": false, + "showShadowRootInWxmlPanel": true, + "scopeDataCheck": false, + "uglifyFileName": false, + "checkInvalidKey": true, + "checkSiteMap": true, + "uploadWithSourceMap": true, + "compileHotReLoad": false, + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "useIsolateContext": true, + "useCompilerModule": false, + "userConfirmedUseCompilerModuleSwitch": false + }, + "compileType": "miniprogram", + "libVersion": "", + "appid": "", + "projectname": "", + "debugOptions": { + "hidedInDevtools": [] + }, + "scripts": {}, + "isGameTourist": false, + "simulatorPluginLibVersion": {}, + "condition": { + "search": { + "current": -1, + "list": [] + }, + "conversation": { + "current": -1, + "list": [] + }, + "game": { + "current": -1, + "list": [] + }, + "plugin": { + "current": -1, + "list": [] + }, + "gamePlugin": { + "current": -1, + "list": [] + }, + "miniprogram": { + "current": -1, + "list": [] + } + } +} diff --git a/packages/uni-mp-kuaishou/src/compiler/transforms/vModel.ts b/packages/uni-mp-kuaishou/src/compiler/transforms/vModel.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f49b6a1db595f229da3154a4a432940303c110b --- /dev/null +++ b/packages/uni-mp-kuaishou/src/compiler/transforms/vModel.ts @@ -0,0 +1,16 @@ +import { + createTransformModel, + matchTransformModel, +} from '@dcloudio/uni-cli-shared' +import { transformModel as baseTransformModel } from '@dcloudio/uni-mp-compiler' +/** + * 快手小程序的自定义组件,不支持动态事件绑定,故 v-model 也需要调整,其中 input、textarea 也不支持 + */ +export const transformModel = createTransformModel(baseTransformModel, { + match: (node, context) => { + if (node.tag === 'input' || node.tag === 'textarea') { + return true + } + return matchTransformModel(node, context) + }, +}) diff --git a/packages/uni-mp-kuaishou/src/compiler/transforms/vOn.ts b/packages/uni-mp-kuaishou/src/compiler/transforms/vOn.ts new file mode 100644 index 0000000000000000000000000000000000000000..37f63dd8c4c28af29763bc79ed19cf3b046808dd --- /dev/null +++ b/packages/uni-mp-kuaishou/src/compiler/transforms/vOn.ts @@ -0,0 +1,13 @@ +import { createTransformOn, matchTransformOn } from '@dcloudio/uni-cli-shared' +import { transformOn as baseTransformOn } from '@dcloudio/uni-mp-compiler' +/** + * 快手小程序的自定义组件,不支持动态事件绑定 + */ +export const transformOn = createTransformOn(baseTransformOn, { + match: (name, node, context) => { + if (name === 'input' && (node.tag === 'input' || node.tag === 'textarea')) { + return true + } + return matchTransformOn(name, node, context) + }, +}) diff --git a/packages/uni-mp-kuaishou/src/runtime/index.ts b/packages/uni-mp-kuaishou/src/runtime/index.ts index 5a92b3b64641af3ea0af949429c034cb26d7ea52..ec33897600626ddeb4a5d027bc8cf5cf7705ef85 100644 --- a/packages/uni-mp-kuaishou/src/runtime/index.ts +++ b/packages/uni-mp-kuaishou/src/runtime/index.ts @@ -1,10 +1,16 @@ import { EventChannel } from '@dcloudio/uni-shared' -import { initCreateComponent } from '@dcloudio/uni-mp-core' -import { createApp, createPage } from '@dcloudio/uni-mp-weixin/src/runtime' +import { + initCreateApp, + initCreatePage, + initCreateComponent, +} from '@dcloudio/uni-mp-core' +import '@dcloudio/uni-mp-polyfill' +import parsePageOptions from './parsePageOptions' import parseComponentOptions from './parseComponentOptions' -export { createApp, createPage } from '@dcloudio/uni-mp-weixin/src/runtime' +export const createApp = initCreateApp() +export const createPage = initCreatePage(parsePageOptions) export const createComponent = initCreateComponent(parseComponentOptions) ;(ks as any).EventChannel = EventChannel ;(ks as any).createApp = (global as any).createApp = createApp diff --git a/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts b/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts index a6edb663cb70e3e8fddd1b13e927e0bb6ce04df2..9cc9aba8f4b29596c21d27d630680406d618220e 100644 --- a/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts +++ b/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts @@ -1,5 +1,9 @@ import { extend } from '@vue/shared' -import { MPComponentInstance, MPComponentOptions } from '@dcloudio/uni-mp-core' +import { + handleEvent, + MPComponentInstance, + MPComponentOptions, +} from '@dcloudio/uni-mp-core' import * as baseParseOptions from '@dcloudio/uni-mp-weixin/src/runtime/parseOptions' import { fixSetDataStart, @@ -19,6 +23,9 @@ export function parse(componentOptions: MPComponentOptions) { } oldAttached!.call(this) } + + // 快手小程序自定义组件,不支持绑定动态事件,故由 __e 分发 + componentOptions.methods!.__e = handleEvent } export default extend({}, baseParseOptions, { diff --git a/packages/uni-mp-kuaishou/src/runtime/parsePageOptions.ts b/packages/uni-mp-kuaishou/src/runtime/parsePageOptions.ts new file mode 100644 index 0000000000000000000000000000000000000000..34c460c50fe2bae970d6011ed4fa67b8b204ea6f --- /dev/null +++ b/packages/uni-mp-kuaishou/src/runtime/parsePageOptions.ts @@ -0,0 +1,12 @@ +import { extend } from '@vue/shared' +import { handleEvent, MPComponentOptions } from '@dcloudio/uni-mp-core' +import * as baseParseOptions from '@dcloudio/uni-mp-weixin/src/runtime/parseOptions' + +export function parse(pageOptions: MPComponentOptions) { + // 快手小程序自定义组件,不支持绑定动态事件,故由 __e 分发 + pageOptions.methods!.__e = handleEvent +} + +export default extend({}, baseParseOptions, { + parse, +}) diff --git a/packages/uni-mp-toutiao/dist/uni.mp.esm.js b/packages/uni-mp-toutiao/dist/uni.mp.esm.js index 1644ddaeb6a728ce7814ef9e44052fcda6d16f59..d6cbce9a92c51ad5ac763efe9893ec984c0f040f 100644 --- a/packages/uni-mp-toutiao/dist/uni.mp.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.mp.esm.js @@ -434,12 +434,6 @@ function initDefaultProps(isBehavior = false) { type: null, value: '', }; - { - // 用于字节跳动小程序模拟抽象节点 - properties.generic = { - type: Object, - }; - } // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots properties.vS = { type: null, diff --git a/packages/uni-mp-vite/src/plugin/index.ts b/packages/uni-mp-vite/src/plugin/index.ts index 3771a837851a88734e48a05cc5f97b93f2e97f6c..2b287ae67918413bebf34ba5e05d6b3662c85714 100644 --- a/packages/uni-mp-vite/src/plugin/index.ts +++ b/packages/uni-mp-vite/src/plugin/index.ts @@ -46,6 +46,7 @@ export interface UniMiniProgramPluginOptions { event?: MiniProgramCompilerOptions['event'] class: MiniProgramCompilerOptions['class'] slot: MiniProgramCompilerOptions['slot'] + lazyElement?: MiniProgramCompilerOptions['lazyElement'] filter?: { lang: string extname: string @@ -79,6 +80,7 @@ export function uniMiniProgramPlugin( class: template.class, filter: template.filter ? { lang: template.filter.lang } : undefined, directive: template.directive, + lazyElement: template.lazyElement, emitFile, slot: template.slot, }, diff --git a/packages/uni-mp-vite/src/plugin/template.ts b/packages/uni-mp-vite/src/plugin/template.ts index e1e9c0764c4d9e87cbe22729967aed80f41bae47..ee75e78e1f52f53c2611594b702c83546ef566b2 100644 --- a/packages/uni-mp-vite/src/plugin/template.ts +++ b/packages/uni-mp-vite/src/plugin/template.ts @@ -57,7 +57,7 @@ export function getFilterFiles( export function getTemplateFiles( template: UniMiniProgramPluginOptions['template'] ) { - const files = findMiniProgramTemplateFiles(template.filter!.generate) + const files = findMiniProgramTemplateFiles(template.filter?.generate) clearMiniProgramTemplateFiles() return files } diff --git a/packages/uni-mp-weixin/__tests__/component.spec.ts b/packages/uni-mp-weixin/__tests__/component.spec.ts index 5b528dfded8e3f2ad7f11e8b85c0a466b0c8449d..3888da819a2010d23901c5e32e13eb905978320e 100644 --- a/packages/uni-mp-weixin/__tests__/component.spec.ts +++ b/packages/uni-mp-weixin/__tests__/component.spec.ts @@ -1,6 +1,22 @@ import { assert } from './testUtils' -describe('mp-baidu: transform component', () => { +describe('mp-weixin: transform component', () => { + test('lazy element', () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return {} +}` + ) + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: _o(_ctx.ready) } +}` + ) + }) test(`match-media`, () => { assert( ``, diff --git a/packages/uni-mp-weixin/dist/uni.compiler.js b/packages/uni-mp-weixin/dist/uni.compiler.js index 40b3c5a6d5c01390aec45fb618cb42becb26e4ab..9dd0055929ebef8e18a7a0b92b8093ab2cede073 100644 --- a/packages/uni-mp-weixin/dist/uni.compiler.js +++ b/packages/uni-mp-weixin/dist/uni.compiler.js @@ -16,7 +16,7 @@ var packOptions = { ] }; var setting = { - urlCheck: true, + urlCheck: false, es6: true, postcss: false, minified: false, @@ -76,6 +76,9 @@ const miniProgram = { dynamicSlotNames: true, }, directive: 'wx:', + lazyElement: { + editor: ['ready'], + }, }; const projectConfigFilename = 'project.config.json'; const options = { diff --git a/packages/uni-mp-weixin/src/compiler/options.ts b/packages/uni-mp-weixin/src/compiler/options.ts index 32023911fc5dde27f2b8e8b12a6c1b15106996d0..7cd1e819376dd16f9e78d6abd5524d8995d84cd4 100644 --- a/packages/uni-mp-weixin/src/compiler/options.ts +++ b/packages/uni-mp-weixin/src/compiler/options.ts @@ -33,6 +33,9 @@ export const miniProgram: MiniProgramCompilerOptions = { dynamicSlotNames: true, }, directive: 'wx:', + lazyElement: { + editor: ['ready'], + }, } const projectConfigFilename = 'project.config.json' diff --git a/packages/uni-mp-weixin/src/compiler/project.config.json b/packages/uni-mp-weixin/src/compiler/project.config.json index 1c7a51297f58ef6773b01783bbea74ca36c9a721..fa0805180b2f1ede6545db4da3e9f044447fad81 100644 --- a/packages/uni-mp-weixin/src/compiler/project.config.json +++ b/packages/uni-mp-weixin/src/compiler/project.config.json @@ -4,7 +4,7 @@ "ignore": [] }, "setting": { - "urlCheck": true, + "urlCheck": false, "es6": true, "postcss": false, "minified": false, diff --git a/packages/uni-stat/dist/uni-stat.cjs.js b/packages/uni-stat/dist/uni-stat.cjs.js index 36c3e592c5bed5e70b2ad3f9a26f557b8e7f1b7f..2669cd911fecfd55c6ab1de92ea18a13a1ca1514 100644 --- a/packages/uni-stat/dist/uni-stat.cjs.js +++ b/packages/uni-stat/dist/uni-stat.cjs.js @@ -1,6 +1,6 @@ 'use strict'; -var version = "3.0.0-alpha-3021020211027001"; +var version = "3.0.0-alpha-3021220211102002"; const STAT_VERSION = version; const STAT_URL = 'https://tongji.dcloud.io/uni/stat'; diff --git a/packages/uni-stat/dist/uni-stat.es.js b/packages/uni-stat/dist/uni-stat.es.js index 4138546a068f140f04d0af270287d03a1df0dc33..68e4bb88857c3e1ee0dfaa038c77cc13a1f43fcc 100644 --- a/packages/uni-stat/dist/uni-stat.es.js +++ b/packages/uni-stat/dist/uni-stat.es.js @@ -1,4 +1,4 @@ -var version = "3.0.0-alpha-3021020211027001"; +var version = "3.0.0-alpha-3021220211102002"; const STAT_VERSION = version; const STAT_URL = 'https://tongji.dcloud.io/uni/stat';