wip: initial compat build setup
This commit is contained in:
parent
870f2a7ba3
commit
24850a99c6
@ -41,7 +41,7 @@ module.exports = {
|
||||
},
|
||||
// Packages targeting DOM
|
||||
{
|
||||
files: ['packages/{vue,runtime-dom}/**'],
|
||||
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
|
||||
rules: {
|
||||
'no-restricted-globals': ['error', ...NodeGlobals]
|
||||
}
|
||||
|
1
packages/global.d.ts
vendored
1
packages/global.d.ts
vendored
@ -8,6 +8,7 @@ declare var __ESM_BROWSER__: boolean
|
||||
declare var __NODE_JS__: boolean
|
||||
declare var __COMMIT__: string
|
||||
declare var __VERSION__: string
|
||||
declare var __COMPAT__: boolean
|
||||
|
||||
// Feature flags
|
||||
declare var __FEATURE_OPTIONS_API__: boolean
|
||||
|
@ -13,7 +13,15 @@ import {
|
||||
import { nodeOps } from './nodeOps'
|
||||
import { patchProp, forcePatchProp } from './patchProp'
|
||||
// Importing from the compiler, will be tree-shaken in prod
|
||||
import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared'
|
||||
import {
|
||||
isFunction,
|
||||
isString,
|
||||
isHTMLTag,
|
||||
isSVGTag,
|
||||
extend,
|
||||
warnDeprecation,
|
||||
DeprecationTypes
|
||||
} from '@vue/shared'
|
||||
|
||||
declare module '@vue/reactivity' {
|
||||
export interface RefUnwrapBailTypes {
|
||||
@ -63,8 +71,24 @@ export const createApp = ((...args) => {
|
||||
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
|
||||
const container = normalizeContainer(containerOrSelector)
|
||||
if (!container) return
|
||||
|
||||
// 2.x compat check
|
||||
if (__COMPAT__ && __DEV__) {
|
||||
for (let i = 0; i < container.attributes.length; i++) {
|
||||
const attr = container.attributes[i]
|
||||
if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
|
||||
warnDeprecation(DeprecationTypes.DOM_TEMPLATE_MOUNT)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const component = app._component
|
||||
if (!isFunction(component) && !component.render && !component.template) {
|
||||
// __UNSAFE__
|
||||
// Reason: potential execution of JS expressions in in-DOM template.
|
||||
// The user must make sure the in-DOM template is trusted. If it's
|
||||
// rendered by the server, the template should not contain any user data.
|
||||
component.template = container.innerHTML
|
||||
}
|
||||
// clear content before mounting
|
||||
|
25
packages/shared/src/deprecations.ts
Normal file
25
packages/shared/src/deprecations.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export const enum DeprecationTypes {
|
||||
DOM_TEMPLATE_MOUNT
|
||||
}
|
||||
|
||||
type DeprecationData = {
|
||||
message: string
|
||||
link?: string
|
||||
}
|
||||
|
||||
const deprecations: Record<DeprecationTypes, DeprecationData> = {
|
||||
[DeprecationTypes.DOM_TEMPLATE_MOUNT]: {
|
||||
message:
|
||||
`Vue detected directives on the mount container. ` +
|
||||
`In Vue 3, the container is no longer considered part of the template ` +
|
||||
`and will not be processed/replaced.`,
|
||||
link: `https://v3.vuejs.org/guide/migration/mount-changes.html`
|
||||
}
|
||||
}
|
||||
|
||||
export function warnDeprecation(key: DeprecationTypes) {
|
||||
const { message, link } = deprecations[key]
|
||||
console.warn(
|
||||
`[Deprecation]: ${message}${link ? `\nFor more details, see ${link}` : ``}`
|
||||
)
|
||||
}
|
@ -12,6 +12,7 @@ export * from './domAttrConfig'
|
||||
export * from './escapeHtml'
|
||||
export * from './looseEqual'
|
||||
export * from './toDisplayString'
|
||||
export * from './deprecations'
|
||||
|
||||
/**
|
||||
* List of @babel/parser plugins that are used for template expression
|
||||
|
1
packages/vue-compat/README.md
Normal file
1
packages/vue-compat/README.md
Normal file
@ -0,0 +1 @@
|
||||
# @vue/compat
|
7
packages/vue-compat/api-extractor.json
Normal file
7
packages/vue-compat/api-extractor.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../api-extractor.json",
|
||||
"mainEntryPointFilePath": "./dist/packages/<unscopedPackageName>/src/index.d.ts",
|
||||
"dtsRollup": {
|
||||
"publicTrimmedFilePath": "./dist/<unscopedPackageName>.d.ts"
|
||||
}
|
||||
}
|
7
packages/vue-compat/index.js
Normal file
7
packages/vue-compat/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./dist/compat.cjs.prod.js')
|
||||
} else {
|
||||
module.exports = require('./dist/compat.cjs.js')
|
||||
}
|
44
packages/vue-compat/package.json
Normal file
44
packages/vue-compat/package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@vue/compat",
|
||||
"version": "3.0.11",
|
||||
"description": "@vue/compat",
|
||||
"main": "index.js",
|
||||
"module": "dist/vue.esm-bundler.js",
|
||||
"types": "dist/vue.d.ts",
|
||||
"unpkg": "dist/vue.global.js",
|
||||
"jsdelivr": "dist/vue.global.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"dist"
|
||||
],
|
||||
"buildOptions": {
|
||||
"name": "Vue",
|
||||
"filename": "vue",
|
||||
"compat": true,
|
||||
"formats": [
|
||||
"esm-bundler",
|
||||
"esm-bundler-runtime",
|
||||
"cjs",
|
||||
"global",
|
||||
"global-runtime",
|
||||
"esm-browser",
|
||||
"esm-browser-runtime"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuejs/vue.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vue"
|
||||
],
|
||||
"author": "Evan You",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vuejs/vue/issues"
|
||||
},
|
||||
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-compat#readme",
|
||||
"peerDependencies": {
|
||||
"vue": "3.0.11"
|
||||
}
|
||||
}
|
157
packages/vue-compat/src/apiGlobal.ts
Normal file
157
packages/vue-compat/src/apiGlobal.ts
Normal file
@ -0,0 +1,157 @@
|
||||
import { reactive } from '@vue/reactivity'
|
||||
import {
|
||||
createApp,
|
||||
defineComponent,
|
||||
nextTick,
|
||||
App,
|
||||
AppConfig,
|
||||
Plugin,
|
||||
Component,
|
||||
ComponentOptions,
|
||||
ComponentPublicInstance,
|
||||
Directive,
|
||||
RenderFunction,
|
||||
isRuntimeOnly
|
||||
} from '@vue/runtime-dom'
|
||||
|
||||
// TODO make these getter/setters and trigger deprecation warnings
|
||||
export type LegacyConfig = AppConfig & {
|
||||
/**
|
||||
* @deprecated `config.silent` option has been removed
|
||||
*/
|
||||
silent?: boolean
|
||||
/**
|
||||
* @deprecated use __VUE_PROD_DEVTOOLS__ compile-time feature flag instead
|
||||
* https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
|
||||
*/
|
||||
devtools?: boolean
|
||||
/**
|
||||
* @deprecated use `config.isCustomElement` instead
|
||||
* https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement
|
||||
*/
|
||||
ignoredElements?: (string | RegExp)[]
|
||||
/**
|
||||
* @deprecated
|
||||
* https://v3.vuejs.org/guide/migration/keycode-modifiers.html
|
||||
*/
|
||||
keyCodes?: Record<string, number | number[]>
|
||||
/**
|
||||
* @deprecated
|
||||
* https://v3.vuejs.org/guide/migration/global-api.html#config-productiontip-removed
|
||||
*/
|
||||
productionTip?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the default `Vue` export has been removed in Vue 3. The type for
|
||||
* the default export is provided only for migration purposes. Please use
|
||||
* named imports instead - e.g. `import { createApp } from 'vue'`.
|
||||
*/
|
||||
export type GlobalVue = Pick<App, 'version' | 'component' | 'directive'> & {
|
||||
// no inference here since these types are not meant for actual use - they
|
||||
// are merely here to provide type checks for internal implementation and
|
||||
// information for migration.
|
||||
new (options?: ComponentOptions): ComponentPublicInstance
|
||||
|
||||
version: string
|
||||
config: LegacyConfig
|
||||
|
||||
extend: typeof defineComponent
|
||||
nextTick: typeof nextTick
|
||||
|
||||
use(plugin: Plugin, ...options: any[]): GlobalVue
|
||||
mixin(mixin: ComponentOptions): GlobalVue
|
||||
|
||||
component(name: string): Component | undefined
|
||||
component(name: string, component: Component): GlobalVue
|
||||
directive(name: string): Directive | undefined
|
||||
directive(name: string, directive: Directive): GlobalVue
|
||||
|
||||
compile(template: string): RenderFunction
|
||||
|
||||
/**
|
||||
* @deprecated Vue 3 no longer needs set() for adding new properties.
|
||||
*/
|
||||
set(target: any, key: string | number | symbol, value: any): void
|
||||
/**
|
||||
* @deprecated Vue 3 no longer needs delete() for property deletions.
|
||||
*/
|
||||
delete(target: any, key: string | number | symbol): void
|
||||
/**
|
||||
* @deprecated use `reactive` instead.
|
||||
*/
|
||||
observable: typeof reactive
|
||||
/**
|
||||
* @deprecated filters have been removed from Vue 3.
|
||||
*/
|
||||
filter(name: string, arg: any): null
|
||||
}
|
||||
|
||||
export const Vue: GlobalVue = function Vue(options: ComponentOptions = {}) {
|
||||
const app = createApp(options)
|
||||
// copy over global config mutations
|
||||
for (const key in singletonApp.config) {
|
||||
if (
|
||||
key !== 'isNativeTag' &&
|
||||
!(key === 'isCustomElement' && isRuntimeOnly())
|
||||
) {
|
||||
// @ts-ignore
|
||||
app.config[key] = singletonApp.config[key]
|
||||
}
|
||||
}
|
||||
if (options.el) {
|
||||
return app.mount(options.el)
|
||||
}
|
||||
} as any
|
||||
|
||||
const singletonApp = createApp({})
|
||||
|
||||
Vue.version = __VERSION__
|
||||
Vue.config = singletonApp.config
|
||||
|
||||
Vue.extend = defineComponent
|
||||
Vue.nextTick = nextTick
|
||||
|
||||
Vue.set = (target, key, value) => {
|
||||
// TODO deprecation warnings
|
||||
target[key] = value
|
||||
}
|
||||
Vue.delete = (target, key) => {
|
||||
// TODO deprecation warnings
|
||||
delete target[key]
|
||||
}
|
||||
// TODO wrap with deprecation warning
|
||||
Vue.observable = reactive
|
||||
|
||||
Vue.use = (p, ...options) => {
|
||||
singletonApp.use(p, ...options)
|
||||
return Vue
|
||||
}
|
||||
|
||||
Vue.mixin = m => {
|
||||
singletonApp.mixin(m)
|
||||
return Vue
|
||||
}
|
||||
|
||||
Vue.component = ((name: string, comp: any) => {
|
||||
if (comp) {
|
||||
singletonApp.component(name, comp)
|
||||
return Vue
|
||||
} else {
|
||||
return singletonApp.component(name)
|
||||
}
|
||||
}) as any
|
||||
|
||||
Vue.directive = ((name: string, dir: any) => {
|
||||
if (dir) {
|
||||
singletonApp.directive(name, dir)
|
||||
return Vue
|
||||
} else {
|
||||
return singletonApp.directive(name)
|
||||
}
|
||||
}) as any
|
||||
|
||||
Vue.filter = ((name: string, filter: any) => {
|
||||
// TODO deprecation warning
|
||||
// TODO compiler warning for filters (maybe behavior compat?)
|
||||
}) as any
|
14
packages/vue-compat/src/dev.ts
Normal file
14
packages/vue-compat/src/dev.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { initCustomFormatter } from '@vue/runtime-dom'
|
||||
|
||||
export function initDev() {
|
||||
if (__BROWSER__) {
|
||||
if (!__ESM_BUNDLER__) {
|
||||
console.info(
|
||||
`You are running a development build of Vue.\n` +
|
||||
`Make sure to use the production build (*.prod.js) when deploying for production.`
|
||||
)
|
||||
}
|
||||
|
||||
initCustomFormatter()
|
||||
}
|
||||
}
|
93
packages/vue-compat/src/index.ts
Normal file
93
packages/vue-compat/src/index.ts
Normal file
@ -0,0 +1,93 @@
|
||||
// This entry is the "full-build" that includes both the runtime
|
||||
// and the compiler, and supports on-the-fly compilation of the template option.
|
||||
import { initDev } from './dev'
|
||||
import { compile, CompilerOptions, CompilerError } from '@vue/compiler-dom'
|
||||
import { registerRuntimeCompiler, RenderFunction, warn } from '@vue/runtime-dom'
|
||||
import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared'
|
||||
import { InternalRenderFunction } from 'packages/runtime-core/src/component'
|
||||
import * as runtimeDom from '@vue/runtime-dom'
|
||||
import { Vue } from './apiGlobal'
|
||||
|
||||
if (__DEV__) {
|
||||
initDev()
|
||||
}
|
||||
|
||||
const compileCache: Record<string, RenderFunction> = Object.create(null)
|
||||
|
||||
function compileToFunction(
|
||||
template: string | HTMLElement,
|
||||
options?: CompilerOptions
|
||||
): RenderFunction {
|
||||
if (!isString(template)) {
|
||||
if (template.nodeType) {
|
||||
template = template.innerHTML
|
||||
} else {
|
||||
__DEV__ && warn(`invalid template option: `, template)
|
||||
return NOOP
|
||||
}
|
||||
}
|
||||
|
||||
const key = template
|
||||
const cached = compileCache[key]
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
|
||||
if (template[0] === '#') {
|
||||
const el = document.querySelector(template)
|
||||
if (__DEV__ && !el) {
|
||||
warn(`Template element not found or is empty: ${template}`)
|
||||
}
|
||||
// __UNSAFE__
|
||||
// Reason: potential execution of JS expressions in in-DOM template.
|
||||
// The user must make sure the in-DOM template is trusted. If it's rendered
|
||||
// by the server, the template should not contain any user data.
|
||||
template = el ? el.innerHTML : ``
|
||||
}
|
||||
|
||||
const { code } = compile(
|
||||
template,
|
||||
extend(
|
||||
{
|
||||
hoistStatic: true,
|
||||
onError(err: CompilerError) {
|
||||
if (__DEV__) {
|
||||
const message = `Template compilation error: ${err.message}`
|
||||
const codeFrame =
|
||||
err.loc &&
|
||||
generateCodeFrame(
|
||||
template as string,
|
||||
err.loc.start.offset,
|
||||
err.loc.end.offset
|
||||
)
|
||||
warn(codeFrame ? `${message}\n${codeFrame}` : message)
|
||||
} else {
|
||||
/* istanbul ignore next */
|
||||
throw err
|
||||
}
|
||||
}
|
||||
},
|
||||
options
|
||||
)
|
||||
)
|
||||
|
||||
// The wildcard import results in a huge object with every export
|
||||
// with keys that cannot be mangled, and can be quite heavy size-wise.
|
||||
// In the global build we know `Vue` is available globally so we can avoid
|
||||
// the wildcard object.
|
||||
const render = (__GLOBAL__
|
||||
? new Function(code)()
|
||||
: new Function('Vue', code)(runtimeDom)) as RenderFunction
|
||||
|
||||
// mark the function as runtime compiled
|
||||
;(render as InternalRenderFunction)._rc = true
|
||||
|
||||
return (compileCache[key] = render)
|
||||
}
|
||||
|
||||
registerRuntimeCompiler(compileToFunction)
|
||||
|
||||
Vue.compile = compileToFunction
|
||||
extend(Vue, runtimeDom)
|
||||
|
||||
export default Vue
|
25
packages/vue-compat/src/runtime.ts
Normal file
25
packages/vue-compat/src/runtime.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// This entry exports the runtime only, and is built as
|
||||
// `dist/vue.esm-bundler.js` which is used by default for bundlers.
|
||||
import { initDev } from './dev'
|
||||
import { warn } from '@vue/runtime-dom'
|
||||
|
||||
if (__DEV__) {
|
||||
initDev()
|
||||
}
|
||||
|
||||
export * from '@vue/runtime-dom'
|
||||
|
||||
export const compile = () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
`Runtime compilation is not supported in this build of Vue.` +
|
||||
(__ESM_BUNDLER__
|
||||
? ` Configure your bundler to alias "vue" to "@vue/compat/dist/vue.esm-bundler.js".`
|
||||
: __ESM_BROWSER__
|
||||
? ` Use "vue.esm-browser.js" instead.`
|
||||
: __GLOBAL__
|
||||
? ` Use "vue.global.js" instead.`
|
||||
: ``) /* should not happen */
|
||||
)
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// @ts-check
|
||||
import path from 'path'
|
||||
import ts from 'rollup-plugin-typescript2'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
@ -10,10 +11,10 @@ if (!process.env.TARGET) {
|
||||
const masterVersion = require('./package.json').version
|
||||
const packagesDir = path.resolve(__dirname, 'packages')
|
||||
const packageDir = path.resolve(packagesDir, process.env.TARGET)
|
||||
const name = path.basename(packageDir)
|
||||
const resolve = p => path.resolve(packageDir, p)
|
||||
const pkg = require(resolve(`package.json`))
|
||||
const packageOptions = pkg.buildOptions || {}
|
||||
const name = packageOptions.filename || path.basename(packageDir)
|
||||
|
||||
// ensure TS checks only once for each build
|
||||
let hasTSChecked = false
|
||||
@ -89,6 +90,7 @@ function createConfig(format, output, plugins = []) {
|
||||
const isBrowserESMBuild = /esm-browser/.test(format)
|
||||
const isNodeBuild = format === 'cjs'
|
||||
const isGlobalBuild = /global/.test(format)
|
||||
const isCompatBuild = !!packageOptions.compat
|
||||
|
||||
if (isGlobalBuild) {
|
||||
output.name = packageOptions.name
|
||||
@ -116,19 +118,23 @@ function createConfig(format, output, plugins = []) {
|
||||
|
||||
const entryFile = /runtime$/.test(format) ? `src/runtime.ts` : `src/index.ts`
|
||||
|
||||
const external =
|
||||
isGlobalBuild || isBrowserESMBuild
|
||||
? packageOptions.enableNonBrowserBranches
|
||||
? []
|
||||
: // normal browser builds - non-browser only imports are tree-shaken,
|
||||
// they are only listed here to suppress warnings.
|
||||
['source-map', '@babel/parser', 'estree-walker']
|
||||
: // Node / esm-bundler builds. Externalize everything.
|
||||
[
|
||||
...Object.keys(pkg.dependencies || {}),
|
||||
...Object.keys(pkg.peerDependencies || {}),
|
||||
...['path', 'url', 'stream'] // for @vue/compiler-sfc / server-renderer
|
||||
]
|
||||
let external = []
|
||||
|
||||
if (isGlobalBuild || isBrowserESMBuild) {
|
||||
if (!packageOptions.enableNonBrowserBranches) {
|
||||
// normal browser builds - non-browser only imports are tree-shaken,
|
||||
// they are only listed here to suppress warnings.
|
||||
external = ['source-map', '@babel/parser', 'estree-walker']
|
||||
}
|
||||
} else if (!isCompatBuild) {
|
||||
// Node / esm-bundler builds.
|
||||
// externalize all deps unless it's the compat build.
|
||||
external = [
|
||||
...Object.keys(pkg.dependencies || {}),
|
||||
...Object.keys(pkg.peerDependencies || {}),
|
||||
...['path', 'url', 'stream'] // for @vue/compiler-sfc / server-renderer
|
||||
]
|
||||
}
|
||||
|
||||
// the browser builds of @vue/compiler-sfc requires postcss to be available
|
||||
// as a global (e.g. http://wzrd.in/standalone/postcss)
|
||||
@ -139,9 +145,11 @@ function createConfig(format, output, plugins = []) {
|
||||
const nodePlugins =
|
||||
packageOptions.enableNonBrowserBranches && format !== 'cjs'
|
||||
? [
|
||||
// @ts-ignore
|
||||
require('@rollup/plugin-commonjs')({
|
||||
sourceMap: false
|
||||
}),
|
||||
// @ts-ignore
|
||||
require('rollup-plugin-polyfill-node')(),
|
||||
require('@rollup/plugin-node-resolve').nodeResolve()
|
||||
]
|
||||
@ -165,7 +173,8 @@ function createConfig(format, output, plugins = []) {
|
||||
(isGlobalBuild || isBrowserESMBuild || isBundlerESMBuild) &&
|
||||
!packageOptions.enableNonBrowserBranches,
|
||||
isGlobalBuild,
|
||||
isNodeBuild
|
||||
isNodeBuild,
|
||||
isCompatBuild
|
||||
),
|
||||
...nodePlugins,
|
||||
...plugins
|
||||
@ -188,7 +197,8 @@ function createReplacePlugin(
|
||||
isBrowserESMBuild,
|
||||
isBrowserBuild,
|
||||
isGlobalBuild,
|
||||
isNodeBuild
|
||||
isNodeBuild,
|
||||
isCompatBuild
|
||||
) {
|
||||
const replacements = {
|
||||
__COMMIT__: `"${process.env.COMMIT}"`,
|
||||
@ -208,6 +218,9 @@ function createReplacePlugin(
|
||||
// is targeting Node (SSR)?
|
||||
__NODE_JS__: isNodeBuild,
|
||||
|
||||
// 2.x compat build
|
||||
__COMPAT__: isCompatBuild,
|
||||
|
||||
// feature flags
|
||||
__FEATURE_SUSPENSE__: true,
|
||||
__FEATURE_OPTIONS_API__: isBundlerESMBuild ? `__VUE_OPTIONS_API__` : true,
|
||||
@ -231,6 +244,7 @@ function createReplacePlugin(
|
||||
}
|
||||
})
|
||||
return replace({
|
||||
// @ts-ignore
|
||||
values: replacements,
|
||||
preventAssignment: true
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user