diff --git a/README.md b/README.md
index bb389fef..56b8bc69 100644
--- a/README.md
+++ b/README.md
@@ -7,11 +7,6 @@ Vue 2 plugin for **Composition API**
English | [中文](./README.zh-CN.md) ・ [**Composition API Docs**](https://composition-api.vuejs.org/)
-
-**Note: the primary goal of this package is to allow the community to experiment with the API and provide feedback before it's finalized. The implementation may contain minor inconsistencies with the RFC as the latter gets updated. We do not recommend using this package for production yet at this stage.**
-
----
-
## Installation
### NPM
@@ -45,14 +40,14 @@ Include `@vue/composition-api` after Vue and it will install itself automaticall
```html
-
+
```
-`@vue/composition-api` will be exposed to global variable `window.vueCompositionApi`.
+`@vue/composition-api` will be exposed to global variable `window.VueCompositionAPI`.
```ts
-const { ref, reactive } = vueCompositionApi
+const { ref, reactive } = VueCompositionAPI
```
## TypeScript Support
@@ -99,8 +94,7 @@ export default {
## Limitations
-> :white_check_mark:
-> Support :x: Not Supported
+> :white_check_mark: Support :x: Not Supported
### `Ref` Unwrap
@@ -375,6 +369,27 @@ watch(() => {
+### createApp
+
+
+
+⚠️ createApp()
is global
+
+
+In Vue 3, `createApp()` is introduced to provide context(plugin, components, etc.) isolation between app instances. Due the the design of Vue 2, in this plugin, we provide `createApp()` as a forward compatible API which is just an alias of the global.
+
+```ts
+const app1 = createApp(RootComponent1)
+app1.component('Foo', Foo) // equivalent to Vue.component('Foo', Foo)
+app1.use(VueRouter) // equivalent to Vue.use(VueRouter)
+
+const app2 = createApp(RootComponent2)
+app2.component('Bar', Bar) // equivalent to Vue.use('Bar', Bar)
+```
+
+
+
+
### Missing APIs
The following APIs introduced in Vue 3 are not available in this plugin.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 157ab140..3eab32a2 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,135 +1,140 @@
-# Vue Composition API
+# @vue/composition-api
Vue 2 插件用于提供 Vue 3 中的 **组合式 API**.
[![npm](https://img.shields.io/npm/v/@vue/composition-api)](https://www.npmjs.com/package/@vue/composition-api)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)](https://github.com/vuejs/composition-api/actions?query=workflow%3A%22Build+%26+Test%22)
-[**English**](./README.md) | 中文文档 / [**组合式 API RFC**](https://composition-api.vuejs.org/zh)
+[English](./README.md) | 中文 ・ [**组合式 API 文档**](https://composition-api.vuejs.org/zh)
-**请注意:此插件的主要目的是让社区尝试新的API并在其最终确定之前提供反馈。随着RFC的更新,该实现可能包含与RFC有细微的不一致。现阶段,我们暂不建议将此插件用于生产环境。**
----
+## 安装
-# 导航
-
-- [安装](#安装)
-- [使用](#使用)
-- [TypeScript](#TypeScript)
- - [TSX](#tsx)
-- [限制](#限制)
-- [更新日志](https://github.com/vuejs/composition-api/blob/master/CHANGELOG.md)
-
-# 安装
-
-**npm**
+### NPM
```bash
-npm install @vue/composition-api --save
+npm install @vue/composition-api
+# or
+yarn add @vue/composition-api
```
-**yarn**
+在使用 `@vue/composition-api` 前,必须先先通过 `Vue.use()` 进行安装后方可使用使用新的 [**组合式 API**](https://composition-api.vuejs.org/zh) 进行组件开发。
-```bash
-yarn add @vue/composition-api
-```
+```js
+import Vue from 'vue'
+import VueCompositionAPI from '@vue/composition-api'
-**CDN**
+Vue.use(VueCompositionAPI)
+```
-```html
-
+```js
+// 使用 API
+import { ref, reactive } from '@vue/composition-api'
```
-通过全局变量 `window.vueCompositionApi` 来使用。
+> :bulb: 当迁移到 Vue 3 时,只需简单的将 `@vue/composition-api` 替换成 `vue` 即可。你现有的代码几乎无需进行额外的改动。
-# 使用
-在使用任何 `@vue/composition-api` 提供的能力前,必须先通过 `Vue.use()` 进行安装:
+### CDN
-```js
-import Vue from 'vue';
-import VueCompositionApi from '@vue/composition-api';
+在 Vue 之后引入 `@vue/composition-api` ,插件将会自动完成安装。
-Vue.use(VueCompositionApi);
+
+```html
+
+
```
+
-安装插件后,您就可以使用新的 [Composition API](https://vue-composition-api-rfc.netlify.com/) 来开发组件了。
+`@vue/composition-api` 将会暴露在全局变量 `window.VueCompositionAPI` 中。
-# TypeScript
+```ts
+const { ref, reactive } = VueCompositionAPI
+```
+
+## TypeScript 支持
-**本插件要求使用 TypeScript 3.5.1 以上版本,如果你正在使用 `vetur`,请将 `vetur.useWorkspaceDependencies` 设为 `true`。**
+> 本插件要求使用 TypeScript **3.5.1** 或以上版本
为了让 TypeScript 在 Vue 组件选项中正确地推导类型,我们必须使用 `defineComponent` 来定义组件:
```ts
-import { defineComponent } from '@vue/composition-api';
+import { defineComponent } from '@vue/composition-api'
-const Component = defineComponent({
- // 启用类型推断
-});
-
-const Component = {
- // 无法进行选项的类型推断
- // TypeScript 无法知道这是一个 Vue 组件的选项对象
-};
+export default defineComponent({
+ // 类型推断启用
+})
```
-## TSX
+### JSX/TSX
-:rocket: 这里有一个配置好 TS/TSX 支持的[示例仓库](https://github.com/liximomo/vue-composition-api-tsx-example)来帮助你快速开始.
+要使得 `@vue/composition-api` 支持 JSX/TSX,请前往查看由 [@luwanquan](https://github.com/luwanquan) 开发的 Babel 插件[babel-preset-vca-jsx](https://github.com/luwanquan/babel-preset-vca-jsx)。
-要支持 TSX,请创建一个类型定义文件并提供正确的 JSX 定义。内容如下:
+## SSR
-```ts
-// 文件: `shim-tsx.d.ts`
-import Vue, { VNode } from 'vue';
-import { ComponentRenderProxy } from '@vue/composition-api';
-
-declare global {
- namespace JSX {
- // tslint:disable no-empty-interface
- interface Element extends VNode {}
- // tslint:disable no-empty-interface
- interface ElementClass extends ComponentRenderProxy {}
- interface ElementAttributesProperty {
- $props: any; // 定义要使用的属性名称
- }
- interface IntrinsicElements {
- [elem: string]: any;
+尽管 Vue 3 暂时没有给出确定的 SSR 的 API,这个插件实现了 `onServerPrefetch` 生命周期钩子函数。这个钩子允许你使用在传统 API 中的 `serverPrefetch` 函数。
+
+```js
+import { onServerPrefetch } from '@vue/composition-api'
+
+export default {
+ setup (props, { ssrContext }) {
+ const result = ref()
+
+ onServerPrefetch(async () => {
+ result.value = await callApi(ssrContext.someId)
+ })
+
+ return {
+ result,
}
- }
+ },
}
```
-# 限制
+## 限制
-## `Ref` 自动展开 (unwrap)
+> :white_check_mark: 支持 :x: 不支持
+
+
+### `Ref` 自动展开 (unwrap)
数组索引属性无法进行自动展开:
-### **不要**使用 `Array` 直接存取 `ref` 对象:
+
+
+
+❌ 不要 使用数组直接存取 ref
对象
+
```js
const state = reactive({
list: [ref(0)],
-});
+})
// 不会自动展开, 须使用 `.value`
-state.list[0].value === 0; // true
+state.list[0].value === 0 // true
-state.list.push(ref(1));
+state.list.push(ref(1))
// 不会自动展开, 须使用 `.value`
-state.list[1].value === 1; // true
+state.list[1].value === 1 // true
```
-### **不要**在数组中使用含有 `ref` 的普通对象:
+
+
+
+
+
+❌ 不要 在数组中使用含有 ref
的普通对象
+
+
```js
const a = {
count: ref(0),
-};
+}
const b = reactive({
list: [a], // `a.count` 不会自动展开!!
-});
+})
// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0; // true
@@ -142,51 +147,47 @@ const b = reactive({
count: ref(0), // 不会自动展开!!
},
],
-});
+})
// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0; // true
```
-### **应该**总是将 `ref` 存放到 `reactive` 对象中:
+
+
+
+
+
+✅ 在数组中,应该 总是将 ref
存放到 reactive
对象中
+
```js
const a = reactive({
count: ref(0),
-});
+})
const b = reactive({
list: [a],
-});
+})
// 自动展开
-b.list[0].count === 0; // true
+b.list[0].count === 0 // true
b.list.push(
reactive({
count: ref(1),
})
-);
+)
// 自动展开
b.list[1].count === 1; // true
```
-### `reactive` 会返回一个修改过的原始的对象
+
-此行为与 Vue 2 中的 `Vue.observable` 一致
-> Vue 3 中会返回一个新的的代理对象.
-
----
-
-## `watch()` API
-
-不支持 `onTrack` 和 `onTrigger` 选项。
-
----
-
-## 模板 Refs
+### 模板 Refs
-> :white_check_mark: 支持 :x: 不支持
-
-:white_check_mark: 字符串 ref && 从 `setup()` 返回 ref:
+
+
+✅ 字符串 ref && 从 setup()
返回 ref
+
```html
@@ -196,45 +197,59 @@ b.list[1].count === 1; // true
```
-:white_check_mark: 字符串 ref && 从 `setup()` 返回 ref && 渲染函数 / JSX:
+
+
+
+
+
+
+✅ 字符串 ref && 从 setup()
返回 ref && 渲染函数 / JSX
+
```jsx
export default {
setup() {
- const root = ref(null);
+ const root = ref(null)
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
- console.log(root.value); //
- });
+ console.log(root.value) //
+ })
return {
root,
- };
+ }
},
render() {
// 使用 JSX
- return () => ;
+ return () =>
},
-};
+}
```
-:x: 函数 ref:
+
+
+
+
+
+❌ 函数 ref
+
+
```html
@@ -244,69 +259,158 @@ export default {
```
-:x: 渲染函数 / JSX:
+
+
+
+
+
+❌ 在 setup()
中的渲染函数 / JSX
+
```jsx
export default {
setup() {
- const root = ref(null);
+ const root = ref(null)
return () =>
h('div', {
ref: root,
- });
+ })
// 使用 JSX
- return () => ;
+ return () =>
},
-};
+}
```
-如果你依然选择在 `setup()` 中写 `render` 函数,那么你可以使用 `SetupContext.refs` 来访问模板引用,它等价于 Vue 2.x 中的 `this.$refs`:
+
+
+
+
+⚠️ $refs
访问的变通方案
+
+
> :warning: **警告**: `SetupContext.refs` 并不属于 `Vue 3.0` 的一部分, `@vue/composition-api` 将其曝光在 `SetupContext` 中只是临时提供一种变通方案。
+如果你依然选择在 `setup()` 中写 `render` 函数,那么你可以使用 `SetupContext.refs` 来访问模板引用,它等价于 Vue 2.x 中的 `this.$refs`:
+
```js
export default {
setup(initProps, setupContext) {
- const refs = setupContext.refs;
+ const refs = setupContext.refs
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
console.log(refs.root); //
- });
+ })
return () =>
h('div', {
ref: 'root',
- });
+ })
// 使用 JSX
- return () => ;
+ return () =>
},
-};
+}
```
如果项目使用了 TypeScript,你还需要扩展 `SetupContext` 类型:
```ts
-import Vue from 'vue';
-import VueCompositionApi from '@vue/composition-api';
-
-Vue.use(VueCompositionApi);
+import Vue from 'vue'
-declare module '@vue/composition-api/dist/component/component' {
+declare module '@vue/composition-api' {
interface SetupContext {
- readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] };
+ readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }
}
}
```
+
+
+
+### Reactive
+
+
+
+⚠️ reactive()
会返回一个修改过的原始的对象
+
+
+此行为与 Vue 2 中的 `Vue.observable` 一致
+
+> :bulb: 在 Vue 3 中,`reactive()` 会返回一个新的的代理对象.
+
+
+
+
+### Watch
+
+
+
+❌ 不支持 onTrack
和 onTrigger
选项
+
+
+```js
+watch(() => {
+ /* ... */
+}, {
+ immediate: true,
+ onTrack() {}, // 不可用
+ onTrigger() {}, // 不可用
+})
+```
+
+
+
+
+### 缺失的 API
+
+以下在 Vue 3 新引入的 API ,在本插件中暂不适用:
+
+- `readonly`
+- `shallowReadonly`
+- `defineAsyncComponent`
+- `onRenderTracked`
+- `onRenderTriggered`
+- `customRef`
+- `isProxy`
+- `isReadonly`
+- `isVNode`
+
+
+### 在 `data()` 中使用组合式 API
+
+
+
+❌ 在 data()
中使用 ref
, reactive
或其他组合式 API 将不会生效
+
+
+```jsx
+export default {
+ data() {
+ return {
+ // 在模版中会成为 { a: { value: 1 } }
+ a: ref(1)
+ }
+ },
+}
+```
+
+
+
+
+### 性能影响
+
+用于 Vue 2 所提供的公共 API 的限制,`@vue/composition-api` 不可避免地引入了额外的性能开销。在非极端情况下,这并不会对你造成影响。
+
+你可以查看这个 [跑分结果](https://antfu.github.io/vue-composition-api-benchmark-results/) 了解更多信息。
diff --git a/index.js b/index.js
new file mode 100644
index 00000000..bf4ed976
--- /dev/null
+++ b/index.js
@@ -0,0 +1,7 @@
+'use strict'
+
+if (process.env.NODE_ENV === 'production') {
+ module.exports = require('./dist/vue-composition-api.common.prod.js')
+} else {
+ module.exports = require('./dist/vue-composition-api.common.js')
+}
diff --git a/package.json b/package.json
index 78a81d22..84499985 100644
--- a/package.json
+++ b/package.json
@@ -11,10 +11,11 @@
"type": "git",
"url": "git+https://github.com/vuejs/composition-api.git"
},
- "main": "dist/vue-composition-api.js",
- "umd:main": "dist/vue-composition-api.umd.js",
- "browser": "dist/vue-composition-api.umd.js",
- "module": "dist/vue-composition-api.module.js",
+ "main": "index.js",
+ "module": "dist/vue-composition-api.esm.js",
+ "browser": "dist/vue-composition-api.prod.js",
+ "unpkg": "dist/vue-composition-ap.prod.js",
+ "jsdelivr": "dist/vue-composition-api.prod.js",
"typings": "dist/index.d.ts",
"author": {
"name": "liximomo",
@@ -23,7 +24,8 @@
"license": "MIT",
"sideEffects": false,
"files": [
- "dist"
+ "dist",
+ "index.js"
],
"scripts": {
"start": "concurrently \"tsc --emitDeclarationOnly -w\" \"cross-env TARGET=es rollup -c -w\"",
@@ -32,10 +34,11 @@
"test": "yarn test-dts && yarn test-unit",
"test-unit": "cross-env NODE_ENV=test jest",
"test-dts": "tsc -p ./test-dts/tsconfig.json && yarn build && tsc -p ./test-dts/tsconfig.build.json",
+ "update-readme": "node ./scripts/update-readme.js",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"prepublish": "yarn test",
"postpublish": "yarn release-gh",
- "version": "yarn changelog && git add CHANGELOG.md",
+ "version": "yarn changelog && yarn update-readme && git add CHANGELOG.md README.*",
"release": "yarn version && git push --follow-tags && yarn publish --non-interactive",
"release-gh": "conventional-github-releaser -p angular"
},
diff --git a/rollup.config.js b/rollup.config.js
index 679708c9..8fa7f89a 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -7,27 +7,27 @@ import dts from 'rollup-plugin-dts'
const builds = {
'cjs-dev': {
- outFile: 'vue-composition-api.js',
+ outFile: 'vue-composition-api.common.js',
format: 'cjs',
mode: 'development',
},
'cjs-prod': {
- outFile: 'vue-composition-api.min.js',
+ outFile: 'vue-composition-api.common.prod.js',
format: 'cjs',
mode: 'production',
},
'umd-dev': {
- outFile: 'vue-composition-api.umd.js',
+ outFile: 'vue-composition-api.js',
format: 'umd',
mode: 'development',
},
'umd-prod': {
- outFile: 'vue-composition-api.umd.min.js',
+ outFile: 'vue-composition-api.prod.js',
format: 'umd',
mode: 'production',
},
- es: {
- outFile: 'vue-composition-api.module.js',
+ esm: {
+ outFile: 'vue-composition-api.esm.js',
format: 'es',
mode: 'development',
},
@@ -54,7 +54,7 @@ function genConfig({ outFile, format, mode }) {
vue: 'Vue',
},
exports: 'named',
- name: format === 'umd' ? 'vueCompositionApi' : undefined,
+ name: format === 'umd' ? 'VueCompositionAPI' : undefined,
},
external: ['vue'],
onwarn,
diff --git a/scripts/update-readme.js b/scripts/update-readme.js
new file mode 100644
index 00000000..364b5a9c
--- /dev/null
+++ b/scripts/update-readme.js
@@ -0,0 +1,29 @@
+const { promises: fs } = require('fs')
+const path = require('path')
+const { version } = require('../package.json')
+
+const files = ['../README.md', '../README.zh-CN.md']
+
+const MakeLinks = (version, vueVersion = '2.6') =>
+ `
+\`\`\`html
+
+
+\`\`\`
+`
+
+;(async () => {
+ const links = MakeLinks(version)
+
+ for (const file of files) {
+ const filepath = path.resolve(__dirname, file)
+ const raw = await fs.readFile(filepath, 'utf-8')
+
+ const updated = raw.replace(
+ /([\s\S]*)/g,
+ `${links}`
+ )
+
+ await fs.writeFile(filepath, updated, 'utf-8')
+ }
+})()
diff --git a/src/apis/computed.ts b/src/apis/computed.ts
index bdc2c856..7edda5c7 100644
--- a/src/apis/computed.ts
+++ b/src/apis/computed.ts
@@ -1,4 +1,4 @@
-import { getCurrentVue, getCurrentVM } from '../runtimeContext'
+import { getCurrentVue, getCurrentInstance } from '../runtimeContext'
import { createRef, Ref } from '../reactivity'
import { defineComponentInstance } from '../helper'
import { warn } from '../utils'
@@ -22,7 +22,7 @@ export function computed(options: Option): WritableComputedRef
export function computed(
options: Option['get'] | Option
): ComputedRef | WritableComputedRef {
- const vm = getCurrentVM()
+ const vm = getCurrentInstance()
let get: Option['get'], set: Option['set'] | undefined
if (typeof options === 'function') {
get = options
diff --git a/src/apis/inject.ts b/src/apis/inject.ts
index 9b8e533b..82f504cc 100644
--- a/src/apis/inject.ts
+++ b/src/apis/inject.ts
@@ -1,7 +1,7 @@
import { ComponentInstance } from '../component'
import { currentVMInFn } from '../helper'
import { hasOwn, warn } from '../utils'
-import { getCurrentVM } from '../runtimeContext'
+import { getCurrentInstance } from '../runtimeContext'
const NOT_FOUND = {}
export interface InjectionKey extends Symbol {}
@@ -48,7 +48,7 @@ export function inject(
return defaultValue
}
- const vm = getCurrentVM()
+ const vm = getCurrentInstance()
if (vm) {
const val = resolveInject(key, vm)
if (val !== NOT_FOUND) {
diff --git a/src/apis/lifecycle.ts b/src/apis/lifecycle.ts
index 62457d1b..b7467fc4 100644
--- a/src/apis/lifecycle.ts
+++ b/src/apis/lifecycle.ts
@@ -1,6 +1,10 @@
import { VueConstructor } from 'vue'
import { ComponentInstance } from '../component'
-import { getCurrentVue, setCurrentVM, getCurrentVM } from '../runtimeContext'
+import {
+ getCurrentVue,
+ setCurrentVM,
+ getCurrentInstance,
+} from '../runtimeContext'
import { currentVMInFn } from '../helper'
const genName = (name: string) => `on${name[0].toUpperCase() + name.slice(1)}`
@@ -26,7 +30,7 @@ function injectHookOption(
function wrapHookCall(vm: ComponentInstance, fn: Function) {
return (...args: any) => {
- let preVm = getCurrentVM()
+ let preVm = getCurrentInstance()
setCurrentVM(vm)
try {
return fn(...args)
diff --git a/src/apis/watch.ts b/src/apis/watch.ts
index a4b94633..0639439c 100644
--- a/src/apis/watch.ts
+++ b/src/apis/watch.ts
@@ -2,7 +2,7 @@ import { ComponentInstance } from '../component'
import { Ref, isRef, isReactive } from '../reactivity'
import { assert, logError, noopFn, warn, isFunction } from '../utils'
import { defineComponentInstance } from '../helper'
-import { getCurrentVM, getCurrentVue } from '../runtimeContext'
+import { getCurrentInstance, getCurrentVue } from '../runtimeContext'
import { WatcherPreFlushQueueKey, WatcherPostFlushQueueKey } from '../symbols'
import { ComputedRef } from './computed'
@@ -95,7 +95,7 @@ function getWatchEffectOption(options?: Partial): WatchOptions {
}
function getWatcherVM() {
- let vm = getCurrentVM()
+ let vm = getCurrentInstance()
if (!vm) {
if (!fallbackVM) {
fallbackVM = defineComponentInstance(getCurrentVue())
diff --git a/src/component/defineComponent.ts b/src/component/defineComponent.ts
index 81e24bb2..6a904f22 100644
--- a/src/component/defineComponent.ts
+++ b/src/component/defineComponent.ts
@@ -1,4 +1,3 @@
-import Vue from 'vue'
import { ComponentPropsOptions } from './componentProps'
import {
MethodOptions,
@@ -53,10 +52,3 @@ export function defineComponent<
export function defineComponent(options: any) {
return options as any
}
-
-export const createComponent = ((options: any) => {
- if (__DEV__) {
- Vue.util.warn('`createComponent` has been renamed to `defineComponent`.')
- }
- return defineComponent(options)
-}) as typeof defineComponent
diff --git a/src/component/index.ts b/src/component/index.ts
index ecc2e4e9..fc609147 100644
--- a/src/component/index.ts
+++ b/src/component/index.ts
@@ -1,4 +1,4 @@
-export { defineComponent, createComponent } from './defineComponent'
+export { defineComponent } from './defineComponent'
export { SetupFunction, SetupContext } from './componentOptions'
export { ComponentInstance, ComponentRenderProxy } from './componentProxy'
export { Data } from './common'
diff --git a/src/createApp.ts b/src/createApp.ts
new file mode 100644
index 00000000..e0f12c77
--- /dev/null
+++ b/src/createApp.ts
@@ -0,0 +1,53 @@
+import type Vue from 'vue'
+import { VueConstructor } from 'vue/types/umd'
+import { getCurrentVue } from './runtimeContext'
+import { warn } from './utils'
+
+export interface App {
+ config: VueConstructor['config']
+ use: VueConstructor['use']
+ mixin: VueConstructor['mixin']
+ component: VueConstructor['component']
+ directive: VueConstructor['directive']
+ mount: Vue['$mount']
+ unmount: Vue['$destroy']
+}
+
+export function createApp(rootComponent: any, rootProps: any = undefined): App {
+ const V = getCurrentVue()!
+
+ let mountedVM: Vue | undefined = undefined
+
+ return {
+ config: V.config,
+ use: V.use.bind(V),
+ mixin: V.mixin.bind(V),
+ component: V.component.bind(V),
+ directive: V.directive.bind(V),
+ mount: (el, hydrating) => {
+ if (!mountedVM) {
+ mountedVM = new V({ propsData: rootProps, ...rootComponent })
+ mountedVM.$mount(el, hydrating)
+ return mountedVM
+ } else {
+ if (__DEV__) {
+ warn(
+ `App has already been mounted.\n` +
+ `If you want to remount the same app, move your app creation logic ` +
+ `into a factory function and create fresh app instances for each ` +
+ `mount - e.g. \`const createMyApp = () => createApp(App)\``
+ )
+ }
+ return mountedVM
+ }
+ },
+ unmount: () => {
+ if (mountedVM) {
+ mountedVM.$destroy()
+ mountedVM = undefined
+ } else if (__DEV__) {
+ warn(`Cannot unmount an app that is not mounted.`)
+ }
+ },
+ }
+}
diff --git a/src/createElement.ts b/src/createElement.ts
index 42ee20a8..bb0a3eb9 100644
--- a/src/createElement.ts
+++ b/src/createElement.ts
@@ -7,7 +7,7 @@ type CreateElement = Vue['$createElement']
let fallbackCreateElement: CreateElement
-const createElement: CreateElement = function createElement(...args: any) {
+export const createElement = (function createElement(...args: any) {
if (!currentVM) {
warn('`createElement()` has been called outside of render function.')
if (!fallbackCreateElement) {
@@ -19,6 +19,4 @@ const createElement: CreateElement = function createElement(...args: any) {
}
return currentVM.$createElement.apply(currentVM, args)
-} as any
-
-export default createElement
+} as any) as CreateElement
diff --git a/src/helper.ts b/src/helper.ts
index 97040c04..be5ba135 100644
--- a/src/helper.ts
+++ b/src/helper.ts
@@ -1,10 +1,10 @@
import Vue, { VNode, ComponentOptions, VueConstructor } from 'vue'
import { ComponentInstance } from './component'
-import { currentVue, getCurrentVM } from './runtimeContext'
+import { currentVue, getCurrentInstance } from './runtimeContext'
import { warn } from './utils'
export function currentVMInFn(hook: string): ComponentInstance | null {
- const vm = getCurrentVM()
+ const vm = getCurrentInstance()
if (__DEV__ && !vm) {
warn(
`${hook} is called when there is no active component instance to be ` +
diff --git a/src/index.ts b/src/index.ts
index 325bd340..4c3a9088 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
import Vue, { VueConstructor } from 'vue'
-import { Data, SetupFunction, SetupContext } from './component'
+import { Data, SetupFunction } from './component'
import { install } from './install'
import { mixin } from './setup'
@@ -14,20 +14,17 @@ const VueCompositionAPI = {
}
export default VueCompositionAPI
-
+export { createApp } from './createApp'
export { nextTick } from './nextTick'
-export { default as createElement } from './createElement'
-export { SetupContext }
+export { createElement as h } from './createElement'
+export { getCurrentInstance } from './runtimeContext'
export {
- createComponent,
defineComponent,
ComponentRenderProxy,
PropType,
PropOptions,
+ SetupContext,
} from './component'
-// For getting a hold of the interal instance in setup() - useful for advanced
-// plugins
-export { getCurrentVM as getCurrentInstance } from './runtimeContext'
export * from './apis/state'
export * from './apis/lifecycle'
diff --git a/src/runtimeContext.ts b/src/runtimeContext.ts
index f6894377..a0b7b503 100644
--- a/src/runtimeContext.ts
+++ b/src/runtimeContext.ts
@@ -17,7 +17,7 @@ export function setCurrentVue(vue: VueConstructor) {
currentVue = vue
}
-export function getCurrentVM(): ComponentInstance | null {
+export function getCurrentInstance(): ComponentInstance | null {
return currentVM
}
diff --git a/src/setup.ts b/src/setup.ts
index ac3b73f2..b9e465ab 100644
--- a/src/setup.ts
+++ b/src/setup.ts
@@ -6,7 +6,7 @@ import {
Data,
} from './component'
import { Ref, isRef, isReactive, markRaw } from './reactivity'
-import { getCurrentVM, setCurrentVM } from './runtimeContext'
+import { getCurrentInstance, setCurrentVM } from './runtimeContext'
import { resolveSlots, createSlotProxy } from './helper'
import { hasOwn, isPlainObject, assert, proxy, warn, isFunction } from './utils'
import { ref } from './apis/state'
@@ -112,7 +112,7 @@ function activateCurrentInstance(
fn: (vm_: ComponentInstance) => any,
onError?: (err: Error) => void
) {
- let preVm = getCurrentVM()
+ let preVm = getCurrentInstance()
setCurrentVM(vm)
try {
return fn(vm)
diff --git a/test/createApp.spec.js b/test/createApp.spec.js
new file mode 100644
index 00000000..d299be73
--- /dev/null
+++ b/test/createApp.spec.js
@@ -0,0 +1,66 @@
+const Vue = require('vue/dist/vue.common.js')
+const { createApp, defineComponent, ref, h } = require('../src')
+
+describe('createApp', () => {
+ it('should work', async () => {
+ const vm = new Vue({
+ setup() {
+ return {
+ a: ref(1),
+ }
+ },
+ template: '{{a}}
',
+ }).$mount()
+
+ await Vue.nextTick()
+ expect(vm.a).toBe(1)
+ expect(vm.$el.textContent).toBe('1')
+ })
+
+ it('should work with rootProps', async () => {
+ const app = createApp(
+ defineComponent({
+ props: {
+ msg: String,
+ },
+ template: '{{msg}}
',
+ }),
+ {
+ msg: 'foobar',
+ }
+ )
+ const vm = app.mount()
+
+ await Vue.nextTick()
+ expect(vm.$el.textContent).toBe('foobar')
+ })
+
+ it('should work with components', async () => {
+ const Foo = defineComponent({
+ props: {
+ msg: {
+ type: String,
+ required: true,
+ },
+ },
+ template: '{{msg}}
',
+ })
+
+ const app = createApp(
+ defineComponent({
+ props: {
+ msg: String,
+ },
+ template: '',
+ }),
+ {
+ msg: 'foobar',
+ }
+ )
+ app.component('Foo', Foo)
+ const vm = app.mount()
+
+ await Vue.nextTick()
+ expect(vm.$el.textContent).toBe('foobar')
+ })
+})
diff --git a/test/setup.spec.js b/test/setup.spec.js
index 92a770ea..cf67075b 100644
--- a/test/setup.spec.js
+++ b/test/setup.spec.js
@@ -2,7 +2,7 @@ const Vue = require('vue/dist/vue.common.js')
const {
ref,
computed,
- createElement: h,
+ h,
provide,
inject,
reactive,
diff --git a/test/setupContext.spec.js b/test/setupContext.spec.js
index 017af58b..1d33cb55 100644
--- a/test/setupContext.spec.js
+++ b/test/setupContext.spec.js
@@ -1,5 +1,5 @@
const Vue = require('vue/dist/vue.common.js')
-const { ref, watch, createElement: h } = require('../src')
+const { h } = require('../src')
describe('setupContext', () => {
it('should have proper properties', () => {
diff --git a/test/templateRefs.spec.js b/test/templateRefs.spec.js
index 8745a82c..10bbc566 100644
--- a/test/templateRefs.spec.js
+++ b/test/templateRefs.spec.js
@@ -1,5 +1,5 @@
const Vue = require('vue/dist/vue.common.js')
-const { ref, watchEffect, watch, createElement: h } = require('../src')
+const { ref, watchEffect } = require('../src')
describe('ref', () => {
it('should work', (done) => {
diff --git a/test/types/defineComponent.spec.ts b/test/types/defineComponent.spec.ts
index d4fe4b31..709fda70 100644
--- a/test/types/defineComponent.spec.ts
+++ b/test/types/defineComponent.spec.ts
@@ -1,7 +1,6 @@
import {
- createComponent,
defineComponent,
- createElement as h,
+ h,
ref,
SetupContext,
PropType,
@@ -217,38 +216,4 @@ describe('defineComponent', () => {
})
})
})
-
- describe('retro-compatible with createComponent', () => {
- it('should still work and warn', () => {
- const warn = jest
- .spyOn(global.console, 'error')
- .mockImplementation(() => null)
- const Child = createComponent({
- props: { msg: String },
- setup(props) {
- return () => h('span', props.msg)
- },
- })
-
- const App = createComponent({
- setup() {
- const msg = ref('hello')
- return () =>
- h('div', [
- h(Child, {
- props: {
- msg: msg.value,
- },
- }),
- ])
- },
- })
- const vm = new Vue(App).$mount()
- expect(vm.$el.querySelector('span').textContent).toBe('hello')
- expect(warn.mock.calls[0][0]).toMatch(
- '[Vue warn]: `createComponent` has been renamed to `defineComponent`.'
- )
- warn.mockRestore()
- })
- })
})
diff --git a/test/v3/runtime-core/apiLifecycle.spec.ts b/test/v3/runtime-core/apiLifecycle.spec.ts
index f952bdc4..418c282a 100644
--- a/test/v3/runtime-core/apiLifecycle.spec.ts
+++ b/test/v3/runtime-core/apiLifecycle.spec.ts
@@ -4,7 +4,7 @@ import {
onBeforeMount,
onMounted,
ref,
- createElement as h,
+ h,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,