Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: implement defineVaporCustomElement #14017

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
edison1105 wants to merge 26 commits into minor
base: minor
Choose a base branch
Loading
from edison/feat/defineVaporCustomElement
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e808152
feat: implement defineVaporCustomElement
edison1105 Oct 24, 2025
da010a7
wip: enhance VaporElement with type parameters and pre-rendering support
edison1105 Oct 24, 2025
4b8a7fb
wip: save
edison1105 Oct 24, 2025
9f6a1b1
Merge branch 'minor' into edison/feat/defineVaporCustomElement
edison1105 Oct 27, 2025
1a8027a
wip: save
edison1105 Oct 27, 2025
e770960
chore: Merge branch 'minor' into edison/feat/defineVaporCustomElement
edison1105 Oct 27, 2025
2ca34e6
wip: process custom element as component
edison1105 Oct 27, 2025
8c1fc4d
fix: ignore errors caused by accessing Node after the test environmen...
edison1105 Oct 27, 2025
cf806db
wip: save
edison1105 Oct 27, 2025
225428c
test: add more tests
edison1105 Oct 28, 2025
f7290b6
wip: enhance slot rendering for custom elements
edison1105 Oct 28, 2025
7e29657
wip: save
edison1105 Oct 28, 2025
9fa0d63
fix: update createComponent call to include app context
edison1105 Oct 28, 2025
a590cfc
fix: enhance HMR style handling and component style injection
edison1105 Oct 28, 2025
f6eaa88
wip: save
edison1105 Oct 28, 2025
4edb144
wip: save
edison1105 Oct 28, 2025
836db6b
wip: save
edison1105 Oct 28, 2025
cbf18fb
refactor: handling slot update
edison1105 Oct 28, 2025
ccbb170
test: enhance nested custom element and teleport rendering with shado...
edison1105 Oct 28, 2025
cf93845
wip: save
edison1105 Oct 29, 2025
9b5e134
refactor: replace getCurrentInstance with getCurrentGenericInstance i...
edison1105 Oct 29, 2025
6bc0420
wip: add SSR support
edison1105 Oct 29, 2025
579ace9
test: remove tests
edison1105 Oct 29, 2025
fb06fcf
chore: tweaks
edison1105 Oct 29, 2025
d5b2e38
refactor: add createPlainElement helper
edison1105 Oct 29, 2025
8a298fa
feat: add useInstanceOption for safer instance access
edison1105 Oct 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,15 @@ export function render(_ctx) {
}"
`;

exports[`compiler: element transform > custom element 1`] = `
"import { createPlainElement as _createPlainElement } from 'vue';

export function render(_ctx) {
const n0 = _createPlainElement("my-custom-element", null, null, true)
return n0
}"
`;

exports[`compiler: element transform > dynamic component > capitalized version w/ static binding 1`] = `
"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -1037,4 +1037,15 @@ describe('compiler: element transform', () => {
expect(code).toMatchSnapshot()
expect(code).contain('return null')
})

test('custom element', () => {
const { code } = compileWithElementTransform(
'<my-custom-element></my-custom-element>',
{
isCustomElement: tag => tag === 'my-custom-element',
},
)
expect(code).toMatchSnapshot()
expect(code).toContain('createPlainElement')
})
})
12 changes: 8 additions & 4 deletions packages/compiler-vapor/src/generators/component.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ export function genCreateComponent(
...genCall(
operation.dynamic && !operation.dynamic.isStatic
? helper('createDynamicComponent')
: operation.asset
? helper('createComponentWithFallback')
: helper('createComponent'),
: operation.isCustomElement
? helper('createPlainElement')
: operation.asset
? helper('createComponentWithFallback')
: helper('createComponent'),
tag,
rawProps,
rawSlots,
Expand All @@ -86,7 +88,9 @@ export function genCreateComponent(
]

function genTag() {
if (operation.dynamic) {
if (operation.isCustomElement) {
return JSON.stringify(operation.tag)
} else if (operation.dynamic) {
if (operation.dynamic.isStatic) {
return genCall(
helper('resolveDynamicComponent'),
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/ir/index.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export interface CreateComponentIRNode extends BaseIRNode {
root: boolean
once: boolean
dynamic?: SimpleExpressionNode
isCustomElement: boolean
parent?: number
anchor?: number
append?: boolean
Expand Down
19 changes: 14 additions & 5 deletions packages/compiler-vapor/src/transforms/transformElement.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ export const transformElement: NodeTransform = (node, context) => {
)
return

const isComponent = node.tagType === ElementTypes.COMPONENT
// treat custom elements as components because the template helper cannot
// resolve them properly; they require creation via createElement
const isCustomElement = !!context.options.isCustomElement(node.tag)
const isComponent =
node.tagType === ElementTypes.COMPONENT || isCustomElement

const isDynamicComponent = isComponentTag(node.tag)
const propsResult = buildProps(
node,
Expand All @@ -77,9 +82,10 @@ export const transformElement: NodeTransform = (node, context) => {
parent = parent.parent
}
const singleRoot =
context.root === parent &&
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
.length === 1
(context.root === parent &&
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
.length === 1) ||
isCustomElement

if (isComponent) {
transformComponentElement(
Expand All @@ -88,6 +94,7 @@ export const transformElement: NodeTransform = (node, context) => {
singleRoot,
context,
isDynamicComponent,
isCustomElement,
)
} else {
transformNativeElement(
Expand All @@ -107,6 +114,7 @@ function transformComponentElement(
singleRoot: boolean,
context: TransformContext,
isDynamicComponent: boolean,
isCustomElement: boolean,
) {
const dynamicComponent = isDynamicComponent
? resolveDynamicComponent(node)
Expand All @@ -115,7 +123,7 @@ function transformComponentElement(
let { tag } = node
let asset = true

if (!dynamicComponent) {
if (!dynamicComponent && !isCustomElement) {
const fromSetup = resolveSetupReference(tag, context)
if (fromSetup) {
tag = fromSetup
Expand Down Expand Up @@ -160,6 +168,7 @@ function transformComponentElement(
slots: [...context.slots],
once: context.inVOnce,
dynamic: dynamicComponent,
isCustomElement,
}
context.slots = []
}
Expand Down
5 changes: 5 additions & 0 deletions packages/runtime-core/src/apiCreateApp.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export interface App<HostElement = any> {
*/
_ceVNode?: VNode

/**
* @internal vapor custom element instance
*/
_ceComponent?: GenericComponentInstance | null

/**
* v2 compat only
*/
Expand Down
34 changes: 34 additions & 0 deletions packages/runtime-core/src/componentCurrentInstance.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
} from './component'
import { currentRenderingInstance } from './componentRenderContext'
import { type EffectScope, setCurrentScope } from '@vue/reactivity'
import { warn } from './warning'

/**
* @internal
Expand Down Expand Up @@ -90,3 +91,36 @@ export const setCurrentInstance = (
simpleSetCurrentInstance(instance)
}
}

const internalOptions = ['ce'] as const

/**
* @internal
*/
export const useInstanceOption = <K extends (typeof internalOptions)[number]>(
key: K,
silent = false,
): {
hasInstance: boolean
value: GenericComponentInstance[K] | undefined
} => {
const instance = getCurrentGenericInstance()
if (!instance) {
if (__DEV__ && !silent) {
warn(`useInstanceOption called without an active component instance.`)
}
return { hasInstance: false, value: undefined }
}

if (!internalOptions.includes(key)) {
if (__DEV__) {
warn(
`useInstanceOption only accepts ` +
` ${internalOptions.map(k => `'${k}'`).join(', ')} as key, got '${key}'.`,
)
}
return { hasInstance: true, value: undefined }
}

return { hasInstance: true, value: instance[key] }
}
11 changes: 10 additions & 1 deletion packages/runtime-core/src/hmr.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,16 @@ function reload(id: string, newComp: HMRComponent): void {
// create a snapshot which avoids the set being mutated during updates
const instances = [...record.instances]

if (newComp.__vapor) {
if (newComp.__vapor && !instances.some(i => i.ceReload)) {
// For multiple instances with the same __hmrId, remove styles first before reload
// to avoid the second instance's style removal deleting the first instance's
// newly added styles (since hmrReload is synchronous)
for (const instance of instances) {
// update custom element child style
if (instance.root && instance.root.ce && instance !== instance.root) {
instance.root.ce._removeChildStyle(instance.type)
}
}
for (const instance of instances) {
instance.hmrReload!(newComp)
}
Expand Down
5 changes: 5 additions & 0 deletions packages/runtime-core/src/index.ts
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ export {
// plugins
export { getCurrentInstance } from './component'

/**
* @internal
*/
export { useInstanceOption } from './component'

// For raw render function users
export { h } from './h'
// Advanced render function utilities
Expand Down
Loading
Loading

AltStyle によって変換されたページ (->オリジナル) /