From 0108361410bb0cee9761d2a2f95f1e41eeb047aa Mon Sep 17 00:00:00 2001 From: chenjiajian <798095202@qq.com> Date: Fri, 24 Jul 2020 10:36:51 +0800 Subject: [PATCH 01/10] =?UTF-8?q?refactor:=20(mini):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=AB=AF=E6=A8=A1=E6=9D=BF=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 移除 mini-runner 里根据平台判断的模板逻辑,改为各平台插件自己管理这部分逻辑 * 修复支付宝小程序 picker-view 组件不生效的问题, fix #7013 --- packages/shared/package.json | 3 +- packages/shared/src/components.ts | 76 +--- packages/shared/src/index.ts | 1 + packages/shared/src/template.ts | 370 ++++++++++++++++++ packages/taro-cli/src/presets/index.ts | 6 +- .../taro-cli/src/presets/platforms/alipay.ts | 84 +++- packages/taro-cli/src/presets/platforms/jd.ts | 35 +- packages/taro-cli/src/presets/platforms/qq.ts | 44 ++- .../taro-cli/src/presets/platforms/swan.ts | 63 ++- packages/taro-cli/src/presets/platforms/tt.ts | 29 +- .../taro-cli/src/presets/platforms/weapp.ts | 44 ++- packages/taro-mini-runner/src/index.ts | 2 +- .../src/plugins/MiniPlugin.ts | 36 +- .../src/prerender/prerender.ts | 14 +- .../taro-mini-runner/src/template/adapters.ts | 29 -- .../taro-mini-runner/src/template/index.ts | 250 ------------ packages/taro-mini-runner/src/utils/types.ts | 5 +- .../src/webpack/build.conf.ts | 10 +- 18 files changed, 634 insertions(+), 467 deletions(-) create mode 100644 packages/shared/src/template.ts delete mode 100644 packages/taro-mini-runner/src/template/adapters.ts delete mode 100644 packages/taro-mini-runner/src/template/index.ts diff --git a/packages/shared/package.json b/packages/shared/package.json index 7cbc0d785915..863a4012f297 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -16,7 +16,8 @@ "url": "git+https://github.com/NervJS/taro.git" }, "scripts": { - "build": "rollup -c" + "build": "rollup -c", + "dev": "rollup -c -w" }, "bugs": { "url": "https://github.com/NervJS/taro/issues" diff --git a/packages/shared/src/components.ts b/packages/shared/src/components.ts index 7864c4b1ff04..728ce484d1ae 100644 --- a/packages/shared/src/components.ts +++ b/packages/shared/src/components.ts @@ -1,13 +1,11 @@ import { Shortcuts } from './shortcuts' -import { toDashed, hasOwn, toCamelCase } from './utils' -import { isBooleanStringLiteral, isNumber } from './is' -const styles = { +export const styles = { style: `i.${Shortcuts.Style}`, class: `i.${Shortcuts.Class}` } -const events = { +export const events = { bindtap: 'eh' } @@ -19,7 +17,7 @@ const touchEvents = { bindLongTap: '' } -const alipayEvents = { +export const alipayEvents = { onTap: 'eh', onTouchMove: 'eh', onTouchEnd: 'eh', @@ -27,6 +25,15 @@ const alipayEvents = { onLongTap: 'eh' } +export const specialEvents = new Set([ + 'htouchmove', + 'vtouchmove' +]) + +export function singleQuote (s: string) { + return `'${s}'` +} + const View = { 'hover-class': singleQuote('none'), 'hover-stop-propagation': 'false', @@ -377,10 +384,6 @@ const ScrollView = { ...touchEvents } -function singleQuote (s: string) { - return `'${s}'` -} - const Swiper = { 'indicator-dots': 'false', 'indicator-color': singleQuote('rgba(0, 0, 0, .3)'), @@ -448,11 +451,6 @@ const Audio = { bindEnded: '' } -const specialEvents = new Set([ - 'htouchmove', - 'vtouchmove' -]) - const Camera = { mode: singleQuote('normal'), 'device-position': singleQuote('back'), @@ -646,56 +644,6 @@ const Slot = { name: '' } -interface Components { - [key: string]: Record; -} - -export function createMiniComponents (components: Components, buildType: string) { - const result: Components = Object.create(null) - const isAlipay = buildType === 'alipay' - - for (const key in components) { - if (hasOwn(components, key)) { - const component = components[key] - const compName = toDashed(key) - const newComp: Record = Object.create(null) - for (let prop in component) { - if (hasOwn(component, prop)) { - let propValue = component[prop] - if (prop.startsWith('bind') || specialEvents.has(prop)) { - prop = isAlipay ? prop.replace('bind', 'on') : prop.toLowerCase() - if ((buildType === 'weapp' || buildType === 'qq') && prop === 'bindlongtap') { - prop = 'bindlongpress' - } - propValue = 'eh' - } else if (propValue === '') { - propValue = `i.${toCamelCase(prop)}` - } else if (isBooleanStringLiteral(propValue) || isNumber(+propValue)) { - propValue = `i.${toCamelCase(prop)} === undefined ? ${propValue} : i.${toCamelCase(prop)}` - } else { - propValue = `i.${toCamelCase(prop)} || ${propValue || singleQuote('')}` - } - - newComp[prop] = propValue - } - } - if (compName !== 'block') { - Object.assign(newComp, styles, isAlipay ? alipayEvents : events) - } - - if (compName === 'slot' || compName === 'slot-view') { - result[compName] = { - slot: 'i.name' - } - } else { - result[compName] = newComp - } - } - } - - return result -} - export const internalComponents = { View, Icon, diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 37363b1ba9e0..9c2c4cfa33c4 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -2,3 +2,4 @@ export * from './is' export { Shortcuts } from './shortcuts' export * from './components' export * from './utils' +export * from './template' diff --git a/packages/shared/src/template.ts b/packages/shared/src/template.ts new file mode 100644 index 000000000000..30e3e9f64c13 --- /dev/null +++ b/packages/shared/src/template.ts @@ -0,0 +1,370 @@ +/** + * 这里我们需要关心的小程序种类有两类: + * 1. 模板递归: + * - 支持:tmpl0 套 tmpl0 + * - 不支持:这就使得我们必须生成多级的模板,tmpl0 套 tmpl1,tmpl1 套 tmpl2…… + * 直到超过阈值 N (N = config.miniapp.baseLevel) tmplN 会套组件 comp,组件 comp 重新再套 tmpl0。 + * 2. 小程序脚本语言(wxs, sjs, etc...): + * - 支持:可以在模板使用函数缩减模板大小或提高性能(存疑),例如判断一个值是不是假值(falsy value)。 + * 将来或许会把数据序列化^1 的操作也放到小程序脚本语言里。 + * - 不支持:使用纯 *xml 语法 + * + * ^1: packages/taro-runtime/src/hydrate.ts +*/ + +import { + internalComponents, + focusComponents, + styles, + events, + specialEvents, + singleQuote +} from './components' +import { Shortcuts } from './shortcuts' +import { isBooleanStringLiteral, isNumber, isFunction } from './is' +import { toCamelCase, toDashed, hasOwn } from './utils' + +interface Component { + nodeName: string; + attributes: Attributes; +} + +interface Components { + [key: string]: Record; +} + +export interface IAdapter { + if: string; + else: string; + elseif: string; + for: string; + forItem: string; + forIndex: string; + key: string; + xs?: string, + type: string; +} + +export type Attributes = Record + +const voidElements = new Set([ + 'progress', + 'icon', + 'rich-text', + 'input', + 'textarea', + 'slider', + 'switch', + 'audio', + 'live-player', + 'live-pusher', + 'video' +]) + +const weixinAdapter: IAdapter = { + if: 'wx:if', + else: 'wx:else', + elseif: 'wx:elif', + for: 'wx:for', + forItem: 'wx:for-item', + forIndex: 'wx:for-index', + key: 'wx:key', + xs: 'wxs', + type: 'weapp' +} + +export class BaseTemplate { + protected exportExpr = 'module.exports =' + protected isSupportRecursive: boolean + protected supportXS = false + protected baseLevel = 16 + protected miniComponents: Components + protected modifyTemplateChild?: (child: string, nodeName: string) => string + protected modifyTemplateChildren?: (children: string, nodeName: string) => string + protected modifyTemplateResult?: (res: string, nodeName: string, level: number, children: string) => string + + public Adapter = weixinAdapter + + private buildAttribute (attrs: Attributes, nodeName: string): string { + return Object.keys(attrs) + .map(k => `${k}="${k.startsWith('bind') || k.startsWith('on') ? attrs[k] : `{${this.getAttrValue(attrs[k], k, nodeName)}}`}" `) + .join('') + } + + protected replacePropName (name: string, value: string) { + if (value === 'eh') return name.toLowerCase() + return name + } + + protected createMiniComponents (components: Components) { + const result: Components = Object.create(null) + + for (const key in components) { + if (hasOwn(components, key)) { + const component = components[key] + const compName = toDashed(key) + const newComp: Record = Object.create(null) + for (let prop in component) { + if (hasOwn(component, prop)) { + let propValue = component[prop] + if (prop.startsWith('bind') || specialEvents.has(prop)) { + propValue = 'eh' + } else if (propValue === '') { + propValue = `i.${toCamelCase(prop)}` + } else if (isBooleanStringLiteral(propValue) || isNumber(+propValue)) { + propValue = `i.${toCamelCase(prop)} === undefined ? ${propValue} : i.${toCamelCase(prop)}` + } else { + propValue = `i.${toCamelCase(prop)} || ${propValue || singleQuote('')}` + } + + prop = this.replacePropName(prop, propValue) + + newComp[prop] = propValue + } + } + if (compName !== 'block') { + Object.assign(newComp, styles, this.getEvents()) + } + + if (compName === 'slot' || compName === 'slot-view') { + result[compName] = { + slot: 'i.name' + } + } else { + result[compName] = newComp + } + } + } + + return result + } + + protected buildBaseTemplate () { + const Adapter = this.Adapter + + return `${this.buildXsTemplate()} +