From 1955ddc05607bfa3043e7ab5e8e643903e014d1d Mon Sep 17 00:00:00 2001 From: meixg Date: Mon, 23 May 2022 17:49:51 +0800 Subject: [PATCH] feat: simplify the template component's rendering function --- src/compilers/renderer-compiler.ts | 84 ++++++++++++++++++- src/models/component-info.ts | 5 +- .../component.js | 54 ++++++++++++ .../data.json | 2 + .../expected.html | 1 + .../ssr-spec.ts | 12 +++ 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 test/cases/provide-class-template-component/component.js create mode 100644 test/cases/provide-class-template-component/data.json create mode 100644 test/cases/provide-class-template-component/expected.html create mode 100644 test/cases/provide-class-template-component/ssr-spec.ts diff --git a/src/compilers/renderer-compiler.ts b/src/compilers/renderer-compiler.ts index 9fc39fb7..ebf16527 100644 --- a/src/compilers/renderer-compiler.ts +++ b/src/compilers/renderer-compiler.ts @@ -39,7 +39,9 @@ export class RendererCompiler { DEF('...info') ] const fn = new FunctionDefinition(this.options.functionName || '', args, - this.compileComponentRendererBody(componentInfo) + componentInfo.componentType === 'template' + ? this.compileTemplateComponentRendererBody(componentInfo) + : this.compileComponentRendererBody(componentInfo) ) mergeLiteralAdd(fn) return fn @@ -132,6 +134,68 @@ export class RendererCompiler { return body } + private compileTemplateComponentRendererBody (info: ComponentInfo) { + const body = [] + // 没有 ANode 的组件,比如 load-success 样例 + if (!info.root) { + body.push(RETURN(L(''))) + return body + } + + // 兼容多参数的情况 + body.push(new If( + new BinaryExpression( + BINARY(I('info'), '.', I('length')), + '===', + L(1) + ), + [ASSIGN(I('info'), BINARY( + BINARY(I('info'), '[]', L(0)), + '||', + L({}) + ))] + )) + body.push(new Else([ + ASSIGN(I('info'), new MapLiteral([ + [I('noDataOutput'), BINARY(I('info'), '[]', L(1))], + [I('parentCtx'), BINARY(I('info'), '[]', L(2))], + [I('slots'), BINARY(I('info'), '[]', L(4))] + ])) + ])) + + // get params from info + body.push(createDefineWithDefaultValue('noDataOutput', BINARY(I('info'), '.', I('noDataOutput')), L(false))) + body.push(createDefineWithDefaultValue('parentCtx', BINARY(I('info'), '.', I('parentCtx')), NULL)) + body.push(createDefineWithDefaultValue('slots', BINARY(I('info'), '.', I('slots')), EMPTY_MAP)) + + // helper + body.push(new ImportHelper('_')) + + // instance preraration + if (info.hasMethod('initData')) { + if (this.options.useProvidedComponentClass) { + body.push(STATEMENT(new CreateComponentPrototype(info))) + } + // context + body.push(this.compileGenInstance(info)) + body.push(...this.compileTemplateComponentContext()) + body.push(...this.emitInitData()) + } else { + body.push(DEF('instance', I('{}'))) + body.push(...this.compileTemplateComponentContext()) + } + + body.push(DEF('html', L(''))) + body.push(ASSIGN(I('parentCtx'), I('ctx'))) + const aNodeCompiler = new ANodeCompiler( + info, !!this.options.ssrOnly, this.id, this.options.useProvidedComponentClass + ) + body.push(...aNodeCompiler.compile(info.root, true)) + + body.push(RETURN(I('html'))) + return body + } + private compileGenInstance (info: ComponentInfo) { return DEF('instance', new CreateComponentInstance(info)) } @@ -185,6 +249,24 @@ export class RendererCompiler { ] } + private compileTemplateComponentContext () { + return [ + ASSIGN( + BINARY(I('instance'), '.', I('sourceSlots')), + new FunctionCall( + BINARY(I('_'), '.', I('mergeChildSlots')), + [I('slots')] + ) + ), + DEF('ctx', new MapLiteral([ + I('instance'), + I('slots'), + I('data'), + I('parentCtx') + ])) + ] + } + /** * 产出 initData() 的函数调用 * diff --git a/src/models/component-info.ts b/src/models/component-info.ts index 51077a83..907e3347 100644 --- a/src/models/component-info.ts +++ b/src/models/component-info.ts @@ -33,9 +33,10 @@ export type ComponentType = 'normal' | 'template' * 所有类型的 ComponentInfo,都需要实现如下接口 */ export interface ComponentInfo { - id: string, - root: ANode, + id: string + root: ANode childComponents: Map + componentType: ComponentType hasMethod (name: string): boolean getComputedNames (): string[] getFilterNames (): string[] diff --git a/test/cases/provide-class-template-component/component.js b/test/cases/provide-class-template-component/component.js new file mode 100644 index 00000000..5d9d97e6 --- /dev/null +++ b/test/cases/provide-class-template-component/component.js @@ -0,0 +1,54 @@ +const san = require('san') +const List = san.defineTemplateComponent({ + initData () { + return { + text: 'child' + } + }, + template: '
{{ text }}
' +}) + +const CompB = san.defineTemplateComponent({ + initData () { + return { + text: 'comp b' + } + }, + template: '
{{ text }}
' +}) +const CompA = san.defineComponent({ + components: { + 'x-l': CompB + }, + initData () { + return { + text: 'component a' + } + }, + template: '
{{ text }}
' +}) + +const MyComponent = san.defineComponent({ + components: { + 'x-l': List, + 'x-g': san.createComponentLoader({ + load: () => { + return List + }, + placeholder: CompA + }) + }, + initData () { + return { + c: 'x-l' + } + }, + trimWhitespace: 'all', + template: `
+
+ + +
` +}) + +exports = module.exports = MyComponent diff --git a/test/cases/provide-class-template-component/data.json b/test/cases/provide-class-template-component/data.json new file mode 100644 index 00000000..7a73a41b --- /dev/null +++ b/test/cases/provide-class-template-component/data.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/test/cases/provide-class-template-component/expected.html b/test/cases/provide-class-template-component/expected.html new file mode 100644 index 00000000..84d3991f --- /dev/null +++ b/test/cases/provide-class-template-component/expected.html @@ -0,0 +1 @@ +
child
child
component a
comp b
\ No newline at end of file diff --git a/test/cases/provide-class-template-component/ssr-spec.ts b/test/cases/provide-class-template-component/ssr-spec.ts new file mode 100644 index 00000000..55ac5360 --- /dev/null +++ b/test/cases/provide-class-template-component/ssr-spec.ts @@ -0,0 +1,12 @@ +import type { SsrSpecConfig } from '../../e2e.spec' + +export default { + enabled: { + jssrc: false, + comsrc: true, + comrdr: false + }, + compileOptions: { + useProvidedComponentClass: true + } +} as SsrSpecConfig