]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test(vapor): apiCreateVaporApp
authorEvan You <evan@vuejs.org>
Tue, 10 Dec 2024 04:49:47 +0000 (12:49 +0800)
committerEvan You <evan@vuejs.org>
Tue, 10 Dec 2024 04:49:47 +0000 (12:49 +0800)
packages/runtime-core/src/component.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/profiling.ts
packages/runtime-core/src/warning.ts
packages/runtime-vapor/__tests__/apiCreateSelector.spec.ts
packages/runtime-vapor/__tests__/apiCreateVaporApp.spec.ts
packages/runtime-vapor/__tests__/apiExpose.spec.ts
packages/runtime-vapor/__tests__/dom/templateRef.spec.ts
packages/runtime-vapor/src/apiCreateApp.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/renderEffect.ts

index 72a595258a441701cc10d784a5f5f2a6789b3a71..db717f84e9adc71ccd0c4f61dcb3dc3efdb4860d 100644 (file)
@@ -785,6 +785,9 @@ export function createComponentInstance(
   return instance
 }
 
+/**
+ * @internal
+ */
 export function validateComponentName(
   name: string,
   { isNativeTag }: AppConfig,
index 00bc68573d79fda611aef808d7a4170572b93936..0a0313e1d79681157ad12dd18b8cc388ffe2bbdb 100644 (file)
@@ -500,6 +500,7 @@ export {
   type GenericComponentInstance,
   type LifecycleHook,
   nextUid,
+  validateComponentName,
 } from './component'
 export { pushWarningContext, popWarningContext } from './warning'
 export {
@@ -512,3 +513,4 @@ export {
   simpleSetCurrentInstance,
 } from './componentCurrentInstance'
 export { registerHMR, unregisterHMR } from './hmr'
+export { startMeasure, endMeasure } from './profiling'
index 1984f5a21f2c10168c1f2692797d61dfcda85780..ec789de721170de2acd09a73189652aa8f929f7d 100644 (file)
@@ -1,15 +1,15 @@
 /* eslint-disable no-restricted-globals */
-import {
-  type ComponentInternalInstance,
-  formatComponentName,
-} from './component'
+import { type GenericComponentInstance, formatComponentName } from './component'
 import { devtoolsPerfEnd, devtoolsPerfStart } from './devtools'
 
 let supported: boolean
 let perf: Performance
 
+/**
+ * @internal
+ */
 export function startMeasure(
-  instance: ComponentInternalInstance,
+  instance: GenericComponentInstance,
   type: string,
 ): void {
   if (instance.appContext.config.performance && isSupported()) {
@@ -21,8 +21,11 @@ export function startMeasure(
   }
 }
 
+/**
+ * @internal
+ */
 export function endMeasure(
-  instance: ComponentInternalInstance,
+  instance: GenericComponentInstance,
   type: string,
 ): void {
   if (instance.appContext.config.performance && isSupported()) {
index 222a576c2bf2d60507458d62ba0a1f9f193b1b51..c261bf602bd8b495ff23458dba69ee0a91c23b17 100644 (file)
@@ -57,7 +57,7 @@ export function warn(msg: string, ...args: any[]): void {
       [
         // eslint-disable-next-line no-restricted-syntax
         msg + args.map(a => a.toString?.() ?? JSON.stringify(a)).join(''),
-        instance && instance.proxy,
+        (instance && instance.proxy) || instance,
         trace
           .map(
             ({ ctx }) =>
index 87dbf5aba5d5ebec50e54e4936bece23de9d9d68..05f95bf081e40e82b45049836d85e6e0f4735d0d 100644 (file)
@@ -1,6 +1,8 @@
 import { ref } from '@vue/reactivity'
 import { makeRender } from './_utils'
-// import { createFor, createSelector, nextTick, renderEffect } from '../src'
+// @ts-expect-error
+import { createFor, createSelector, renderEffect } from '../src'
+import { nextTick } from '@vue/runtime-dom'
 
 const define = makeRender()
 
@@ -16,6 +18,7 @@ describe.todo('api: createSelector', () => {
       const isSleected = createSelector(index)
       return createFor(
         () => list.value,
+        // @ts-expect-error
         ([item]) => {
           const span = document.createElement('li')
           renderEffect(() => {
@@ -25,6 +28,7 @@ describe.todo('api: createSelector', () => {
           })
           return span
         },
+        // @ts-expect-error
         item => item.id,
       )
     }).render()
@@ -66,10 +70,12 @@ describe.todo('api: createSelector', () => {
     const { host } = define(() => {
       const isSleected = createSelector(
         index,
+        // @ts-expect-error
         (key, value) => key === value + 1,
       )
       return createFor(
         () => list.value,
+        // @ts-expect-error
         ([item]) => {
           const span = document.createElement('li')
           renderEffect(() => {
@@ -79,6 +85,7 @@ describe.todo('api: createSelector', () => {
           })
           return span
         },
+        // @ts-expect-error
         item => item.id,
       )
     }).render()
index faa76067552d8679ccd6999863a0f08239b011d1..a8bbd96a99a3a15110307f4cabcd48981fe76f96 100644 (file)
@@ -1,25 +1,29 @@
 import {
-  type ComponentInternalInstance,
-  type Plugin,
   createComponent,
   createTextNode,
   createVaporApp,
-  defineComponent,
-  getCurrentInstance,
+  defineVaporComponent,
+  // @ts-expect-error
+  withDirectives,
+} from '../src'
+import {
+  type GenericComponentInstance,
+  type Plugin,
+  currentInstance,
   inject,
   provide,
   resolveComponent,
   resolveDirective,
-  withDirectives,
-} from '../src'
-import { warn } from '@vue/runtime-dom'
+  warn,
+} from '@vue/runtime-dom'
 import { makeRender } from './_utils'
+import type { VaporComponent } from '../src/component'
 
 const define = makeRender()
 
-describe.todo('api: createVaporApp', () => {
+describe('api: createVaporApp', () => {
   test('mount', () => {
-    const Comp = defineComponent({
+    const Comp = defineVaporComponent({
       props: {
         count: { default: 0 },
       },
@@ -51,7 +55,7 @@ describe.todo('api: createVaporApp', () => {
   })
 
   test('unmount', () => {
-    const Comp = defineComponent({
+    const Comp = defineVaporComponent({
       props: {
         count: { default: 0 },
       },
@@ -82,22 +86,22 @@ describe.todo('api: createVaporApp', () => {
       },
     })
 
-    const Child = defineComponent({
+    const Child = defineVaporComponent({
       setup() {
         const foo = inject('foo')
         const bar = inject('bar')
         try {
           inject('__proto__')
         } catch (e: any) {}
-        return createTextNode(() => [`${foo},${bar}`])
+        return createTextNode([`${foo},${bar}`])
       },
     })
 
-    const { app, mount, create, host } = Root.create(null)
+    const { app, mount, create, html } = Root.create()
     app.provide('foo', 1)
     app.provide('bar', 2)
     mount()
-    expect(host.innerHTML).toBe(`3,2`)
+    expect(html()).toBe(`3,2`)
     expect('[Vue warn]: injection "__proto__" not found.').toHaveBeenWarned()
 
     const { app: app2 } = create()
@@ -132,8 +136,8 @@ describe.todo('api: createVaporApp', () => {
   test('component', () => {
     const { app, mount, host } = define({
       setup() {
-        const FooBar = resolveComponent('foo-bar')
-        const BarBaz = resolveComponent('bar-baz')
+        const FooBar = resolveComponent('foo-bar') as VaporComponent
+        const BarBaz = resolveComponent('bar-baz') as VaporComponent
         return [createComponent(FooBar), createComponent(BarBaz)]
       },
     }).create()
@@ -152,7 +156,7 @@ describe.todo('api: createVaporApp', () => {
     expect(host.innerHTML).toBe(`foobar!barbaz!`)
   })
 
-  test('directive', () => {
+  test.todo('directive', () => {
     const spy1 = vi.fn()
     const spy2 = vi.fn()
 
@@ -229,7 +233,7 @@ describe.todo('api: createVaporApp', () => {
 
   test('config.errorHandler', () => {
     const error = new Error()
-    let instance: ComponentInternalInstance
+    let instance: GenericComponentInstance
 
     const handler = vi.fn((err, _instance, info) => {
       expect(err).toBe(error)
@@ -239,7 +243,8 @@ describe.todo('api: createVaporApp', () => {
 
     const { app, mount } = define({
       setup() {
-        instance = getCurrentInstance()!
+        instance = currentInstance!
+        return {}
       },
       render() {
         throw error
@@ -251,7 +256,7 @@ describe.todo('api: createVaporApp', () => {
   })
 
   test('config.warnHandler', () => {
-    let instance: ComponentInternalInstance
+    let instance: GenericComponentInstance
 
     const handler = vi.fn((msg, _instance, trace) => {
       expect(msg).toMatch(`warn message`)
@@ -262,8 +267,9 @@ describe.todo('api: createVaporApp', () => {
     const { app, mount } = define({
       name: 'Hello',
       setup() {
-        instance = getCurrentInstance()!
+        instance = currentInstance!
         warn('warn message')
+        return []
       },
     }).create()
 
@@ -275,22 +281,23 @@ describe.todo('api: createVaporApp', () => {
   describe('config.isNativeTag', () => {
     const isNativeTag = vi.fn(tag => tag === 'div')
 
-    test('Component.name', () => {
-      const { app, mount } = define({
-        name: 'div',
-        render(): any {},
-      }).create()
+    // Not relevant for vapor
+    // test('Component.name', () => {
+    //   const { app, mount } = define({
+    //     name: 'div',
+    //     render(): any {},
+    //   }).create()
 
-      Object.defineProperty(app.config, 'isNativeTag', {
-        value: isNativeTag,
-        writable: false,
-      })
+    //   Object.defineProperty(app.config, 'isNativeTag', {
+    //     value: isNativeTag,
+    //     writable: false,
+    //   })
 
-      mount()
-      expect(
-        `Do not use built-in or reserved HTML elements as component id: div`,
-      ).toHaveBeenWarned()
-    })
+    //   mount()
+    //   expect(
+    //     `Do not use built-in or reserved HTML elements as component id: div`,
+    //   ).toHaveBeenWarned()
+    // })
 
     test('register using app.component', () => {
       const { app, mount } = define({
@@ -316,7 +323,7 @@ describe.todo('api: createVaporApp', () => {
     })
 
     test('with performance enabled', () => {
-      const { app, mount } = define({}).create()
+      const { app, mount } = define({ setup: () => [] }).create()
 
       app.config.performance = true
       mount()
@@ -324,7 +331,7 @@ describe.todo('api: createVaporApp', () => {
     })
 
     test('with performance disabled', () => {
-      const { app, mount } = define({}).create()
+      const { app, mount } = define({ setup: () => [] }).create()
 
       app.config.performance = false
       mount()
@@ -333,14 +340,16 @@ describe.todo('api: createVaporApp', () => {
   })
 
   test('config.globalProperty', () => {
-    const { app, mount, html } = define({
-      render() {
-        const instance = getCurrentInstance()!
-        return createTextNode([instance.appContext.config.globalProperties.msg])
+    const { app } = define({
+      setup() {
+        return []
       },
     }).create()
-    app.config.globalProperties.msg = 'hello world'
-    mount()
-    expect(html()).toBe('hello world')
+    try {
+      app.config.globalProperties.msg = 'hello world'
+    } catch (e) {}
+    expect(
+      `app.config.globalProperties is not supported in vapor mode`,
+    ).toHaveBeenWarned()
   })
 })
index e5b482c5fb63c88a8abc6ebffcf22e3b69884395..91f2b76afa090dc9a2892a544cc0b319ac02fe4a 100644 (file)
@@ -1,11 +1,8 @@
 import { ref, shallowRef } from '@vue/reactivity'
-import { createComponent } from '../src/component'
+import { type VaporComponentInstance, createComponent } from '../src/component'
 import { setRef } from '../src/dom/templateRef'
 import { makeRender } from './_utils'
-import {
-  type ComponentInternalInstance,
-  getCurrentInstance,
-} from '../src/component'
+import { currentInstance } from '@vue/runtime-dom'
 import { defineVaporComponent } from '../src/apiDefineComponent'
 
 const define = makeRender()
@@ -39,10 +36,11 @@ describe.todo('api: expose', () => {
   })
 
   test('via setup context (expose empty)', () => {
-    let childInstance: ComponentInternalInstance | null = null
+    let childInstance: VaporComponentInstance | null = null
     const Child = defineVaporComponent({
       setup(_) {
-        childInstance = getCurrentInstance()
+        childInstance = currentInstance as VaporComponentInstance
+        return []
       },
     })
     const childRef = shallowRef()
@@ -77,6 +75,7 @@ describe.todo('api: expose', () => {
     define({
       setup(_, { expose }) {
         expose(ref(1))
+        return []
       },
     }).render()
 
@@ -89,6 +88,7 @@ describe.todo('api: expose', () => {
     define({
       setup(_, { expose }) {
         expose(['focus'])
+        return []
       },
     }).render()
 
@@ -101,6 +101,7 @@ describe.todo('api: expose', () => {
     define({
       setup(_, { expose }) {
         expose(() => null)
+        return []
       },
     }).render()
 
index 16bd6403c3825319bf56a0762626376e2ba2a0f3..f4fb1d0774fb5b28a966ec08442543e692c7561e 100644 (file)
@@ -1,19 +1,23 @@
 import type { NodeRef } from '../../src/dom/templateRef'
 import {
+  // @ts-expect-error
   createFor,
+  // @ts-expect-error
   createIf,
-  getCurrentInstance,
   insert,
-  nextTick,
-  reactive,
-  ref,
   renderEffect,
   setRef,
   setText,
   template,
-  watchEffect,
 } from '../../src'
 import { makeRender } from '../_utils'
+import {
+  currentInstance,
+  nextTick,
+  reactive,
+  ref,
+  watchEffect,
+} from '@vue/runtime-dom'
 
 const define = makeRender()
 
@@ -257,7 +261,7 @@ describe.todo('api: template ref', () => {
     const t1 = template('<i></i>')
     const { render } = define({
       render() {
-        const instance = getCurrentInstance()!
+        const instance = currentInstance!
         const n0 = t0()
         const n1 = t1()
         let r0: NodeRef | undefined
@@ -303,7 +307,7 @@ describe.todo('api: template ref', () => {
     const t1 = template('<i></i>')
     const { render } = define({
       render() {
-        const instance = getCurrentInstance()!
+        const instance = currentInstance!
         const n0 = createIf(
           () => refToggle.value,
           () => {
@@ -355,6 +359,7 @@ describe.todo('api: template ref', () => {
             const n1 = t0()
             const n2 = createFor(
               () => list,
+              // @ts-expect-error
               state => {
                 const n1 = t1()
                 setRef(n1 as Element, listRefs, undefined, true)
@@ -413,6 +418,7 @@ describe.todo('api: template ref', () => {
             const n1 = t0()
             const n2 = createFor(
               () => list,
+              // @ts-expect-error
               state => {
                 const n1 = t1()
                 setRef(n1 as Element, 'listRefs', undefined, true)
@@ -469,6 +475,7 @@ describe.todo('api: template ref', () => {
         const n2 = n1!.nextSibling!
         const n3 = createFor(
           () => list.value,
+          // @ts-expect-error
           state => {
             const n4 = t1()
             setRef(n4 as Element, 'listRefs', undefined, true)
index fc976f7b5fc56fceed5cfe32e795254c35ee3a81..7c4db89618a0c1bfb14d64965bc0f4437e2a2d75 100644 (file)
@@ -11,6 +11,7 @@ import {
   type CreateAppFunction,
   createAppAPI,
   normalizeContainer,
+  warn,
 } from '@vue/runtime-dom'
 import type { RawProps } from './componentProps'
 
@@ -21,7 +22,13 @@ const mountApp: AppMountFn<ParentNode> = (app, container) => {
   if (container.nodeType === 1 /* Node.ELEMENT_NODE */) {
     container.textContent = ''
   }
-  const instance = createComponent(app._component, app._props as RawProps)
+  const instance = createComponent(
+    app._component,
+    app._props as RawProps,
+    null,
+    false,
+    app._context,
+  )
   mountComponent(instance, container)
   return instance
 }
@@ -36,6 +43,19 @@ export const createVaporApp: CreateAppFunction<ParentNode, VaporComponent> = (
 ) => {
   if (!_createApp) _createApp = createAppAPI(mountApp, unmountApp, i => i)
   const app = _createApp(comp, props)
+
+  if (__DEV__) {
+    app.config.globalProperties = new Proxy(
+      {},
+      {
+        set() {
+          warn(`app.config.globalProperties is not supported in vapor mode.`)
+          return false
+        },
+      },
+    )
+  }
+
   const mount = app.mount
   app.mount = (container, ...args: any[]) => {
     container = normalizeContainer(container) as ParentNode
index 033b2fa6a26fba5c4556d349474d6ac6b792b30e..f544809b7d68166b5c5e749bde77244e6e8f81d4 100644 (file)
@@ -13,11 +13,13 @@ import {
   type SuspenseBoundary,
   callWithErrorHandling,
   currentInstance,
+  endMeasure,
   nextUid,
   popWarningContext,
   pushWarningContext,
   registerHMR,
   simpleSetCurrentInstance,
+  startMeasure,
   unregisterHMR,
   warn,
 } from '@vue/runtime-dom'
@@ -100,6 +102,7 @@ export function createComponent(
   rawProps?: RawProps | null,
   rawSlots?: RawSlots | null,
   isSingleRoot?: boolean,
+  appContext?: GenericAppContext,
 ): VaporComponentInstance {
   // check if we are the single root of the parent
   // if yes, inject parent attrs as dynamic props source
@@ -117,15 +120,22 @@ export function createComponent(
     }
   }
 
-  const instance = new VaporComponentInstance(component, rawProps, rawSlots)
-  const prev = currentInstance
-  simpleSetCurrentInstance(instance)
+  const instance = new VaporComponentInstance(
+    component,
+    rawProps,
+    rawSlots,
+    appContext,
+  )
 
-  pauseTracking()
   if (__DEV__) {
     pushWarningContext(instance)
+    startMeasure(instance, `init`)
   }
 
+  const prev = currentInstance
+  simpleSetCurrentInstance(instance)
+  pauseTracking()
+
   const setupFn = isFunction(component) ? component : component.setup
   const setupContext = (instance.setupContext =
     setupFn && setupFn.length > 1 ? new SetupContext(instance) : null)
@@ -177,11 +187,13 @@ export function createComponent(
     })
   }
 
+  resetTracking()
+  simpleSetCurrentInstance(prev, instance)
+
   if (__DEV__) {
     popWarningContext()
+    endMeasure(instance, 'init')
   }
-  resetTracking()
-  simpleSetCurrentInstance(prev, instance)
 
   return instance
 }
@@ -280,6 +292,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
     comp: VaporComponent,
     rawProps?: RawProps | null,
     rawSlots?: RawSlots | null,
+    appContext?: GenericAppContext,
   ) {
     this.vapor = true
     this.uid = nextUid()
@@ -295,7 +308,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
       this.provides = currentInstance.provides
       this.ids = currentInstance.ids
     } else {
-      this.appContext = emptyContext
+      this.appContext = appContext || emptyContext
       this.provides = Object.create(this.appContext.provides)
       this.ids = ['', 0, 0]
     }
@@ -417,6 +430,9 @@ export function mountComponent(
   parent: ParentNode,
   anchor?: Node | null | 0,
 ): void {
+  if (__DEV__) {
+    startMeasure(instance, `mount`)
+  }
   if (!instance.isMounted) {
     if (instance.bm) invokeArrayFns(instance.bm)
     insert(instance.block, parent, anchor)
@@ -427,6 +443,9 @@ export function mountComponent(
   } else {
     insert(instance.block, parent, anchor)
   }
+  if (__DEV__) {
+    endMeasure(instance, `mount`)
+  }
 }
 
 export function unmountComponent(
index 6dec684b09004594607ea60c5c903ebea4d69bbe..b3d10b758900dc2e0caeb16a689acae3e5f1960e 100644 (file)
@@ -5,13 +5,14 @@ import {
   queueJob,
   queuePostFlushCb,
   simpleSetCurrentInstance,
+  startMeasure,
   warn,
 } from '@vue/runtime-dom'
 import { type VaporComponentInstance, isVaporComponent } from './component'
 import { invokeArrayFns } from '@vue/shared'
 
 export function renderEffect(fn: () => void, noLifecycle = false): void {
-  const instance = currentInstance as VaporComponentInstance
+  const instance = currentInstance as VaporComponentInstance | null
   const scope = getCurrentScope()
   if (__DEV__ && !__TEST__ && !isVaporComponent(instance)) {
     warn('renderEffect called without active vapor instance.')
@@ -20,6 +21,9 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
   const renderEffectFn = noLifecycle
     ? fn
     : () => {
+        if (__DEV__ && instance) {
+          startMeasure(instance, `renderEffect`)
+        }
         const prev = currentInstance
         simpleSetCurrentInstance(instance)
         if (scope) scope.on()
@@ -41,6 +45,9 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
         }
         if (scope) scope.off()
         simpleSetCurrentInstance(prev, instance)
+        if (__DEV__ && instance) {
+          startMeasure(instance, `renderEffect`)
+        }
       }
 
   const effect = new ReactiveEffect(renderEffectFn)