Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions packages/runtime-vapor/__tests__/component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,29 @@ describe('component', () => {
__DEV__ = true
})

test('setup and render co-usage in production mode', () => {
__DEV__ = false
const { component: Child } = define({
setup: () => ({ foo: 'foo' }),
render() {
return template('<div> HI </div>', true)()
},
})

let exposed: Record<string, any> | null = {}
const { host } = define({
setup() {
let child = createComponent(Child, null, null, true)
exposed = child.exposed
return child
},
}).render()

expect(exposed.foo).toBe('foo')
expect(host.innerHTML).toBe('<div> HI </div>')
__DEV__ = true
})

it('warn if functional vapor component not return a block', () => {
// @ts-expect-error
define(() => {
Expand Down
29 changes: 21 additions & 8 deletions packages/runtime-vapor/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,21 +1025,34 @@ function handleSetupResult(
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
instance.devtoolsRawSetupState = setupResult
}
instance.exposed || instance.expose(setupResult)
instance.setupState = proxyRefs(setupResult)
if (__DEV__) {
instance.setupState = createDevSetupStateProxy(instance)
}
devRender(instance)
}
} else {
// component has a render function but no setup function
// (typically components with only a template and no state)
if (setupResult === EMPTY_OBJ && component.render) {
instance.block = callWithErrorHandling(
component.render,
instance,
ErrorCodes.RENDER_FUNCTION,
)
// component has a render function with either:
// - no setup function (components with only a template)
// - setup returning non-block state for use in render
// support setup fn and render fn co-usage for expose
if (!isBlock(setupResult) && component.render) {
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing devtoolsRawSetupState assignment for production devtools support.

The dev-only path at lines 965-966 sets instance.devtoolsRawSetupState when __DEV__ || __FEATURE_PROD_DEVTOOLS__ is true. This production code path should have the same assignment to ensure devtools work correctly in production builds with devtools enabled.

Suggestion: Add before line 979:

if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
  instance.devtoolsRawSetupState = setupResult
}
Suggested change
if (!isBlock(setupResult) && component.render) {
if (!isBlock(setupResult) && component.render) {
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
instance.devtoolsRawSetupState = setupResult
}

Copilot uses AI. Check for mistakes.
instance.exposed || instance.expose(setupResult)
instance.setupState = proxyRefs(setupResult)
instance.block =
callWithErrorHandling(
component.render,
instance,
ErrorCodes.RENDER_FUNCTION,
[
instance.setupState,
instance.props,
instance.emit,
instance.attrs,
instance.slots,
],
) || []
Comment on lines 1040 to 1055
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new setup + render co-usage functionality in production mode.

While there's an existing test at line 420 in component.spec.ts that tests setup + render together, it only verifies dev warnings for non-existent property access. The new production code path (lines 978-992) lacks test coverage for:

  1. Verifying that setupState properties (especially refs) are properly accessible and unwrapped in the render function in production mode
  2. Testing that the render function receives the correct parameters in the expected order
  3. Ensuring devtools integration works correctly with devtoolsRawSetupState

Consider adding a test that:

  • Sets __DEV__ = false
  • Creates a component with both setup (returning refs/reactive state) and render functions
  • Verifies the render function can access and use the setup state correctly

Copilot uses AI. Check for mistakes.
} else {
// in prod result can only be block
instance.block = setupResult as Block
Expand Down
Loading