Skip to content

Commit

Permalink
perf: reutilization of RendererCompiler
Browse files Browse the repository at this point in the history
  • Loading branch information
harttle committed Mar 27, 2020
1 parent df2c1d2 commit 8269ae1
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export { SanProject } from './models/san-project'
export { Compiler } from './models/compiler'
export { ComponentInfo } from './models/component-info'
export { ComponentTree } from './models/component-tree'
export { isComponentLoader, COMPONENT_RESERVED_MEMBERS } from './models/component'
export { COMPONENT_RESERVED_MEMBERS } from './models/component'
export { CompiledComponent } from './models/compiled-component'

let defaultProject: SanProject
Expand Down
9 changes: 4 additions & 5 deletions src/target-js/compilers/anode-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { stringLiteralize, expr } from './expr-compiler'
import { isComponentLoader } from '../../models/component'
import { ComponentTree } from '../../models/component-tree'
import { JSEmitter } from '../emitters/emitter'
import { ANode, ExprStringNode, AIfNode, AForNode, ASlotNode, ATemplateNode, ATextNode } from 'san'
Expand All @@ -16,8 +15,8 @@ export class ANodeCompiler {
private ssrIndex = 0

constructor (
private componentInfo: ComponentInfo,
private componentTree: ComponentTree,
private owner: ComponentInfo,
private root: ComponentTree,
private elementSourceCompiler: ElementCompiler,
public emitter: JSEmitter
) {
Expand All @@ -30,9 +29,9 @@ export class ANodeCompiler {
if (TypeGuards.isASlotNode(aNode)) return this.compileSlot(aNode)
if (TypeGuards.isATemplateNode(aNode)) return this.compileTemplate(aNode)

const ComponentClass = this.componentInfo.getChildComponentClass(aNode)
const ComponentClass = this.owner.getChildComponentClass(aNode)
if (ComponentClass) {
const info = this.componentTree.addComponentClass(ComponentClass)
const info = this.root.addComponentClass(ComponentClass)
return info ? this.compileComponent(aNode, info) : undefined
}
return this.compileElement(aNode)
Expand Down
6 changes: 3 additions & 3 deletions src/target-js/compilers/element-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import { ComponentTree } from '../../models/component-tree'
export class ElementCompiler {
private aNodeCompiler: ANodeCompiler
constructor (
componentInfo: ComponentInfo,
componentTree: ComponentTree,
owner: ComponentInfo,
root: ComponentTree,
private noTemplateOutput: boolean,
public emitter: JSEmitter = new JSEmitter()
) {
this.aNodeCompiler = new ANodeCompiler(componentInfo, componentTree, this, emitter)
this.aNodeCompiler = new ANodeCompiler(owner, root, this, emitter)
}

/**
Expand Down
59 changes: 27 additions & 32 deletions src/target-js/compilers/renderer-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,38 +49,27 @@ export interface CompileContext {
* Each ComponentClass is compiled to a render function
*/
export class RendererCompiler {
private elementCompiler: ElementCompiler

constructor (
private componentInfo: ComponentInfo,
noTemplateOutput: boolean,
componentTree: ComponentTree,
private noTemplateOutput: boolean,
private componentTree: ComponentTree,
public emitter = new JSEmitter()
) {
this.emitter = emitter
this.elementCompiler = new ElementCompiler(
componentInfo,
componentTree,
noTemplateOutput,
emitter
)
this.componentInfo = componentInfo
}
) {}

public compileComponentSource () {
public compileComponentSource (componentInfo: ComponentInfo) {
this.emitter.writeAnonymousFunction(RENDERER_ARGS, () => {
this.compileComponentRendererBody()
this.compileComponentRendererBody(componentInfo)
})
return this.emitter.fullText()
}

public compileComponentRenderer () {
const body = this.compileComponentRendererBody()
public compileComponentRenderer (componentInfo: ComponentInfo) {
this.emitter.clear()
const body = this.compileComponentRendererBody(componentInfo)
return new Function(...RENDERER_ARGS, body) // eslint-disable-line no-new-func
}

public compileComponentPrototypeSource () {
const component = this.componentInfo.component
public compileComponentPrototypeSource (componentInfo: ComponentInfo) {
const component = componentInfo.component
const ComponentProto = component.constructor.prototype
const builtinKeys = ['components', '_cmptReady', 'aNode', 'constructor']
const { emitter } = this
Expand Down Expand Up @@ -125,15 +114,15 @@ export class RendererCompiler {
// filters
emitter.writeLine('filters: {')
emitter.writeIndentedLines(map(
this.componentInfo.filters,
componentInfo.filters,
(fn, key) => `${key}: ${functionString(fn)}`
).join(', '))
emitter.writeLine('},')

// computed obj
emitter.writeLine('computed: {')
emitter.writeIndentedLines(map(
this.componentInfo.computed,
componentInfo.computed,
(fn, key) => `${key}: ${functionString(fn)}`
).join(', '))
emitter.writeLine('},')
Expand All @@ -142,14 +131,14 @@ export class RendererCompiler {
emitter.writeLine('tagName: "' + component.aNode.tagName + '"')
}

public compileComponentRendererBody () {
public compileComponentRendererBody (componentInfo: ComponentInfo) {
const { emitter } = this
const component = this.componentInfo.component
const component = componentInfo.component
emitter.writeLine('var _ = sanssrRuntime._;')
emitter.writeLine('var SanData = sanssrRuntime.SanData;')
emitter.writeLine('var html = "";')

this.genComponentContextCode()
this.genComponentContextCode(componentInfo)

// init data
const defaultData = (component.initData && component.initData()) || {}
Expand All @@ -176,14 +165,20 @@ export class RendererCompiler {
emitter.writeLine('if (' + expr(ifDirective.value) + ') {')
}

this.elementCompiler.tagStart(component.aNode, 'tagName')
const elementCompiler = new ElementCompiler(
componentInfo,
this.componentTree,
this.noTemplateOutput,
emitter
)
elementCompiler.tagStart(component.aNode, 'tagName')

emitter.writeIf('!noDataOutput', () => {
emitter.writeDataComment()
})

this.elementCompiler.inner(component.aNode)
this.elementCompiler.tagEnd(component.aNode, 'tagName')
elementCompiler.inner(component.aNode)
elementCompiler.tagEnd(component.aNode, 'tagName')

if (ifDirective) {
emitter.writeLine('}')
Expand All @@ -196,17 +191,17 @@ export class RendererCompiler {
/**
* 生成组件 renderer 时 ctx 对象构建的代码
*/
private genComponentContextCode () {
private genComponentContextCode (componentInfo: ComponentInfo) {
const { emitter } = this
emitter.writeBlock('var ctx =', () => {
emitter.writeLine(`instance: _.createFromPrototype(sanssrRuntime.prototype${this.componentInfo.cid}),`)
emitter.writeLine(`instance: _.createFromPrototype(sanssrRuntime.prototype${componentInfo.cid}),`)
emitter.writeLine('sourceSlots: sourceSlots,')
emitter.writeLine('data: data,')
emitter.writeLine('owner: parentCtx,')

// computedNames
emitter.nextLine('computedNames: [')
emitter.write(Object.keys(this.componentInfo.computed).map(x => `'${x}'`).join(', '))
emitter.write(Object.keys(componentInfo.computed).map(x => `'${x}'`).join(', '))
emitter.feedLine('],')

emitter.writeLine('slotRenderers: {}')
Expand Down
11 changes: 5 additions & 6 deletions src/target-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@ export default class ToJSCompiler implements Compiler {

function emitFunctionBody () {
emitRuntime(emitter, 'sanssrRuntime')
const cc = new RendererCompiler(noTemplateOutput, sanApp.componentTree, emitter)
for (const info of sanApp.componentTree.preOrder()) {
const { cid } = info
const cc = new RendererCompiler(info, noTemplateOutput, sanApp.componentTree, emitter)

emitter.writeBlock(`sanssrRuntime.prototype${cid} =`, () => {
cc.compileComponentPrototypeSource()
cc.compileComponentPrototypeSource(info)
})
emitter.nextLine(`sanssrRuntime.renderer${cid} = `)
cc.compileComponentSource()
cc.compileComponentSource(info)
}
const funcName = 'sanssrRuntime.renderer' + sanApp.componentTree.root.cid
emitter.writeLine(`return ${funcName}(data, noDataOutput, sanssrRuntime)`)
Expand All @@ -65,12 +64,12 @@ export default class ToJSCompiler implements Compiler {
noTemplateOutput = false
}: ToJSCompileOptions = {}): Renderer {
const sanssrRuntime = { _, SanData }
const cc = new RendererCompiler(noTemplateOutput, sanApp.componentTree)

for (const info of sanApp.componentTree.preOrder()) {
const { cid } = info
const cc = new RendererCompiler(info, noTemplateOutput, sanApp.componentTree)
sanssrRuntime[`prototype${cid}`] = info.component
sanssrRuntime[`renderer${cid}`] = cc.compileComponentRenderer()
sanssrRuntime[`renderer${cid}`] = cc.compileComponentRenderer(info)
}
const entryComponentId = sanApp.componentTree.root.cid
return (data: any, noDataOutput: boolean = false) => {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ export abstract class Emitter {
constructor (shiftWidth = 4) {
this.shiftWidth = shiftWidth
}

public clear () {
this.code = ''
this.indentLevel = 0
}
public abstract write (str: string): void
public fullText () {
return this.code
Expand Down
4 changes: 2 additions & 2 deletions test/unit/target-js/compilers/renderer-compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ describe('target-js/compilers/renderer-compiler', () => {
component: new ComponentClass(),
componentClass: ComponentClass
} as any)
const compiler = new RendererCompiler(info, false, {} as any)
compiler.compileComponentPrototypeSource()
const compiler = new RendererCompiler(false, {} as any)
compiler.compileComponentPrototypeSource(info)
expect(compiler.emitter.fullText()).toEqual(`foo: [
1,
x => x
Expand Down

0 comments on commit 8269ae1

Please sign in to comment.