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