Browse Source

wip(vapor): per-file vapor support in sfc playground

Evan You 1 year ago
parent
commit
aa84afc199

+ 1 - 1
packages-private/sfc-playground/package.json

@@ -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:*"

+ 9 - 51
packages-private/sfc-playground/src/App.vue

@@ -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()

+ 0 - 9
packages-private/sfc-playground/src/Header.vue

@@ -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"

+ 5 - 3
packages/compiler-sfc/src/compileScript.ts

@@ -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__, { ... })

+ 4 - 5
packages/compiler-sfc/src/compileTemplate.ts

@@ -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
 

+ 1 - 0
packages/runtime-vapor/src/apiDefineComponent.ts

@@ -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
 }

+ 1 - 0
packages/runtime-vapor/src/vdomInterop.ts

@@ -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
   },

+ 5 - 5
pnpm-lock.yaml

@@ -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: