mirror of https://github.com/vuejs/core.git
Merge 9e2eea9103
into bb4ae25793
This commit is contained in:
commit
7914078ba4
|
@ -27,7 +27,8 @@ const slotProp = ref('slot prop')
|
||||||
change slot prop
|
change slot prop
|
||||||
</button>
|
</button>
|
||||||
<div class="vdom-slot-in-vapor-default">
|
<div class="vdom-slot-in-vapor-default">
|
||||||
#default: <slot :foo="slotProp" />
|
#default:
|
||||||
|
<slot :foo="slotProp" />
|
||||||
</div>
|
</div>
|
||||||
<div class="vdom-slot-in-vapor-test">
|
<div class="vdom-slot-in-vapor-test">
|
||||||
#test: <slot name="test">fallback content</slot>
|
#test: <slot name="test">fallback content</slot>
|
||||||
|
@ -40,7 +41,7 @@ const slotProp = ref('slot prop')
|
||||||
>
|
>
|
||||||
Toggle default slot to vdom
|
Toggle default slot to vdom
|
||||||
</button>
|
</button>
|
||||||
<VdomComp :msg="msg">
|
<VdomComp :msg="msg" class="foo">
|
||||||
<template #default="{ foo }" v-if="passSlot">
|
<template #default="{ foo }" v-if="passSlot">
|
||||||
<div>slot prop: {{ foo }}</div>
|
<div>slot prop: {{ foo }}</div>
|
||||||
<div>component prop: {{ msg }}</div>
|
<div>component prop: {{ msg }}</div>
|
||||||
|
|
|
@ -449,7 +449,7 @@ describe('compiler: transform v-model', () => {
|
||||||
expect(codegen.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`)
|
expect(codegen.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should generate modelModifiers for component v-model', () => {
|
test('should generate modelValueModifiers for component v-model', () => {
|
||||||
const root = parseWithVModel('<Comp v-model.trim.bar-baz="foo" />', {
|
const root = parseWithVModel('<Comp v-model.trim.bar-baz="foo" />', {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
})
|
})
|
||||||
|
@ -461,7 +461,7 @@ describe('compiler: transform v-model', () => {
|
||||||
{ key: { content: `modelValue` } },
|
{ key: { content: `modelValue` } },
|
||||||
{ key: { content: `onUpdate:modelValue` } },
|
{ key: { content: `onUpdate:modelValue` } },
|
||||||
{
|
{
|
||||||
key: { content: 'modelModifiers' },
|
key: { content: 'modelValueModifiers' },
|
||||||
value: {
|
value: {
|
||||||
content: `{ trim: true, "bar-baz": true }`,
|
content: `{ trim: true, "bar-baz": true }`,
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
|
@ -469,7 +469,7 @@ describe('compiler: transform v-model', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
// should NOT include modelModifiers in dynamicPropNames because it's never
|
// should NOT include modelValueModifiers in dynamicPropNames because it's never
|
||||||
// gonna change
|
// gonna change
|
||||||
expect(vnodeCall.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`)
|
expect(vnodeCall.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`)
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,10 +30,6 @@ export function walkIdentifiers(
|
||||||
parentStack: Node[] = [],
|
parentStack: Node[] = [],
|
||||||
knownIds: Record<string, number> = Object.create(null),
|
knownIds: Record<string, number> = Object.create(null),
|
||||||
): void {
|
): void {
|
||||||
if (__BROWSER__) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const rootExp =
|
const rootExp =
|
||||||
root.type === 'Program'
|
root.type === 'Program'
|
||||||
? root.body[0].type === 'ExpressionStatement' && root.body[0].expression
|
? root.body[0].type === 'ExpressionStatement' && root.body[0].expression
|
||||||
|
@ -110,10 +106,6 @@ export function isReferencedIdentifier(
|
||||||
parent: Node | null,
|
parent: Node | null,
|
||||||
parentStack: Node[],
|
parentStack: Node[],
|
||||||
): boolean {
|
): boolean {
|
||||||
if (__BROWSER__) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||||
? isStaticExp(arg)
|
? isStaticExp(arg)
|
||||||
? `${arg.content}Modifiers`
|
? `${arg.content}Modifiers`
|
||||||
: createCompoundExpression([arg, ' + "Modifiers"'])
|
: createCompoundExpression([arg, ' + "Modifiers"'])
|
||||||
: `modelModifiers`
|
: `modelValueModifiers`
|
||||||
props.push(
|
props.push(
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
modifiersKey,
|
modifiersKey,
|
||||||
|
|
|
@ -6,7 +6,7 @@ exports[`defineModel() > basic usage 1`] = `
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { required: true },
|
"modelValue": { required: true },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
"count": {},
|
"count": {},
|
||||||
"countModifiers": {},
|
"countModifiers": {},
|
||||||
"toString": { type: Function },
|
"toString": { type: Function },
|
||||||
|
@ -34,7 +34,7 @@ export default /*@__PURE__*/_defineComponent({
|
||||||
"modelValue": {
|
"modelValue": {
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
@ -60,7 +60,7 @@ export default /*@__PURE__*/_defineComponent({
|
||||||
default: 0,
|
default: 0,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
@ -86,7 +86,7 @@ export default /*@__PURE__*/_defineComponent({
|
||||||
}, {
|
}, {
|
||||||
"modelValue": {
|
"modelValue": {
|
||||||
},
|
},
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
}),
|
}),
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props: any, { expose: __expose }) {
|
setup(__props: any, { expose: __expose }) {
|
||||||
|
@ -109,7 +109,7 @@ exports[`defineModel() > w/ Boolean And Function types, production mode 1`] = `
|
||||||
export default /*@__PURE__*/_defineComponent({
|
export default /*@__PURE__*/_defineComponent({
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { type: [Boolean, String] },
|
"modelValue": { type: [Boolean, String] },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
@ -150,7 +150,7 @@ exports[`defineModel() > w/ defineProps and defineEmits 1`] = `
|
||||||
export default {
|
export default {
|
||||||
props: /*@__PURE__*/_mergeModels({ foo: String }, {
|
props: /*@__PURE__*/_mergeModels({ foo: String }, {
|
||||||
"modelValue": { default: 0 },
|
"modelValue": { default: 0 },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
}),
|
}),
|
||||||
emits: /*@__PURE__*/_mergeModels(['change'], ["update:modelValue"]),
|
emits: /*@__PURE__*/_mergeModels(['change'], ["update:modelValue"]),
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
@ -172,7 +172,7 @@ exports[`defineModel() > w/ types, basic usage 1`] = `
|
||||||
export default /*@__PURE__*/_defineComponent({
|
export default /*@__PURE__*/_defineComponent({
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { type: [Boolean, String] },
|
"modelValue": { type: [Boolean, String] },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
"count": { type: Number },
|
"count": { type: Number },
|
||||||
"countModifiers": {},
|
"countModifiers": {},
|
||||||
"disabled": { type: Number, ...{ required: false } },
|
"disabled": { type: Number, ...{ required: false } },
|
||||||
|
@ -201,7 +201,7 @@ exports[`defineModel() > w/ types, production mode 1`] = `
|
||||||
export default /*@__PURE__*/_defineComponent({
|
export default /*@__PURE__*/_defineComponent({
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { type: Boolean },
|
"modelValue": { type: Boolean },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
"fn": {},
|
"fn": {},
|
||||||
"fnModifiers": {},
|
"fnModifiers": {},
|
||||||
"fnWithDefault": { type: Function, ...{ default: () => null } },
|
"fnWithDefault": { type: Function, ...{ default: () => null } },
|
||||||
|
@ -233,7 +233,7 @@ exports[`defineModel() > w/ types, production mode, boolean + multiple types 1`]
|
||||||
export default /*@__PURE__*/_defineComponent({
|
export default /*@__PURE__*/_defineComponent({
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { type: [Boolean, String, Object] },
|
"modelValue": { type: [Boolean, String, Object] },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
@ -253,7 +253,7 @@ exports[`defineModel() > w/ types, production mode, function + runtime opts + mu
|
||||||
export default /*@__PURE__*/_defineComponent({
|
export default /*@__PURE__*/_defineComponent({
|
||||||
props: {
|
props: {
|
||||||
"modelValue": { type: [Number, Function], ...{ default: () => 1 } },
|
"modelValue": { type: [Number, Function], ...{ default: () => 1 } },
|
||||||
"modelModifiers": {},
|
"modelValueModifiers": {},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ describe('defineModel()', () => {
|
||||||
)
|
)
|
||||||
assertCode(content)
|
assertCode(content)
|
||||||
expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
|
expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
|
||||||
expect(content).toMatch('"modelModifiers": {}')
|
expect(content).toMatch('"modelValueModifiers": {}')
|
||||||
expect(content).toMatch('"count": { type: Number }')
|
expect(content).toMatch('"count": { type: Number }')
|
||||||
expect(content).toMatch(
|
expect(content).toMatch(
|
||||||
'"disabled": { type: Number, ...{ required: false } }',
|
'"disabled": { type: Number, ...{ required: false } }',
|
||||||
|
|
|
@ -167,9 +167,7 @@ export function genModelProps(ctx: ScriptCompileContext) {
|
||||||
modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},`
|
modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},`
|
||||||
|
|
||||||
// also generate modifiers prop
|
// also generate modifiers prop
|
||||||
const modifierPropName = JSON.stringify(
|
const modifierPropName = JSON.stringify(`${name}Modifiers`)
|
||||||
name === 'modelValue' ? `modelModifiers` : `${name}Modifiers`,
|
|
||||||
)
|
|
||||||
modelPropsDecl += `\n ${modifierPropName}: {},`
|
modelPropsDecl += `\n ${modifierPropName}: {},`
|
||||||
}
|
}
|
||||||
return `{${modelPropsDecl}\n }`
|
return `{${modelPropsDecl}\n }`
|
||||||
|
|
|
@ -246,6 +246,36 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > component event with keys modifier 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, withKeys as _withKeys, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Foo = _resolveComponent("Foo")
|
||||||
|
const n0 = _createComponentWithFallback(_component_Foo, { onKeyup: () => _withKeys(_ctx.bar, ["enter"]) }, null, true)
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > component event with multiple modifiers and event options 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, withModifiers as _withModifiers, withKeys as _withKeys, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Foo = _resolveComponent("Foo")
|
||||||
|
const n0 = _createComponentWithFallback(_component_Foo, { onFooCaptureOnce: () => _withKeys(_withModifiers(_ctx.bar, ["stop","prevent"]), ["enter"]) }, null, true)
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > component event with nonKeys modifier 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, withModifiers as _withModifiers, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Foo = _resolveComponent("Foo")
|
||||||
|
const n0 = _createComponentWithFallback(_component_Foo, { onFoo: () => _withModifiers(_ctx.bar, ["stop","prevent"]) }, null, true)
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: element transform > component event with once modifier 1`] = `
|
exports[`compiler: element transform > component event with once modifier 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`compiler: vModel transform > component > v-model for component should generate modelModifiers 1`] = `
|
exports[`compiler: vModel transform > component > v-model for component should generate modelValueModifiers 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const _component_Comp = _resolveComponent("Comp")
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo),
|
const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo),
|
||||||
"onUpdate:modelValue": () => _value => (_ctx.foo = _value),
|
"onUpdate:modelValue": () => _value => (_ctx.foo = _value),
|
||||||
modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true)
|
modelValueModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true)
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -896,6 +896,78 @@ describe('compiler: element transform', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('component event with keys modifier', () => {
|
||||||
|
const { code, ir } = compileWithElementTransform(
|
||||||
|
`<Foo @keyup.enter="bar" />`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||||
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
tag: 'Foo',
|
||||||
|
props: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
key: { content: 'keyup' },
|
||||||
|
handler: true,
|
||||||
|
handlerModifiers: {
|
||||||
|
keys: ['enter'],
|
||||||
|
nonKeys: [],
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('component event with nonKeys modifier', () => {
|
||||||
|
const { code, ir } = compileWithElementTransform(
|
||||||
|
`<Foo @foo.stop.prevent="bar" />`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||||
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
tag: 'Foo',
|
||||||
|
props: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
key: { content: 'foo' },
|
||||||
|
handler: true,
|
||||||
|
handlerModifiers: {
|
||||||
|
keys: [],
|
||||||
|
nonKeys: ['stop', 'prevent'],
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('component event with multiple modifiers and event options', () => {
|
||||||
|
const { code, ir } = compileWithElementTransform(
|
||||||
|
`<Foo @foo.enter.stop.prevent.capture.once="bar" />`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||||
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
tag: 'Foo',
|
||||||
|
props: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
key: { content: 'foo' },
|
||||||
|
handler: true,
|
||||||
|
handlerModifiers: {
|
||||||
|
keys: ['enter'],
|
||||||
|
nonKeys: ['stop', 'prevent'],
|
||||||
|
options: ['capture', 'once'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('component with dynamic event arguments', () => {
|
test('component with dynamic event arguments', () => {
|
||||||
const { code, ir } = compileWithElementTransform(
|
const { code, ir } = compileWithElementTransform(
|
||||||
`<Foo @[foo-bar]="bar" @[baz]="qux" />`,
|
`<Foo @[foo-bar]="bar" @[baz]="qux" />`,
|
||||||
|
|
|
@ -266,13 +266,13 @@ describe('compiler: vModel transform', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('v-model for component should generate modelModifiers', () => {
|
test('v-model for component should generate modelValueModifiers', () => {
|
||||||
const { code, ir } = compileWithVModel(
|
const { code, ir } = compileWithVModel(
|
||||||
'<Comp v-model.trim.bar-baz="foo" />',
|
'<Comp v-model.trim.bar-baz="foo" />',
|
||||||
)
|
)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(code).contain(
|
expect(code).contain(
|
||||||
`modelModifiers: () => ({ trim: true, "bar-baz": true })`,
|
`modelValueModifiers: () => ({ trim: true, "bar-baz": true })`,
|
||||||
)
|
)
|
||||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
|
|
@ -19,7 +19,14 @@ import {
|
||||||
} from './generators/utils'
|
} from './generators/utils'
|
||||||
import { setTemplateRefIdent } from './generators/templateRef'
|
import { setTemplateRefIdent } from './generators/templateRef'
|
||||||
|
|
||||||
export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
|
type CustomGenOperation = (
|
||||||
|
opers: any,
|
||||||
|
context: CodegenContext,
|
||||||
|
) => CodeFragment[] | void
|
||||||
|
|
||||||
|
export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'> & {
|
||||||
|
customGenOperation?: CustomGenOperation | null
|
||||||
|
}
|
||||||
|
|
||||||
export class CodegenContext {
|
export class CodegenContext {
|
||||||
options: Required<CodegenOptions>
|
options: Required<CodegenOptions>
|
||||||
|
@ -87,6 +94,7 @@ export class CodegenContext {
|
||||||
inline: false,
|
inline: false,
|
||||||
bindingMetadata: {},
|
bindingMetadata: {},
|
||||||
expressionPlugins: [],
|
expressionPlugins: [],
|
||||||
|
customGenOperation: null,
|
||||||
}
|
}
|
||||||
this.options = extend(defaultOptions, options)
|
this.options = extend(defaultOptions, options)
|
||||||
this.block = ir.block
|
this.block = ir.block
|
||||||
|
|
|
@ -211,7 +211,7 @@ function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
|
||||||
? genEventHandler(
|
? genEventHandler(
|
||||||
context,
|
context,
|
||||||
prop.values[0],
|
prop.values[0],
|
||||||
undefined,
|
prop.handlerModifiers,
|
||||||
true /* wrap handlers passed to components */,
|
true /* wrap handlers passed to components */,
|
||||||
)
|
)
|
||||||
: isStatic
|
: isStatic
|
||||||
|
@ -240,9 +240,7 @@ function genModelModifiers(
|
||||||
if (!modelModifiers || !modelModifiers.length) return []
|
if (!modelModifiers || !modelModifiers.length) return []
|
||||||
|
|
||||||
const modifiersKey = key.isStatic
|
const modifiersKey = key.isStatic
|
||||||
? key.content === 'modelValue'
|
? [`${key.content}Modifiers`]
|
||||||
? [`modelModifiers`]
|
|
||||||
: [`${key.content}Modifiers`]
|
|
||||||
: ['[', ...genExpression(key, context), ' + "Modifiers"]']
|
: ['[', ...genExpression(key, context), ' + "Modifiers"]']
|
||||||
|
|
||||||
const modifiersVal = genDirectiveModifiers(modelModifiers)
|
const modifiersVal = genDirectiveModifiers(modelModifiers)
|
||||||
|
|
|
@ -88,6 +88,11 @@ export function genOperation(
|
||||||
case IRNodeTypes.GET_TEXT_CHILD:
|
case IRNodeTypes.GET_TEXT_CHILD:
|
||||||
return genGetTextChild(oper, context)
|
return genGetTextChild(oper, context)
|
||||||
default:
|
default:
|
||||||
|
if (context.options.customGenOperation) {
|
||||||
|
const result = context.options.customGenOperation(oper, context)
|
||||||
|
if (result) return result
|
||||||
|
}
|
||||||
|
|
||||||
const exhaustiveCheck: never = oper
|
const exhaustiveCheck: never = oper
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled operation type in genOperation: ${exhaustiveCheck}`,
|
`Unhandled operation type in genOperation: ${exhaustiveCheck}`,
|
||||||
|
|
|
@ -114,9 +114,10 @@ export function genPropKey(
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { helper } = context
|
const { helper } = context
|
||||||
|
|
||||||
const handlerModifierPostfix = handlerModifiers
|
const handlerModifierPostfix =
|
||||||
? handlerModifiers.map(capitalize).join('')
|
handlerModifiers && handlerModifiers.options
|
||||||
: ''
|
? handlerModifiers.options.map(capitalize).join('')
|
||||||
|
: ''
|
||||||
// static arg was transformed by v-bind transformer
|
// static arg was transformed by v-bind transformer
|
||||||
if (node.isStatic) {
|
if (node.isStatic) {
|
||||||
// only quote keys if necessary
|
// only quote keys if necessary
|
||||||
|
|
|
@ -10,8 +10,8 @@ export function genSetText(
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { helper } = context
|
const { helper } = context
|
||||||
const { element, values, generated, jsx } = oper
|
const { element, values, generated } = oper
|
||||||
const texts = combineValues(values, context, jsx)
|
const texts = combineValues(values, context)
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...genCall(helper('setText'), `${generated ? 'x' : 'n'}${element}`, texts),
|
...genCall(helper('setText'), `${generated ? 'x' : 'n'}${element}`, texts),
|
||||||
|
@ -21,16 +21,15 @@ export function genSetText(
|
||||||
function combineValues(
|
function combineValues(
|
||||||
values: SimpleExpressionNode[],
|
values: SimpleExpressionNode[],
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
jsx?: boolean,
|
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
return values.flatMap((value, i) => {
|
return values.flatMap((value, i) => {
|
||||||
let exp = genExpression(value, context)
|
let exp = genExpression(value, context)
|
||||||
if (!jsx && getLiteralExpressionValue(value) == null) {
|
if (getLiteralExpressionValue(value) == null) {
|
||||||
// dynamic, wrap with toDisplayString
|
// dynamic, wrap with toDisplayString
|
||||||
exp = genCall(context.helper('toDisplayString'), exp)
|
exp = genCall(context.helper('toDisplayString'), exp)
|
||||||
}
|
}
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
exp.unshift(jsx ? ', ' : ' + ')
|
exp.unshift(' + ')
|
||||||
}
|
}
|
||||||
return exp
|
return exp
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
import { isArray, isString } from '@vue/shared'
|
import { isArray, isString } from '@vue/shared'
|
||||||
import type { CodegenContext } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
|
|
||||||
|
export { genExpression } from './expression'
|
||||||
|
|
||||||
export const NEWLINE: unique symbol = Symbol(__DEV__ ? `newline` : ``)
|
export const NEWLINE: unique symbol = Symbol(__DEV__ ? `newline` : ``)
|
||||||
/** increase offset but don't push actual code */
|
/** increase offset but don't push actual code */
|
||||||
export const LF: unique symbol = Symbol(__DEV__ ? `line feed` : ``)
|
export const LF: unique symbol = Symbol(__DEV__ ? `line feed` : ``)
|
||||||
|
|
|
@ -13,13 +13,7 @@ export {
|
||||||
type CodegenOptions,
|
type CodegenOptions,
|
||||||
type VaporCodegenResult,
|
type VaporCodegenResult,
|
||||||
} from './generate'
|
} from './generate'
|
||||||
export {
|
export * from './generators/utils'
|
||||||
genCall,
|
|
||||||
genMulti,
|
|
||||||
buildCodeFragment,
|
|
||||||
codeFragmentToString,
|
|
||||||
type CodeFragment,
|
|
||||||
} from './generators/utils'
|
|
||||||
export {
|
export {
|
||||||
wrapTemplate,
|
wrapTemplate,
|
||||||
compile,
|
compile,
|
||||||
|
|
|
@ -123,7 +123,6 @@ export interface SetTextIRNode extends BaseIRNode {
|
||||||
element: number
|
element: number
|
||||||
values: SimpleExpressionNode[]
|
values: SimpleExpressionNode[]
|
||||||
generated?: boolean // whether this is a generated empty text node by `processTextLikeContainer`
|
generated?: boolean // whether this is a generated empty text node by `processTextLikeContainer`
|
||||||
jsx?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type KeyOverride = [find: string, replacement: string]
|
export type KeyOverride = [find: string, replacement: string]
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
type IRSlots,
|
type IRSlots,
|
||||||
type OperationNode,
|
type OperationNode,
|
||||||
type RootIRNode,
|
type RootIRNode,
|
||||||
|
type SetEventIRNode,
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from './ir'
|
} from './ir'
|
||||||
import { isConstantExpression, isStaticExpression } from './utils'
|
import { isConstantExpression, isStaticExpression } from './utils'
|
||||||
|
@ -46,7 +47,7 @@ export interface DirectiveTransformResult {
|
||||||
modifier?: '.' | '^'
|
modifier?: '.' | '^'
|
||||||
runtimeCamelize?: boolean
|
runtimeCamelize?: boolean
|
||||||
handler?: boolean
|
handler?: boolean
|
||||||
handlerModifiers?: string[]
|
handlerModifiers?: SetEventIRNode['modifiers']
|
||||||
model?: boolean
|
model?: boolean
|
||||||
modelModifiers?: string[]
|
modelModifiers?: string[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
key: arg,
|
key: arg,
|
||||||
value: handler,
|
value: handler,
|
||||||
handler: true,
|
handler: true,
|
||||||
handlerModifiers: eventOptionModifiers,
|
handlerModifiers: {
|
||||||
|
keys: keyModifiers,
|
||||||
|
nonKeys: nonKeyModifiers,
|
||||||
|
options: eventOptionModifiers,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ describe('component: emit', () => {
|
||||||
const Comp = () =>
|
const Comp = () =>
|
||||||
h(Foo, {
|
h(Foo, {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
modelModifiers: { number: true },
|
modelValueModifiers: { number: true },
|
||||||
'onUpdate:modelValue': fn1,
|
'onUpdate:modelValue': fn1,
|
||||||
|
|
||||||
foo: null,
|
foo: null,
|
||||||
|
@ -356,7 +356,7 @@ describe('component: emit', () => {
|
||||||
const Comp = () =>
|
const Comp = () =>
|
||||||
h(Foo, {
|
h(Foo, {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
modelModifiers: { trim: true },
|
modelValueModifiers: { trim: true },
|
||||||
'onUpdate:modelValue': fn1,
|
'onUpdate:modelValue': fn1,
|
||||||
|
|
||||||
foo: null,
|
foo: null,
|
||||||
|
@ -410,7 +410,7 @@ describe('component: emit', () => {
|
||||||
const Comp = () =>
|
const Comp = () =>
|
||||||
h(Foo, {
|
h(Foo, {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
modelModifiers: { trim: true },
|
modelValueModifiers: { trim: true },
|
||||||
'onUpdate:modelValue': fn1,
|
'onUpdate:modelValue': fn1,
|
||||||
|
|
||||||
firstName: null,
|
firstName: null,
|
||||||
|
@ -464,7 +464,7 @@ describe('component: emit', () => {
|
||||||
const Comp = () =>
|
const Comp = () =>
|
||||||
h(Foo, {
|
h(Foo, {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
modelModifiers: { trim: true, number: true },
|
modelValueModifiers: { trim: true, number: true },
|
||||||
'onUpdate:modelValue': fn1,
|
'onUpdate:modelValue': fn1,
|
||||||
|
|
||||||
foo: null,
|
foo: null,
|
||||||
|
@ -492,7 +492,7 @@ describe('component: emit', () => {
|
||||||
const Comp = () =>
|
const Comp = () =>
|
||||||
h(Foo, {
|
h(Foo, {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
modelModifiers: { trim: true },
|
modelValueModifiers: { trim: true },
|
||||||
'onUpdate:modelValue': fn,
|
'onUpdate:modelValue': fn,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
||||||
import type { DefineComponent } from './apiDefineComponent'
|
import type { DefineComponent } from './apiDefineComponent'
|
||||||
|
|
||||||
export interface App<HostElement = any> {
|
export interface App<HostElement = any> {
|
||||||
|
vapor?: boolean
|
||||||
version: string
|
version: string
|
||||||
config: AppConfig
|
config: AppConfig
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,25 @@ export let currentInstance: GenericComponentInstance | null = null
|
||||||
export const getCurrentGenericInstance: () => GenericComponentInstance | null =
|
export const getCurrentGenericInstance: () => GenericComponentInstance | null =
|
||||||
() => currentInstance || currentRenderingInstance
|
() => currentInstance || currentRenderingInstance
|
||||||
|
|
||||||
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
|
/**
|
||||||
currentInstance && !currentInstance.vapor
|
* Retrieves the current component instance.
|
||||||
? (currentInstance as ComponentInternalInstance)
|
*
|
||||||
|
* @param generic - A boolean flag indicating whether to return a generic component instance.
|
||||||
|
* If `true`, returns a `GenericComponentInstance` including vapor instance.
|
||||||
|
* If `false` or unset, returns a `ComponentInternalInstance` if available.
|
||||||
|
* @returns The current component instance, or `null` if no instance is active.
|
||||||
|
*/
|
||||||
|
export function getCurrentInstance(
|
||||||
|
generic: true,
|
||||||
|
): GenericComponentInstance | null
|
||||||
|
export function getCurrentInstance(
|
||||||
|
generic?: boolean,
|
||||||
|
): ComponentInternalInstance | null
|
||||||
|
export function getCurrentInstance(generic?: boolean) {
|
||||||
|
return currentInstance && (generic || !currentInstance.vapor)
|
||||||
|
? currentInstance
|
||||||
: currentRenderingInstance
|
: currentRenderingInstance
|
||||||
|
}
|
||||||
|
|
||||||
export let isInSSRComponentSetup = false
|
export let isInSSRComponentSetup = false
|
||||||
|
|
||||||
|
|
|
@ -145,9 +145,9 @@ export const getModelModifiers = (
|
||||||
modelName: string,
|
modelName: string,
|
||||||
getter: (props: Record<string, any>, key: string) => any,
|
getter: (props: Record<string, any>, key: string) => any,
|
||||||
): Record<string, boolean> | undefined => {
|
): Record<string, boolean> | undefined => {
|
||||||
return modelName === 'modelValue' || modelName === 'model-value'
|
return (
|
||||||
? getter(props, 'modelModifiers')
|
getter(props, `${modelName}Modifiers`) ||
|
||||||
: getter(props, `${modelName}Modifiers`) ||
|
getter(props, `${camelize(modelName)}Modifiers`) ||
|
||||||
getter(props, `${camelize(modelName)}Modifiers`) ||
|
getter(props, `${hyphenate(modelName)}Modifiers`)
|
||||||
getter(props, `${hyphenate(modelName)}Modifiers`)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,25 +331,29 @@ describe('component', () => {
|
||||||
__DEV__ = true
|
__DEV__ = true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('warn if functional vapor component not return a block', () => {
|
it('functional vapor component return a object', () => {
|
||||||
define(() => {
|
const { host } = define(() => {
|
||||||
return () => {}
|
return {}
|
||||||
}).render()
|
}).render()
|
||||||
|
|
||||||
expect(
|
expect(host.textContent).toBe(`[object Object]`)
|
||||||
'Functional vapor component must return a block directly',
|
|
||||||
).toHaveBeenWarned()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('warn if setup return a function and no render function', () => {
|
it('functional vapor component return a function', () => {
|
||||||
define({
|
const { host } = define(() => {
|
||||||
|
return () => ({})
|
||||||
|
}).render()
|
||||||
|
|
||||||
|
expect(host.textContent).toBe(`() => ({})`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('setup return a function and no render function', () => {
|
||||||
|
const { host } = define({
|
||||||
setup() {
|
setup() {
|
||||||
return () => []
|
return () => []
|
||||||
},
|
},
|
||||||
}).render()
|
}).render()
|
||||||
|
|
||||||
expect(
|
expect(host.textContent).toBe(`() => []`)
|
||||||
'Vapor component setup() returned non-block value, and has no render function',
|
|
||||||
).toHaveBeenWarned()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -265,7 +265,7 @@ describe('component: emit', () => {
|
||||||
const fn2 = vi.fn()
|
const fn2 = vi.fn()
|
||||||
render({
|
render({
|
||||||
modelValue: () => null,
|
modelValue: () => null,
|
||||||
modelModifiers: () => ({ number: true }),
|
modelValueModifiers: () => ({ number: true }),
|
||||||
['onUpdate:modelValue']: () => fn1,
|
['onUpdate:modelValue']: () => fn1,
|
||||||
foo: () => null,
|
foo: () => null,
|
||||||
fooModifiers: () => ({ number: true }),
|
fooModifiers: () => ({ number: true }),
|
||||||
|
@ -291,7 +291,7 @@ describe('component: emit', () => {
|
||||||
modelValue() {
|
modelValue() {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
modelModifiers() {
|
modelValueModifiers() {
|
||||||
return { trim: true }
|
return { trim: true }
|
||||||
},
|
},
|
||||||
['onUpdate:modelValue']() {
|
['onUpdate:modelValue']() {
|
||||||
|
@ -327,7 +327,7 @@ describe('component: emit', () => {
|
||||||
modelValue() {
|
modelValue() {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
modelModifiers() {
|
modelValueModifiers() {
|
||||||
return { trim: true, number: true }
|
return { trim: true, number: true }
|
||||||
},
|
},
|
||||||
['onUpdate:modelValue']() {
|
['onUpdate:modelValue']() {
|
||||||
|
@ -361,7 +361,7 @@ describe('component: emit', () => {
|
||||||
modelValue() {
|
modelValue() {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
modelModifiers() {
|
modelValueModifiers() {
|
||||||
return { trim: true }
|
return { trim: true }
|
||||||
},
|
},
|
||||||
['onUpdate:modelValue']() {
|
['onUpdate:modelValue']() {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { createTextNode, normalizeNode } from '../../src/dom/node'
|
||||||
|
import { VaporFragment } from '../../src'
|
||||||
|
|
||||||
|
describe('dom node', () => {
|
||||||
|
test('normalizeNode', () => {
|
||||||
|
// null / undefined -> Comment
|
||||||
|
expect(normalizeNode(null)).toBeInstanceOf(Comment)
|
||||||
|
expect(normalizeNode(undefined)).toBeInstanceOf(Comment)
|
||||||
|
|
||||||
|
// boolean -> Comment
|
||||||
|
expect(normalizeNode(true)).toBeInstanceOf(Comment)
|
||||||
|
expect(normalizeNode(false)).toBeInstanceOf(Comment)
|
||||||
|
|
||||||
|
// array -> Fragment
|
||||||
|
expect(normalizeNode(['foo'])).toBeInstanceOf(VaporFragment)
|
||||||
|
|
||||||
|
// VNode -> VNode
|
||||||
|
const vnode = createTextNode('div')
|
||||||
|
expect(normalizeNode(vnode)).toBe(vnode)
|
||||||
|
|
||||||
|
// primitive types
|
||||||
|
expect(normalizeNode('foo')).toMatchObject(createTextNode('foo'))
|
||||||
|
expect(normalizeNode(1)).toMatchObject(createTextNode('1'))
|
||||||
|
})
|
||||||
|
})
|
|
@ -182,7 +182,6 @@ describe('error handling', () => {
|
||||||
|
|
||||||
define(Comp).render()
|
define(Comp).render()
|
||||||
expect(fn).toHaveBeenCalledWith(err, 'setup function')
|
expect(fn).toHaveBeenCalledWith(err, 'setup function')
|
||||||
expect(`returned non-block value`).toHaveBeenWarned()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('in render function', () => {
|
test('in render function', () => {
|
||||||
|
|
|
@ -100,6 +100,7 @@ function postPrepareApp(app: App) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.vapor = true
|
||||||
const mount = app.mount
|
const mount = app.mount
|
||||||
app.mount = (container, ...args: any[]) => {
|
app.mount = (container, ...args: any[]) => {
|
||||||
container = normalizeContainer(container) as ParentNode
|
container = normalizeContainer(container) as ParentNode
|
||||||
|
|
|
@ -23,9 +23,8 @@ import {
|
||||||
simpleSetCurrentInstance,
|
simpleSetCurrentInstance,
|
||||||
startMeasure,
|
startMeasure,
|
||||||
unregisterHMR,
|
unregisterHMR,
|
||||||
warn,
|
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { type Block, DynamicFragment, insert, isBlock, remove } from './block'
|
import { type Block, DynamicFragment, insert, remove } from './block'
|
||||||
import {
|
import {
|
||||||
type ShallowRef,
|
type ShallowRef,
|
||||||
markRaw,
|
markRaw,
|
||||||
|
@ -59,6 +58,7 @@ import {
|
||||||
} from './componentSlots'
|
} from './componentSlots'
|
||||||
import { hmrReload, hmrRerender } from './hmr'
|
import { hmrReload, hmrRerender } from './hmr'
|
||||||
import { isHydrating, locateHydrationNode } from './dom/hydration'
|
import { isHydrating, locateHydrationNode } from './dom/hydration'
|
||||||
|
import { normalizeNode } from './dom/node'
|
||||||
import {
|
import {
|
||||||
insertionAnchor,
|
insertionAnchor,
|
||||||
insertionParent,
|
insertionParent,
|
||||||
|
@ -150,8 +150,9 @@ export function createComponent(
|
||||||
resetInsertionState()
|
resetInsertionState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isFnComponent = isFunction(component)
|
||||||
// vdom interop enabled and component is not an explicit vapor component
|
// vdom interop enabled and component is not an explicit vapor component
|
||||||
if (appContext.vapor && !component.__vapor) {
|
if (appContext.vapor && !isFnComponent && !component.__vapor) {
|
||||||
const frag = appContext.vapor.vdomMount(
|
const frag = appContext.vapor.vdomMount(
|
||||||
component as any,
|
component as any,
|
||||||
rawProps,
|
rawProps,
|
||||||
|
@ -188,6 +189,14 @@ export function createComponent(
|
||||||
appContext,
|
appContext,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HMR
|
||||||
|
if (__DEV__ && component.__hmrId) {
|
||||||
|
registerHMR(instance)
|
||||||
|
instance.isSingleRoot = isSingleRoot
|
||||||
|
instance.hmrRerender = hmrRerender.bind(null, instance)
|
||||||
|
instance.hmrReload = hmrReload.bind(null, instance)
|
||||||
|
}
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
pushWarningContext(instance)
|
pushWarningContext(instance)
|
||||||
startMeasure(instance, `init`)
|
startMeasure(instance, `init`)
|
||||||
|
@ -205,36 +214,22 @@ export function createComponent(
|
||||||
setupPropsValidation(instance)
|
setupPropsValidation(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupFn = isFunction(component) ? component : component.setup
|
const setupFn = isFnComponent ? component : component.setup
|
||||||
const setupResult = setupFn
|
const setupResult = setupFn
|
||||||
? callWithErrorHandling(setupFn, instance, ErrorCodes.SETUP_FUNCTION, [
|
? callWithErrorHandling(setupFn, instance, ErrorCodes.SETUP_FUNCTION, [
|
||||||
instance.props,
|
instance.props,
|
||||||
instance,
|
instance,
|
||||||
]) || EMPTY_OBJ
|
]) || []
|
||||||
: EMPTY_OBJ
|
: []
|
||||||
|
|
||||||
if (__DEV__ && !isBlock(setupResult)) {
|
if (__DEV__) {
|
||||||
if (isFunction(component)) {
|
if (isFnComponent || !component.render) {
|
||||||
warn(`Functional vapor component must return a block directly.`)
|
instance.block = normalizeNode(setupResult)
|
||||||
instance.block = []
|
|
||||||
} else if (!component.render) {
|
|
||||||
warn(
|
|
||||||
`Vapor component setup() returned non-block value, and has no render function.`,
|
|
||||||
)
|
|
||||||
instance.block = []
|
|
||||||
} else {
|
} else {
|
||||||
instance.devtoolsRawSetupState = setupResult
|
instance.devtoolsRawSetupState = setupResult
|
||||||
// TODO make the proxy warn non-existent property access during dev
|
// TODO make the proxy warn non-existent property access during dev
|
||||||
instance.setupState = proxyRefs(setupResult)
|
instance.setupState = proxyRefs(setupResult)
|
||||||
devRender(instance)
|
devRender(instance)
|
||||||
|
|
||||||
// HMR
|
|
||||||
if (component.__hmrId) {
|
|
||||||
registerHMR(instance)
|
|
||||||
instance.isSingleRoot = isSingleRoot
|
|
||||||
instance.hmrRerender = hmrRerender.bind(null, instance)
|
|
||||||
instance.hmrReload = hmrReload.bind(null, instance)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// component has a render function but no setup function
|
// component has a render function but no setup function
|
||||||
|
@ -247,7 +242,7 @@ export function createComponent(
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// in prod result can only be block
|
// in prod result can only be block
|
||||||
instance.block = setupResult as Block
|
instance.block = normalizeNode(setupResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,18 +286,33 @@ export let isApplyingFallthroughProps = false
|
||||||
*/
|
*/
|
||||||
export function devRender(instance: VaporComponentInstance): void {
|
export function devRender(instance: VaporComponentInstance): void {
|
||||||
instance.block =
|
instance.block =
|
||||||
callWithErrorHandling(
|
(instance.type.render
|
||||||
instance.type.render!,
|
? callWithErrorHandling(
|
||||||
instance,
|
instance.type.render,
|
||||||
ErrorCodes.RENDER_FUNCTION,
|
instance,
|
||||||
[
|
ErrorCodes.RENDER_FUNCTION,
|
||||||
instance.setupState,
|
[
|
||||||
instance.props,
|
instance.setupState,
|
||||||
instance.emit,
|
instance.props,
|
||||||
instance.attrs,
|
instance.emit,
|
||||||
instance.slots,
|
instance.attrs,
|
||||||
],
|
instance.slots,
|
||||||
) || []
|
],
|
||||||
|
)
|
||||||
|
: callWithErrorHandling(
|
||||||
|
isFunction(instance.type) ? instance.type : instance.type.setup!,
|
||||||
|
instance,
|
||||||
|
ErrorCodes.SETUP_FUNCTION,
|
||||||
|
[
|
||||||
|
instance.props,
|
||||||
|
{
|
||||||
|
slots: instance.slots,
|
||||||
|
attrs: instance.attrs,
|
||||||
|
emit: instance.emit,
|
||||||
|
expose: instance.expose,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)) || []
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyContext: GenericAppContext = {
|
const emptyContext: GenericAppContext = {
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { type Block, VaporFragment, isBlock } from '../block'
|
||||||
|
import { isArray } from '@vue/shared'
|
||||||
|
|
||||||
/*! #__NO_SIDE_EFFECTS__ */
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
export function createTextNode(value = ''): Text {
|
export function createTextNode(value = ''): Text {
|
||||||
return document.createTextNode(value)
|
return document.createTextNode(value)
|
||||||
|
@ -27,3 +30,24 @@ export function nthChild(node: Node, i: number): Node {
|
||||||
export function next(node: Node): Node {
|
export function next(node: Node): Node {
|
||||||
return node.nextSibling!
|
return node.nextSibling!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeChildAtom = Node | string | number | boolean | null | undefined | void
|
||||||
|
|
||||||
|
export type NodeArrayChildren = Array<NodeArrayChildren | NodeChildAtom>
|
||||||
|
|
||||||
|
export type NodeChild = NodeChildAtom | NodeArrayChildren
|
||||||
|
|
||||||
|
export function normalizeNode(node: NodeChild): Block {
|
||||||
|
if (node == null || typeof node === 'boolean') {
|
||||||
|
// empty placeholder
|
||||||
|
return createComment('')
|
||||||
|
} else if (isArray(node) && node.length) {
|
||||||
|
// fragment
|
||||||
|
return new VaporFragment(node.map(normalizeNode))
|
||||||
|
} else if (isBlock(node)) {
|
||||||
|
return node
|
||||||
|
} else {
|
||||||
|
// strings and numbers
|
||||||
|
return createTextNode(String(node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,11 @@ export type { VaporDirective } from './directives/custom'
|
||||||
// compiler-use only
|
// compiler-use only
|
||||||
export { insert, prepend, remove, isFragment, VaporFragment } from './block'
|
export { insert, prepend, remove, isFragment, VaporFragment } from './block'
|
||||||
export { setInsertionState } from './insertionState'
|
export { setInsertionState } from './insertionState'
|
||||||
export { createComponent, createComponentWithFallback } from './component'
|
export {
|
||||||
|
createComponent,
|
||||||
|
createComponentWithFallback,
|
||||||
|
isVaporComponent,
|
||||||
|
} from './component'
|
||||||
export { renderEffect } from './renderEffect'
|
export { renderEffect } from './renderEffect'
|
||||||
export { createSlot } from './componentSlots'
|
export { createSlot } from './componentSlots'
|
||||||
export { template } from './dom/template'
|
export { template } from './dom/template'
|
||||||
|
|
|
@ -154,7 +154,7 @@ function createVDOMComponent(
|
||||||
const frag = new VaporFragment([])
|
const frag = new VaporFragment([])
|
||||||
const vnode = createVNode(
|
const vnode = createVNode(
|
||||||
component,
|
component,
|
||||||
rawProps && new Proxy(rawProps, rawPropsProxyHandlers),
|
rawProps && extend({}, new Proxy(rawProps, rawPropsProxyHandlers)),
|
||||||
)
|
)
|
||||||
const wrapper = new VaporComponentInstance(
|
const wrapper = new VaporComponentInstance(
|
||||||
{ props: component.props },
|
{ props: component.props },
|
||||||
|
|
Loading…
Reference in New Issue