Skip to content

Commit

Permalink
wip: component support
Browse files Browse the repository at this point in the history
  • Loading branch information
pikax committed Jan 2, 2024
1 parent 3d3d08d commit a0622e2
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 21 deletions.
169 changes: 169 additions & 0 deletions packages/compiler-vapor/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
type CodegenOptions,
type CodegenResult,
NewlineType,
NodeTypes,
type Position,
type SourceLocation,
advancePositionWithClone,
Expand All @@ -14,6 +15,7 @@ import {
} from '@vue/compiler-dom'
import {
type AppendNodeIRNode,
type CreateComponentIRNode,
type CreateTextNodeIRNode,
type IRDynamicChildren,
type IRExpression,
Expand Down Expand Up @@ -376,6 +378,8 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
return genSetHtml(oper, context)
case IRNodeTypes.CREATE_TEXT_NODE:
return genCreateTextNode(oper, context)
case IRNodeTypes.CREATE_COMPONENT:
return genCreateComponent(oper, context)
case IRNodeTypes.INSERT_NODE:
return genInsertNode(oper, context)
case IRNodeTypes.PREPEND_NODE:
Expand Down Expand Up @@ -437,6 +441,171 @@ function genCreateTextNode(
)
}

function genCreateComponent(
oper: CreateComponentIRNode,
context: CodegenContext,
) {
const { pushNewline, pushFnCall, vaporHelper } = context

pushNewline(`const n${oper.id} = `)

let props = null
if (oper.props.length && false) {
console.log('ZXZXX')
// props = oper.props
// .map((prop) => {
// const { name, value, exp, arg } = prop
// console.log('using ', prop)

// // const key = oper.runtimeCamelize
// let key = null

// // const content =

// let content = null

// switch (prop?.type) {
// case NodeTypes.ATTRIBUTE: {
// content = value.content
// key = camelize(name)
// break
// }
// case NodeTypes.DIRECTIVE: {
// console.log('found ', prop)
// // content = genExpression(prop.exp, context)
// key = camelize(arg.content)
// content = genWithDirective(exp, context)
// break
// }
// }

// return `${key}: ${JSON.stringify(value?.content)}`
// })
// .join(', ')

console.log('props', props)

// console.log('ppp', oper.props)

// genWithDirective(oper, ctx)

// console.log('res ', genWithDirective({ dir: oper.props[1] }, context))

const dir = oper.props[1]
const { push, newline, pushFnCall, pushMulti, vaporHelper } = context

Check failure on line 495 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

'newline' is declared but its value is never read.

Check failure on line 495 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

'pushFnCall' is declared but its value is never read.

Check failure on line 495 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

'pushMulti' is declared but its value is never read.

Check failure on line 495 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

'vaporHelper' is declared but its value is never read.

// genExpression(dir.exp, context)
if (dir.exp) {

Check failure on line 498 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'exp' does not exist on type 'AttributeNode'.
push(', () => ')
genExpression(dir.exp, context)

Check failure on line 500 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'exp' does not exist on type 'AttributeNode'.
} else if (dir.arg || dir.modifiers.length) {

Check failure on line 501 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'arg' does not exist on type 'AttributeNode'.

Check failure on line 501 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'modifiers' does not exist on type 'AttributeNode'.
push(', void 0')
}

if (dir.arg) {

Check failure on line 505 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'arg' does not exist on type 'AttributeNode'.
push(', ')
genExpression(dir.arg, context)

Check failure on line 507 in packages/compiler-vapor/src/generate.ts

View workflow job for this annotation

GitHub Actions / lint-and-test-dts

Property 'arg' does not exist on type 'AttributeNode'.
} else if (dir.modifiers.length) {
push(', void 0')
}

if (dir.modifiers.length) {
push(', ')
push('{ ')
push(genDirectiveModifiers(dir.modifiers))
push(' }')
}

/*
pushFnCall(
vaporHelper('setAttr'),
`n${oper.element}`,
// 2. key name
() => {
if (oper.runtimeCamelize) {
pushFnCall(helper('camelize'), () => genExpression(oper.key, context))
} else {
genExpression(oper.key, context)
}
},
'undefined',
() => genExpression(oper.value, context),
) */
}
if (oper.props.length) {
props = oper.props
.map((prop) => {
const { name, value, exp, arg } = prop
// const key = oper.runtimeCamelize
let key = null

// const content =

let content = null

switch (prop?.type) {
case NodeTypes.ATTRIBUTE: {
content = value ? JSON.stringify(value.content) : undefined
key = camelize(name)
break
}
case NodeTypes.DIRECTIVE: {
console.log('found ', prop)
// content = genExpression(prop.exp, context)
key = camelize(arg.content)

// content = genWithDirective({ dir: prop }, context)
// genExpression(dir.exp, context)

genIdentifier(
exp.content,
{
inline: context.inline,
bindingMetadata: context.bindingMetadata,
push: (c) => (content = c),
},
{
start: advancePositionWithClone(
exp.loc.start,
exp.content,
exp.loc.start,
),
end: advancePositionWithClone(
exp.loc.start,
exp.content,
exp.loc.end,
),
source: exp.content,
},
)

return `get ${key}() { return ${content} }`

// genExpression(exp, {
// ...context,
// push: (c) => (content = c),
// })
break
}
}

return `${key}: ${content}`
})
.join(', ')

console.log('props', props)
}

pushFnCall(
vaporHelper('createComponent'),
() => genExpression(oper.tag, context),
// () => {
// // oper.props.map((x) => genExpression(x, context))
// },
props ? `{ ${props} }` : '{}',
)
}

function genInsertNode(oper: InsertNodeIRNode, context: CodegenContext) {
const { newline, pushFnCall, vaporHelper } = context
const elements = ([] as number[]).concat(oper.element)
Expand Down
13 changes: 13 additions & 0 deletions packages/compiler-vapor/src/ir.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
AttributeNode,
CompoundExpressionNode,
DirectiveNode,
RootNode,
Expand All @@ -22,6 +23,7 @@ export enum IRNodeTypes {
PREPEND_NODE,
APPEND_NODE,
CREATE_TEXT_NODE,
CREATE_COMPONENT,

WITH_DIRECTIVE,
}
Expand Down Expand Up @@ -98,6 +100,16 @@ export interface CreateTextNodeIRNode extends BaseIRNode {
value: IRExpression
}

export interface CreateComponentIRNode extends BaseIRNode {
type: IRNodeTypes.CREATE_COMPONENT
id: number
tag: string

children: string[]
props: AttributeNode[]
// children: IRExpression
}

export interface InsertNodeIRNode extends BaseIRNode {
type: IRNodeTypes.INSERT_NODE
element: number | number[]
Expand Down Expand Up @@ -134,6 +146,7 @@ export type OperationNode =
| SetEventIRNode
| SetHtmlIRNode
| CreateTextNodeIRNode
| CreateComponentIRNode
| InsertNodeIRNode
| PrependNodeIRNode
| AppendNodeIRNode
Expand Down
42 changes: 29 additions & 13 deletions packages/compiler-vapor/src/transforms/transformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,35 @@ export const transformElement: NodeTransform = (node, ctx) => {
const { tag, props } = node
const isComponent = node.tagType === ElementTypes.COMPONENT

ctx.template += `<${tag}`
if (props.length) {
buildProps(
node,
ctx as TransformContext<ElementNode>,
undefined,
isComponent,
)
}
ctx.template += `>` + ctx.childrenTemplate.join('')
if (isComponent) {
ctx.dynamic.ghost = true

ctx.registerOperation({
type: IRNodeTypes.CREATE_COMPONENT,
id: ctx.reference(),
loc: node.loc,
tag: tag,
children: ctx.childrenTemplate,
// TODO add type
props: props,
})
} else {
ctx.template += `<${tag}`

if (props.length) {
buildProps(
node,
ctx as TransformContext<ElementNode>,
undefined,
isComponent,
)
}
ctx.template += `>` + ctx.childrenTemplate.join('')

// TODO remove unnecessary close tag, e.g. if it's the last element of the template
if (!isVoidTag(tag)) {
ctx.template += `</${tag}>`
// TODO remove unnecessary close tag, e.g. if it's the last element of the template
if (!isVoidTag(tag)) {
ctx.template += `</${tag}>`
}
}
}
}
Expand All @@ -49,6 +64,7 @@ function buildProps(
props: ElementNode['props'] = node.props,
isComponent: boolean,
) {
if (isComponent) console.log('props===== ', props)
for (const prop of props) {
transformProp(prop as VaporDirectiveNode | AttributeNode, node, context)
}
Expand Down
6 changes: 5 additions & 1 deletion packages/runtime-vapor/src/component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EffectScope, type Ref, ref } from '@vue/reactivity'

import { EMPTY_OBJ } from '@vue/shared'
import type { Block } from './render'
import { type Block, render } from './render'
import type { DirectiveBinding } from './directive'
import {
type ComponentPropsOptions,
Expand Down Expand Up @@ -217,3 +217,7 @@ export const createComponentInstance = (
}
return instance
}

export function createComponent(component: Component, props: Data) {
return render(component, props, null).block
}
7 changes: 6 additions & 1 deletion packages/runtime-vapor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ export * from './directive'
export * from './dom'
export * from './directives/vShow'
export * from './apiLifecycle'
export { getCurrentInstance, type ComponentInternalInstance } from './component'

export {
getCurrentInstance,
type ComponentInternalInstance,
createComponent,
} from './component'
15 changes: 9 additions & 6 deletions packages/runtime-vapor/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ export function getIsRendering() {
export function render(
comp: Component,
props: Data,
container: string | ParentNode,
container: string | ParentNode | null,
): ComponentInternalInstance {
const instance = createComponentInstance(comp)
initProps(instance, props)
return mountComponent(instance, (container = normalizeContainer(container)))
}

export function normalizeContainer(container: string | ParentNode): ParentNode {
export function normalizeContainer(
container: string | ParentNode | null,
): ParentNode | null {
return typeof container === 'string'
? // eslint-disable-next-line no-restricted-globals
(document.querySelector(container) as ParentNode)
Expand All @@ -40,7 +42,7 @@ export function normalizeContainer(container: string | ParentNode): ParentNode {

export function mountComponent(
instance: ComponentInternalInstance,
container: ParentNode,
container: ParentNode | null,
) {
instance.container = container

Expand Down Expand Up @@ -76,9 +78,10 @@ export function mountComponent(
bm && invokeArrayFns(bm)
invokeDirectiveHook(instance, 'beforeMount')

insert(block, instance.container)
instance.isMountedRef.value = true

if (container) {
insert(block, instance.container)
instance.isMountedRef.value = true
}
// hook: mounted
invokeDirectiveHook(instance, 'mounted')
m && invokeArrayFns(m)
Expand Down
19 changes: 19 additions & 0 deletions playground/src/component-child.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup>
import { computed, getCurrentInstance, watchEffect } from '@vue/runtime-vapor'
const child = 'Hello world'
defineProps({
random: String,
})
const ctx = getCurrentInstance()
const random = computed(() => ctx.props.random)
// watchEffect(() => {
// console.log('child', ctx.props.random)
// })
</script>
<template>
<div>Child : {{ child }} -- {{ random }}</div>
</template>
Loading

0 comments on commit a0622e2

Please sign in to comment.