]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip(vapor): per-file vapor support in sfc playground
authorEvan You <evan@vuejs.org>
Mon, 3 Feb 2025 04:22:45 +0000 (12:22 +0800)
committerEvan You <evan@vuejs.org>
Mon, 3 Feb 2025 04:22:45 +0000 (12:22 +0800)
packages-private/sfc-playground/package.json
packages-private/sfc-playground/src/App.vue
packages-private/sfc-playground/src/Header.vue
packages/compiler-sfc/src/compileScript.ts
packages/compiler-sfc/src/compileTemplate.ts
packages/runtime-vapor/src/apiDefineComponent.ts
packages/runtime-vapor/src/vdomInterop.ts
pnpm-lock.yaml

index e7ea7f37027dbd7b6b8d38c61d8226ece5f3f440..486971ad58b68184b5db98a604b2eae022c95d24 100644 (file)
@@ -13,7 +13,7 @@
     "vite": "catalog:"
   },
   "dependencies": {
-    "@vue/repl": "^4.4.3",
+    "@vue/repl": "^4.5.0",
     "file-saver": "^2.0.5",
     "jszip": "^3.10.1",
     "vue": "workspace:*"
index 2d4069318ae9557840579ce7197d3f3d30443e64..c05738611573c2341a6ff620026f3746aac71a4d 100644 (file)
@@ -5,11 +5,10 @@ import {
   type SFCOptions,
   useStore,
   useVueImportMap,
-  File,
   StoreState,
 } from '@vue/repl'
 import Monaco from '@vue/repl/monaco-editor'
-import { ref, watchEffect, onMounted, computed, watch } from 'vue'
+import { ref, watchEffect, onMounted, computed } from 'vue'
 
 const replRef = ref<InstanceType<typeof Repl>>()
 
@@ -20,7 +19,6 @@ window.addEventListener('resize', setVH)
 setVH()
 
 const useSSRMode = ref(false)
-const useVaporMode = ref(true)
 
 const AUTO_SAVE_STORAGE_KEY = 'vue-sfc-playground-auto-save'
 const initAutoSave: boolean = JSON.parse(
@@ -31,16 +29,12 @@ const autoSave = ref(initAutoSave)
 const { vueVersion, productionMode, importMap } = useVueImportMap({
   runtimeDev: () => {
     return import.meta.env.PROD
-      ? useVaporMode.value
-        ? `${location.origin}/vue.runtime-with-vapor.esm-browser.js`
-        : `${location.origin}/vue.runtime.esm-browser.js`
+      ? `${location.origin}/vue.runtime-with-vapor.esm-browser.js`
       : `${location.origin}/src/vue-dev-proxy`
   },
   runtimeProd: () => {
     return import.meta.env.PROD
-      ? useVaporMode.value
-        ? `${location.origin}/vue.runtime-with-vapor.esm-browser.prod.js`
-        : `${location.origin}/vue.runtime.esm-browser.prod.js`
+      ? `${location.origin}/vue.runtime-with-vapor.esm-browser.prod.js`
       : `${location.origin}/src/vue-dev-proxy-prod`
   },
   serverRenderer: import.meta.env.PROD
@@ -61,10 +55,6 @@ if (hash.startsWith('__SSR__')) {
   hash = hash.slice(7)
   useSSRMode.value = true
 }
-if (hash.startsWith('__VAPOR__')) {
-  hash = hash.slice(9)
-  useVaporMode.value = true
-}
 
 const files: StoreState['files'] = ref(Object.create(null))
 
@@ -75,13 +65,13 @@ const sfcOptions = computed(
       inlineTemplate: productionMode.value,
       isProd: productionMode.value,
       propsDestructure: true,
-      vapor: useVaporMode.value,
+      // vapor: useVaporMode.value,
     },
     style: {
       isProd: productionMode.value,
     },
     template: {
-      vapor: useVaporMode.value,
+      // vapor: useVaporMode.value,
       isProd: productionMode.value,
       compilerOptions: {
         isCustomElement: (tag: string) =>
@@ -103,38 +93,10 @@ const store = useStore(
 // @ts-expect-error
 globalThis.store = store
 
-watch(
-  useVaporMode,
-  () => {
-    if (useVaporMode.value) {
-      files.value['src/index.html'] = new File(
-        'src/index.html',
-        `<script type="module">
-        import { createVaporApp } from 'vue'
-        import App from './App.vue'
-        createVaporApp(App).mount('#app')` +
-          '<' +
-          '/script>' +
-          `<div id="app"></div>`,
-        true,
-      )
-      store.mainFile = 'src/index.html'
-    } else if (files.value['src/index.html']?.hidden) {
-      delete files.value['src/index.html']
-      store.mainFile = 'src/App.vue'
-      if (store.activeFile.filename === 'src/index.html') {
-        store.activeFile = files.value['src/App.vue']
-      }
-    }
-  },
-  { immediate: true },
-)
-
 // persist state
 watchEffect(() => {
   const newHash = store
     .serialize()
-    .replace(/^#/, useVaporMode.value ? `#__VAPOR__` : `#`)
     .replace(/^#/, useSSRMode.value ? `#__SSR__` : `#`)
     .replace(/^#/, productionMode.value ? `#__PROD__` : `#`)
   history.replaceState({}, '', newHash)
@@ -148,10 +110,6 @@ function toggleSSR() {
   useSSRMode.value = !useSSRMode.value
 }
 
-function toggleVapor() {
-  useVaporMode.value = !useVaporMode.value
-}
-
 function toggleAutoSave() {
   autoSave.value = !autoSave.value
   localStorage.setItem(AUTO_SAVE_STORAGE_KEY, String(autoSave.value))
@@ -179,14 +137,12 @@ onMounted(() => {
     :store="store"
     :prod="productionMode"
     :ssr="useSSRMode"
-    :vapor="useVaporMode"
     :autoSave="autoSave"
     :theme="theme"
     @toggle-theme="toggleTheme"
     @toggle-prod="toggleProdMode"
     @toggle-ssr="toggleSSR"
     @toggle-autosave="toggleAutoSave"
-    @toggle-vapor="toggleVapor"
     @reload-page="reloadPage"
   />
   <Repl
@@ -204,8 +160,10 @@ onMounted(() => {
     :clearConsole="false"
     :preview-options="{
       customCode: {
-        importCode: `import { initCustomFormatter } from 'vue'`,
-        useCode: `if (window.devtoolsFormatters) {
+        importCode: `import { initCustomFormatter, vaporInteropPlugin } from 'vue'`,
+        useCode: `
+  app.use(vaporInteropPlugin)
+  if (window.devtoolsFormatters) {
     const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
     window.devtoolsFormatters.splice(index, 1)
     initCustomFormatter()
index ce18ecae9e9ba961adbce207b49c3b09ed1461cd..132453e986d4ba91a984e4a926c8ff0d84b17c59 100644 (file)
@@ -14,7 +14,6 @@ const props = defineProps<{
   store: ReplStore
   prod: boolean
   ssr: boolean
-  vapor: boolean
   autoSave: boolean
   theme: 'dark' | 'light'
 }>()
@@ -105,14 +104,6 @@ function toggleDark() {
       >
         <span>{{ prod ? 'PROD' : 'DEV' }}</span>
       </button>
-      <button
-        title="Toggle vapor mode"
-        class="toggle-vapor"
-        :class="{ enabled: vapor }"
-        @click="$emit('toggle-vapor')"
-      >
-        <span>{{ vapor ? 'VAPOR ON' : 'VAPOR OFF' }}</span>
-      </button>
       <button
         title="Toggle server rendering mode"
         class="toggle-ssr"
index de096ced32162f65927424d9a16e48f0272747ac..15219ec092806714ae7df6d8af63cd749bceebe9 100644 (file)
@@ -874,6 +874,7 @@ export function compileScript(
         scoped: sfc.styles.some(s => s.scoped),
         isProd: options.isProd,
         ssrCssVars: sfc.cssVars,
+        vapor,
         compilerOptions: {
           ...(options.templateOptions &&
             options.templateOptions.compilerOptions),
@@ -942,9 +943,6 @@ export function compileScript(
     : `export default`
 
   let runtimeOptions = ``
-  if (vapor) {
-    runtimeOptions += `\n  __vapor: true,`
-  }
   if (!ctx.hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) {
     const match = filename.match(/([^/\\]+)\.\w+$/)
     if (match) {
@@ -992,6 +990,10 @@ export function compileScript(
     )
     ctx.s.appendRight(endOffset, `})`)
   } else {
+    // in TS, defineVaporComponent adds the option already
+    if (vapor) {
+      runtimeOptions += `\n  __vapor: true,`
+    }
     if (defaultExport || definedOptions) {
       // without TS, can't rely on rest spread, so we use Object.assign
       // export default Object.assign(__default__, { ... })
index bd69fb2cc9f28ea8396ea6764b1d597e0847e548..5f9a1c18ad7dd2e679a7896d6eb3878f04ec2828 100644 (file)
@@ -209,11 +209,10 @@ function doCompileTemplate({
   const shortId = id.replace(/^data-v-/, '')
   const longId = `data-v-${shortId}`
 
-  const defaultCompiler = vapor
-    ? // TODO ssr
-      (CompilerVapor as TemplateCompiler)
-    : ssr
-      ? (CompilerSSR as TemplateCompiler)
+  const defaultCompiler = ssr
+    ? (CompilerSSR as TemplateCompiler)
+    : vapor
+      ? (CompilerVapor as TemplateCompiler)
       : CompilerDOM
   compiler = compiler || defaultCompiler
 
index d23626a53ece7515cab55c8157bb7934c0f9c335..ed70a6495a5d8f4890c490272b16e527d7565777 100644 (file)
@@ -3,5 +3,6 @@ import type { VaporComponent } from './component'
 /*! #__NO_SIDE_EFFECTS__ */
 export function defineVaporComponent(comp: VaporComponent): VaporComponent {
   // TODO type inference
+  comp.__vapor = true
   return comp
 }
index af85cfa06108eafb9b4e3877f267ee2485425285..a515c853d61605a58b28dae84d067f0cfcac7ac7 100644 (file)
@@ -39,6 +39,7 @@ const vaporInVDOMInterface: VaporInVDOMInterface = {
 
   update(n1: VNode, n2: VNode) {
     n2.component = n1.component
+    // TODO if has patchFlag, do simple diff to skip unnecessary updates
     ;(n2.component as any as VaporComponentInstance).rawPropsRef!.value =
       n2.props
   },
index 0d0fb19fe118ce34191231838f0a8704173af6a0..f5afc7c5466057fc66e6aab9e6bc411909e3bb00 100644 (file)
@@ -229,8 +229,8 @@ importers:
   packages-private/sfc-playground:
     dependencies:
       '@vue/repl':
-        specifier: ^4.4.3
-        version: 4.4.3
+        specifier: ^4.5.0
+        version: 4.5.0
       file-saver:
         specifier: ^2.0.5
         version: 2.0.5
@@ -1531,8 +1531,8 @@ packages:
   '@vue/reactivity@3.5.13':
     resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
 
-  '@vue/repl@4.4.3':
-    resolution: {integrity: sha512-MKIaWgmpaDSfcQrzgsoEFW4jpFbdPYFDn9LBvXFQqEUcosheP9IoUcj/u4omp72oxsecFF5YO4/ssp4aaR8e+g==}
+  '@vue/repl@4.5.0':
+    resolution: {integrity: sha512-nWQfTzBePs5zN4qIK+vwEMEDHCuWWx2AY0utun37cSD2Qi4C84dlTtO/OL0xDzBB8Ob7250KYzIzDP3N3l3qLg==}
 
   '@vue/runtime-core@3.5.13':
     resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==}
@@ -4730,7 +4730,7 @@ snapshots:
     dependencies:
       '@vue/shared': 3.5.13
 
-  '@vue/repl@4.4.3': {}
+  '@vue/repl@4.5.0': {}
 
   '@vue/runtime-core@3.5.13':
     dependencies: