build: add runtime-with-vapor format + fix sfc playground for vapor mode

This commit is contained in:
Evan You 2024-12-08 15:18:16 +08:00
parent 9a8645d0c5
commit 7e8edcd9cd
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
17 changed files with 74 additions and 86 deletions

View File

@ -4,21 +4,21 @@
"packageManager": "pnpm@9.12.3",
"type": "module",
"scripts": {
"dev": "node scripts/dev.js vue runtime-vapor",
"dev": "node scripts/dev.js",
"build": "node scripts/build.js",
"build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
"clean": "rimraf --glob packages/*/dist temp .eslintcache",
"size": "run-s \"size-*\" && node scripts/usage-size.js",
"size-global": "node scripts/build.js vue runtime-vapor runtime-dom runtime-vapor compiler-dom -f global -p --size",
"size-global": "node scripts/build.js vue runtime-dom compiler-dom -f global -p --size",
"size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
"size-esm": "node scripts/build.js runtime-shared runtime-dom runtime-vapor runtime-core reactivity shared runtime-vapor -f esm-bundler",
"size-esm": "node scripts/build.js runtime-shared runtime-dom runtime-core reactivity shared runtime-vapor -f esm-bundler",
"check": "tsc --incremental --noEmit",
"lint": "eslint --cache .",
"format": "prettier --write --cache .",
"format-check": "prettier --check --cache .",
"test": "vitest",
"test-unit": "vitest --project unit",
"test-e2e": "node scripts/build.js vue runtime-vapor -f global -d && vitest --project e2e",
"test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e",
"test-dts": "run-s build-dts test-dts-only",
"test-dts-only": "tsc -p packages-private/dts-built-test/tsconfig.json && tsc -p ./packages-private/dts-test/tsconfig.test.json",
"test-coverage": "vitest run --project unit --coverage",
@ -33,15 +33,13 @@
"dev-compiler": "run-p \"dev template-explorer\" serve open",
"dev-sfc": "run-s dev-prepare-cjs dev-sfc-run",
"dev-sfc-serve": "vite packages-private/sfc-playground",
"dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-bundler-runtime\" \"dev vue -ipf esm-browser-runtime\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
"dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if vapor\" \"dev vue -ipf vapor\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
"dev-vapor": "pnpm -C playground run dev",
"serve": "serve",
"open": "open http://localhost:3000/packages-private/template-explorer/local.html",
"build-sfc-playground": "run-s build-all-cjs build-runtime-esm build-browser-esm build-ssr-esm build-sfc-playground-self",
"build-sfc-playground": "run-s build-all-cjs build-all-esm build-sfc-playground-self",
"build-all-cjs": "node scripts/build.js vue runtime compiler reactivity shared -af cjs",
"build-runtime-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler-runtime && node scripts/build.js vue -f esm-browser-runtime",
"build-browser-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler && node scripts/build.js vue -f esm-browser",
"build-ssr-esm": "node scripts/build.js compiler-sfc server-renderer runtime-vapor -f esm-browser",
"build-all-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler,esm-browser,esm-bundler-runtime,esm-browser-runtime && node scripts/build.js compiler-sfc server-renderer -f esm-browser",
"build-sfc-playground-self": "cd packages-private/sfc-playground && npm run build",
"preinstall": "npx only-allow pnpm",
"postinstall": "simple-git-hooks"

View File

@ -5,10 +5,8 @@ import {
type SFCOptions,
useStore,
useVueImportMap,
mergeImportMap,
File,
StoreState,
ImportMap,
} from '@vue/repl'
import Monaco from '@vue/repl/monaco-editor'
import { ref, watchEffect, onMounted, computed, watch } from 'vue'
@ -31,36 +29,26 @@ const initAutoSave: boolean = JSON.parse(
)
const autoSave = ref(initAutoSave)
const {
vueVersion,
productionMode,
importMap: vueImportMap,
} = useVueImportMap({
runtimeDev: import.meta.env.PROD
? `${location.origin}/vue.runtime.esm-browser.js`
: `${location.origin}/src/vue-dev-proxy`,
runtimeProd: import.meta.env.PROD
? `${location.origin}/vue.runtime.esm-browser.prod.js`
: `${location.origin}/src/vue-dev-proxy-prod`,
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}/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}/src/vue-dev-proxy-prod`
},
serverRenderer: import.meta.env.PROD
? `${location.origin}/server-renderer.esm-browser.js`
: `${location.origin}/src/vue-server-renderer-dev-proxy`,
})
const importMap = computed(() => {
const vapor = import.meta.env.PROD
? `${location.origin}/vue-vapor.esm-browser.js`
: `${location.origin}/src/vue-vapor-dev-proxy`
const vaporImportMap: ImportMap = {
imports: {
'vue/vapor': vapor,
},
}
return mergeImportMap(vueImportMap.value, vaporImportMap)
})
let hash = location.hash.slice(1)
if (hash.startsWith('__DEV__')) {
hash = hash.slice(7)
@ -126,7 +114,7 @@ watch(
files.value['src/index.html'] = new File(
'src/index.html',
`<script type="module">
import { createVaporApp } from 'vue/vapor'
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')` +
'<' +

View File

@ -1,2 +1,2 @@
// serve vue to the iframe sandbox during dev.
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.prod.js'

View File

@ -1,2 +1,2 @@
// serve vue to the iframe sandbox during dev.
export * from 'vue'
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.js'

View File

@ -1,2 +0,0 @@
// serve vue/vapor to the iframe sandbox during dev.
export * from 'vue/vapor'

View File

@ -53,8 +53,9 @@ function copyVuePlugin(): Plugin {
copyFile(`vue/dist/vue.esm-browser.prod.js`)
copyFile(`vue/dist/vue.runtime.esm-browser.js`)
copyFile(`vue/dist/vue.runtime.esm-browser.prod.js`)
copyFile(`vue/dist/vue.runtime-with-vapor.esm-browser.js`)
copyFile(`vue/dist/vue.runtime-with-vapor.esm-browser.prod.js`)
copyFile(`server-renderer/dist/server-renderer.esm-browser.js`)
copyFile(`vue-vapor/dist/vue-vapor.esm-browser.js`)
},
}
}

View File

@ -333,11 +333,6 @@ export interface CodegenOptions extends SharedTransformCodegenOptions {
* @default 'vue'
*/
runtimeModuleName?: string
/**
* Customize where to import runtime helpers from.
* @default 'vue/vapor'
*/
vaporRuntimeModuleName?: string
/**
* Customize where to import ssr runtime helpers from/**
* @default 'vue/server-renderer'

View File

@ -379,8 +379,7 @@ export function compileScript(
const vueImportAliases: Record<string, string> = {}
for (const key in ctx.userImports) {
const { source, imported, local } = ctx.userImports[key]
if (['vue', 'vue/vapor'].includes(source))
vueImportAliases[imported] = local
if (source === 'vue') vueImportAliases[imported] = local
}
// 2.1 process normal <script> body
@ -736,7 +735,7 @@ export function compileScript(
ctx.bindingMetadata[key] =
imported === '*' ||
(imported === 'default' && source.endsWith('.vue')) ||
['vue', 'vue/vapor'].includes(source)
source === 'vue'
? BindingTypes.SETUP_CONST
: BindingTypes.SETUP_MAYBE_REF
}
@ -847,7 +846,7 @@ export function compileScript(
for (const key in allBindings) {
if (
allBindings[key] === true &&
!['vue', 'vue/vapor'].includes(ctx.userImports[key].source) &&
ctx.userImports[key].source !== 'vue' &&
!ctx.userImports[key].source.endsWith('.vue')
) {
// generate getter for import bindings
@ -989,8 +988,7 @@ export function compileScript(
ctx.s.prependLeft(
startOffset,
`\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
`defineComponent`,
vapor,
vapor ? `defineVaporComponent` : `defineComponent`,
)}({${def}${runtimeOptions}\n ${
hasAwait ? `async ` : ``
}setup(${args}) {\n${exposeCall}`,
@ -1031,13 +1029,6 @@ export function compileScript(
.join(', ')} } from ${importSrc}\n`,
)
}
if (ctx.vaporHelperImports.size > 0) {
ctx.s.prepend(
`import { ${[...ctx.vaporHelperImports]
.map(h => `${h} as _${h}`)
.join(', ')} } from 'vue/vapor'\n`,
)
}
return {
...scriptSetup,

View File

@ -64,9 +64,8 @@ export class ScriptCompileContext {
// codegen
bindingMetadata: BindingMetadata = {}
helperImports: Set<string> = new Set()
vaporHelperImports: Set<string> = new Set()
helper(key: string, vapor?: boolean): string {
;(vapor ? this.vaporHelperImports : this.helperImports).add(key)
helper(key: string): string {
this.helperImports.add(key)
return `_${key}`
}

View File

@ -76,7 +76,6 @@ export class CodegenContext {
scopeId: null,
runtimeGlobalName: `Vue`,
runtimeModuleName: `vue`,
vaporRuntimeModuleName: 'vue/vapor',
ssrRuntimeModuleName: 'vue/server-renderer',
ssr: false,
isTS: false,
@ -176,7 +175,7 @@ function genHelperImports({ helpers, vaporHelpers, options }: CodegenContext) {
if (vaporHelpers.size) {
imports += `import { ${[...vaporHelpers]
.map(h => `${h} as _${h}`)
.join(', ')} } from '${options.vaporRuntimeModuleName}';\n`
.join(', ')} } from 'vue';\n`
}
return imports
}

View File

@ -14,10 +14,7 @@
"buildOptions": {
"name": "VueRuntimeVapor",
"formats": [
"esm-bundler",
"esm-browser",
"cjs",
"global"
"esm-bundler"
]
},
"repository": {

View File

@ -1,7 +1,7 @@
import type { VaporComponent } from './component'
/*! #__NO_SIDE_EFFECTS__ */
export function defineComponent(comp: VaporComponent): VaporComponent {
export function defineVaporComponent(comp: VaporComponent): VaporComponent {
// TODO type inference
return comp
}

View File

@ -1,10 +1,11 @@
// public APIs
export { createVaporApp } from './apiCreateApp'
export { defineVaporComponent } from './apiDefineComponent'
// compiler-use only
export { createComponent, createComponentWithFallback } from './component'
export { renderEffect } from './renderEffect'
export { createVaporApp } from './apiCreateApp'
export { defineComponent } from './apiDefineComponent'
export { createSlot } from './componentSlots'
// DOM
export { template, children, next } from './dom/template'
export { insert, prepend, remove, createTextNode } from './dom/node'
export { setStyle } from './dom/style'
@ -20,6 +21,3 @@ export {
} from './dom/prop'
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
export { setRef } from './dom/templateRef'
// re-exports
export { resolveComponent } from '@vue/runtime-dom'

View File

@ -89,7 +89,8 @@
"global",
"global-runtime",
"esm-browser",
"esm-browser-runtime"
"esm-browser-runtime",
"vapor"
]
},
"repository": {

View File

@ -0,0 +1,2 @@
export * from './runtime'
export * from '@vue/runtime-vapor'

View File

@ -21,7 +21,7 @@ import { minify as minifySwc } from '@swc/core'
* @template {keyof T} K
* @typedef { Omit<T, K> & Required<Pick<T, K>> } MarkRequired
*/
/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime'} PackageFormat */
/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime' | 'vapor'} PackageFormat */
/** @typedef {MarkRequired<import('rollup').OutputOptions, 'file' | 'format'>} OutputOptions */
if (!process.env.TARGET) {
@ -85,6 +85,12 @@ const outputConfigs = {
file: resolve(`dist/${name}.runtime.global.js`),
format: 'iife',
},
// The vapor format is a esm-browser + runtime only build that is meant for
// the SFC playground only.
vapor: {
file: resolve(`dist/${name}.runtime-with-vapor.esm-browser.js`),
format: 'es',
},
}
/** @type {ReadonlyArray<PackageFormat>} */
@ -107,7 +113,7 @@ if (process.env.NODE_ENV === 'production') {
if (format === 'cjs') {
packageConfigs.push(createProductionConfig(format))
}
if (/^(global|esm-browser)(-runtime)?/.test(format)) {
if (format === 'vapor' || /^(global|esm-browser)(-runtime)?/.test(format)) {
packageConfigs.push(createMinifiedConfig(format))
}
})
@ -131,7 +137,7 @@ function createConfig(format, output, plugins = []) {
const isProductionBuild =
process.env.__DEV__ === 'false' || /\.prod\.js$/.test(output.file)
const isBundlerESMBuild = /esm-bundler/.test(format)
const isBrowserESMBuild = /esm-browser/.test(format)
const isBrowserESMBuild = /esm-browser/.test(format) || format === 'vapor'
const isServerRenderer = name === 'server-renderer'
const isCJSBuild = format === 'cjs'
const isGlobalBuild = /global/.test(format)
@ -159,7 +165,12 @@ function createConfig(format, output, plugins = []) {
output.name = packageOptions.name
}
let entryFile = /\bruntime\b/.test(format) ? `runtime.ts` : `index.ts`
let entryFile =
format === 'vapor'
? 'runtime-with-vapor.ts'
: /\bruntime\b/.test(format)
? `runtime.ts`
: `index.ts`
// the compat build needs both default AND named exports. This will cause
// Rollup to complain for non-ESM targets, so we use separate entries for

View File

@ -49,9 +49,12 @@ const outputFormat = format.startsWith('global')
? 'cjs'
: 'esm'
const postfix = format.endsWith('-runtime')
? `runtime.${format.replace(/-runtime$/, '')}`
: format
const postfix =
format === 'vapor'
? 'runtime-with-vapor.esm-browser'
: format.endsWith('-runtime')
? `runtime.${format.replace(/-runtime$/, '')}`
: format
const privatePackages = fs.readdirSync('packages-private')
@ -127,9 +130,16 @@ for (const target of targets) {
plugins.push(polyfillNode())
}
const entry =
format === 'vapor'
? 'runtime-with-vapor.ts'
: format.endsWith('-runtime')
? 'runtime.ts'
: 'index.ts'
esbuild
.context({
entryPoints: [resolve(__dirname, `${pkgBasePath}/src/index.ts`)],
entryPoints: [resolve(__dirname, `${pkgBasePath}/src/${entry}`)],
outfile,
bundle: true,
external,