docs: add migration guide for bridge composition api (#1669)

Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
Daniel Roe 2021-11-04 11:20:40 +00:00 committed by GitHub
parent bd7e3b41de
commit 875deefafc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 288 additions and 19 deletions

View File

@ -63,12 +63,12 @@ In the table below, there is a quick comparison between 3 versions of Nuxt:
Feature / Version | Nuxt 2 | Nuxt Bridge | Nuxt 3
-------------------------|-----------------|------------------|---------
Stability | 😊 Stable | 😌 Semi-stable | 😬 Unstable
Performance | 🏎 Fast | ✈️ Faster | 🚀 Fastest
Performance | 🏎 Fast | ✈️ Faster | 🚀 Fastest
Nitro Engine | ❌ | ✅ | ✅
ESM support | 🌙 Partial | 👍 Better | ✅
TypeScript | ☑️ Opt-in | 🚧 Faster | ✅
Composition API | ⚠️ Deprecated | ✅ | ✅
Options API | ✅ | ✅ | ✅ (not recommended)
Options API | ✅ | ✅ | ✅
Components Auto Import | ✅ | ✅ | ✅
`<script setup>` syntax | ❌ | 🚧 Partial | ✅
Auto Imports | ❌ | ✅ | ✅
@ -76,3 +76,4 @@ Webpack | 4 | 4 | 5
Vite | ⚠️ Partial | 🚧 Partial | 🚧 Experimental
Nuxi CLI | ❌ Old | ✅ nuxi | ✅ nuxi
Static sites | ✅ | ✅ | 🚧
Composition API | ❌ | 🚧 Partial | ✅

View File

@ -7,6 +7,10 @@ If you're starting a fresh Nuxt 3 project, please skip this section and go to [N
Learn more in [Introduction](/getting-started/introduction).
::
::alert{type=warning}
Nuxt Bridge provides identical features to Nuxt 3 ([docs](/docs/usage)) but there are some limitations, notably that `useAsyncData` and `useFetch` composables are not available. Please read the rest of this page for details.
::
Bridge is a forward-compatibility layer that allows you to experience many of new Nuxt 3 features by simply installing and enabling a Nuxt module.
Using Nuxt Bridge, you can make sure your project is (almost) ready for Nuxt 3 and have the best developer experience without needing a major rewrite or risk breaking changes.
@ -127,6 +131,10 @@ If you are using TypeScript, you can edit your `tsconfig.json` to benefit from a
}
```
## Migrate Composition API
If you were previously using `@vue/composition-api` or `@nuxtjs/composition-api`, please read the [composition api migration guide](/getting-started/bridge-composition-api).
## Avoid CommonJS syntax
Nuxt 3 natively supports TypeScript and ECMAScript Modules.
@ -174,9 +182,10 @@ Avoid the usage of `__dirname` and `__filename` as much as possible.
- Remove `@nuxt/typescript-build`: Bridge enables same functionality
- Remove `@nuxt/typescript-runtime` and `nuxt-ts`: Nuxt 2 has built-in runtime support
- Remove `@nuxt/nitro`: Bridge injects same functionality
- Remove `@nuxtjs/composition-api` from your dependencies (and from your modules in `nuxt.config`). Bridge provides a legacy composition API layer that handles imports within your files from `@nuxtjs/composition-api` until you've fully finished migrating to native Bridge/Nuxt 3 composables (which you will import from by `#app`, or via auto-imports).
- Remove `@vue/composition-api` from your dependencies ([migration guide](/getting-started/bridge-composition-api)).
- Remove `@nuxtjs/composition-api` from your dependencies (and from your modules in `nuxt.config`) ([migration guide](/getting-started/bridge-composition-api)).
## Exclude Nuxt build folder from git
## Exclude built Nitro folder from git
Add the folder `.output` to the `.gitignore` file.
@ -194,6 +203,51 @@ export default defineNuxtConfig({
})
```
## New plugins format (optional)
You can now migrate to the Nuxt 3 plugins API, which is slightly different in format from Nuxt 2.
Plugins now take only one argument (`nuxtApp`). You can find out more in [the docs](/docs/directory-structure/plugins).
```js
import { defineNuxtPlugin } from '#app'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.provide('injected', () => 'my injected function')
// now available on `nuxtApp.$injected`
})
```
## New `useMeta` (optional)
Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new `useMeta` composable.
```vue
<script setup>
import { useMeta } from '#app'
useMeta({
title: 'My Nuxt App',
})
</script>
```
You will also need to enable this feature explicitly in your `nuxt.config`:
```js
import { defineNuxtConfig } from '@nuxt/bridge'
export default defineNuxtConfig({
bridge: {
meta: true
}
})
```
This `useMeta` composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`.
Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as `useMeta`, as they may conflict.
For more information on how to use this composable, see [the docs](/docs/usage/meta-tags#usemeta-composable).
## Feature Flags
You can optionally disable some features from bridge or opt-in to less stable ones. In normal circumstances, it is always best to stick with defaults!
@ -211,6 +265,9 @@ export default defineNuxtConfig({
// Use Vite as the bundler instead of Webpack 4
// vite: true,
// Enable Nuxt 3 compatible useMeta
// meta: true,
// -- Default features --
// Use legacy server instead of Nitro
@ -232,10 +289,7 @@ export default defineNuxtConfig({
// autoImports: false,
// Do not warn about module incompatibilities
// constraints: false,
// Disable Nuxt 3 compatible useMeta
// meta: false,
// constraints: false
},
vite: {

View File

@ -0,0 +1,210 @@
---
navigation: false
---
# Migrating to Bridge Composition API
Nuxt Bridge provides access to Composition API syntax. It is specifically designed to be aligned with Nuxt 3. Because of this, there are a few extra steps to take when enabling Nuxt Bridge, if you have been using the Composition API previously.
## Using `@vue/composition-api`
If you have been using just `@vue/composition-api` and not `@nuxtjs/composition-api`, then things are very straightforward.
1. First, remove the plugin where you are manually registering the Composition API. Nuxt Bridge will handle this for you.
```diff
- import Vue from 'vue'
- import VueCompositionApi from '@vue/composition-api'
-
- Vue.use(VueCompositionApi)
```
2. Otherwise, there is nothing you need to do. However, if you want, you can remove your explicit imports from `@vue/composition-api` and rely on Nuxt Bridge auto-importing them for you.
## Migrating from `@nuxtjs/composition-api`
Nuxt Bridge implements the Composition API slightly differently from `@nuxtjs/composition-api` and provides different composables (designed to be aligned with the composables that Nuxt 3 provides).
Because some composables have been removed and don't yet have a replacement, this will be a slightly more complicated process.
1. Remove `@nuxtjs/composition-api` from your project dependencies, and remove `@nuxtjs/composition-api/module` from your buildModules.
You don't have to immediately update your imports yet - Nuxt Bridge will automatically provide a 'shim' for most imports you currently have, to give you time to migrate to the new, Nuxt 3-compatible composables, with the following exceptions:
* `withContext` has been removed. See [below](#usecontext-and-withcontext).
* `useStatic` has been removed. There is no current replacement. Feel free to raise a discussion if you have a use case for this.
* `reqRef` and `reqSsrRef`, which were deprecated, have now been removed entirely. Follow the instructions below regarding [ssrRef](#ssrref-and-shallowssrref) to replace this.
2. Remove any explicit imports of the basic Vue Composition API composables, or move them to import from `#app` or `vue`.
```diff
- import { ref, useContext } from '@nuxtjs/composition-api`
+ import { ref } from '#app'
```
3. For each other composable you are using from `@nuxtjs/composition-api`, follow the steps below.
### `defineNuxtMiddleware`
This was a type-helper stub function that is now removed.
Simply remove the `defineNuxtMiddleware` wrapper:
```diff
- import { defineNuxtMiddleware } from '@nuxtjs/composition-api`
- export default defineNuxtMiddleware((ctx) => {})
+ export default (ctx) => {}
```
For typescript support, you can use `@nuxt/types`:
```ts
import type { Middleware } from '@nuxt/types'
export default <Middleware> function (ctx) { }
```
### `defineNuxtPlugin`
This was a type-helper stub function that is now removed.
You may also keep using Nuxt 2-style plugins, by simply removing the function (as with [defineNuxtMiddleware](#definenuxtmiddleware)).
Simply remove the `defineNuxtMiddleware` wrapper:
```diff
- import { defineNuxtPlugin } from '@nuxtjs/composition-api`
- export default defineNuxtPlugin((ctx, inject) => {})
+ export default (ctx, inject) => {}
```
For typescript support, you can use `@nuxt/types`:
```ts
import type { Plugin } from '@nuxt/types'
export default <Plugin> function (ctx, inject) {}
```
### `onGlobalSetup`
This function has been removed, but many use cases can be met by using `useNuxtApp` or `useState` within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout.
If you have another use case for `onGlobalSetup`, please let us know via a discussion.
### `ssrRef` and `shallowSsrRef`
These two functions have been replaced with a new composable that works very similarly under the hood: `useState`.
The key differences are that you must provide a _key_ for this state (which previously will have been generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use `useState` with a global/ambient context, because of the danger of shared state across requests.)
```diff
- import { ssrRef } from '@nuxtjs/composition-api'
+ import { useState } from '#app'
- const ref1 = ssrRef('initialData')
- const ref2 = ssrRef(() => 'factory function')
+ const ref1 = useState('ref1-key', () => 'initialData')
+ const ref2 = useState('ref2-key', () => 'factory function')
// accessing the state
console.log(ref1.value)
```
Because the state is keyed, you can access the same state from multiple locations, as long as you are using the same key.
You can read more about how to use this composable in [the Nuxt 3 docs](/docs/usage/state#usestate).
### `ssrPromise`
This function has been removed, and you will need to find an alternative implementation if you were using it. If you have a use case for `ssrPromise`, please let us know via a discussion.
### `useRouter` and `useRoute`
Nuxt Bridge provides direct replacements for these composables via `useRouter` and `useRoute`.
The only key difference is that `useRoute` no longer returns a computed property.
```diff
- import { useRouter, useRoute } from '@nuxtjs/composition-api'
+ import { useRouter, useRoute } from '#app'
const router = useRouter()
const route = useRoute()
- console.log(route.value.path)
+ console.log(route.path)
```
### `useStore`
In order to access Vuex store instance, you can use `useNuxtApp().$store`.
```diff
- import { useStore } from '@nuxtjs/composition-api`
+ import { useNuxtApp } from '#app'
+ const { $store } = useNuxtApp()
```
```vue
<script>
import { useNuxtApp } from '#app'
const { $store } = useNuxtApp()
</script>
```
### `useContext` and `withContext`
You can access injected helpers using `useNuxtApp`.
```diff
- import { useContext } from '@nuxtjs/composition-api`
+ import { useNuxtApp } from '#app'
+ const { $axios } = useNuxtApp()
```
```vue
<script>
import { useNuxtApp } from '#app'
const { $axios } = useNuxtApp()
</script>
```
::alert{icon=👉}
`useNuxtApp()` also provides a key called `nuxt2Context` which contains all the same properties you would normally access from Nuxt 2 context, but it's advised _not_ to use this directly, as it won't exist in Nuxt 3. Instead, see if there is another way to access what you need. (If not, please raise a feature request or discussion.)
::
### `wrapProperty`
This helper function is not provided any more but you can replace it with the following code:
```js
const wrapProperty = (property, makeComputed = true) => () => {
const vm = getCurrentInstance().proxy
return makeComputed ? computed(() => vm[property]) : vm[property]
}
```
### `useAsync` and `useFetch`
There is currently no replacement for these two functions with bridge.
You can continue to use `useAsync` and `useFetch` by importing them from `@nuxtjs/composition-api`, which is shimmed by Nuxt Bridge.
### `useMeta`
In order to use vue-meta, you can continue importing `useMeta` and `defineComponent` from `@nuxtjs/composition-api`, which is shimmed by Nuxt Bridge.
However, note that the existing limitations of `useMeta` continue, so it cannot be used in `<script setup>` and you must include a `head: {}` object within your `defineComponent`.
```js
import { defineComponent, useMeta } from '@nuxtjs/composition-api'
export default defineComponent({
// You need to define an empty head to activate this functionality
head: {},
setup() {
// This will allow you to set the title in head - but won't allow you to read its state outside of this component.
const { title } = useMeta()
title.value = 'My page'
},
})

View File

@ -1,7 +1,7 @@
import defu from 'defu'
import { computed, getCurrentInstance as getVM, isReactive, isRef, onBeforeMount, onServerPrefetch, reactive, ref, set, shallowRef, toRaw, toRefs, watch } from '@vue/composition-api'
import { useNuxtApp } from './app'
import { useState } from './composables'
import { useRouter as _useRouter, useState } from './composables'
// Vue composition API export
export {
@ -62,7 +62,7 @@ export { ref }
// Common deprecation utils
// TODO: Add migration guide docs to @nuxtjs/composition-api
const checkDocsMsg = 'Please see https://v3.nuxtjs.org for more information.'
const checkDocsMsg = 'Please see https://go.nuxtjs.dev/bridge-capi for more information.'
const msgPrefix = '[bridge] [legacy capi]'
const unsupported = message => () => { throw new Error(`${msgPrefix} ${message} ${checkDocsMsg}`) }
const _warned = {}
@ -73,8 +73,9 @@ const warnOnce = (id, message) => {
}
}
// TODO: Add warning back once we had replacement for useAsync and useMeta
// Warn in case of having any imports from `@nuxtjs/composition-api`
warnOnce('import', `\`@nuxtjs/composition-api\` is deprecated. ${checkDocsMsg}`)
// warnOnce('import', `\`@nuxtjs/composition-api\` is deprecated. ${checkDocsMsg}`)
// Stub functions that provided type support
export const defineNuxtMiddleware = unsupported('You are using `defineNuxtMiddleware`, which is not supported. You can remove wrapper function to keep using Nuxt 2 middleware.')
@ -86,10 +87,10 @@ export const setSSRContext = unsupported('`setSSRContext` is an internal functio
export const globalPlugin = unsupported('`globalPlugin` is an internal function that is no longer used.')
// Deprecated functions
export const withContext = unsupported('`withContext` is a deprecated method that is no longer provided.')
export const withContext = unsupported('`withContext` is a deprecated method that is no longer provided and can be replaced with `useNuxtApp` (import from `#app`).')
export const useStatic = unsupported('`useStatic` is a deprecated method that is no longer provided.')
export const reqRef = unsupported('`reqRef` is a deprecated method that is no longer provided.')
export const reqSsrRef = unsupported('`reqSsrRef` is no longer provided (`ssrRef` can be used instead).')
export const reqRef = unsupported('`reqRef` is a deprecated method that is no longer provided and can be replaced with `ref` (import from `@vue/composition-api`).')
export const reqSsrRef = unsupported('`reqSsrRef` is no longer provided and can be replaced with `useState` (import from `#app`).')
// ssrRef helpers
const sanitise = val => (val && JSON.parse(JSON.stringify(val))) || val
@ -99,13 +100,13 @@ export const ssrRef = (value, key) => {
const vm = getVM()
if (!vm) { throw new Error('ssrRef no longer supports global/ambient context and must be called within a setup() function') }
warnOnce('ssrRef', '`ssrRef` is deprecated and can be replaced with `useState`.')
warnOnce('ssrRef', '`ssrRef` is deprecated and can be replaced with `useState` (import from `#app`).')
return useState(key, value instanceof Function ? value : () => value)
}
export const shallowSsrRef = (value, key) => {
warnOnce('shallowSsrRef', '`shallowSsrRef` is deprecated and can be replaced with `useState`.')
warnOnce('shallowSsrRef', '`shallowSsrRef` is deprecated and can be replaced with `useState` (import from `#app`).')
const ref = ssrRef(value, key)
@ -186,7 +187,7 @@ function createEmptyMeta () {
}
}
export const getHeadOptions = (options) => {
const getHeadOptions = (options) => {
const head = function () {
const optionHead =
options.head instanceof Function ? options.head.call(this) : options.head
@ -247,7 +248,7 @@ export const wrapProperty = (property, makeComputed = true) => () => {
export const useRouter = () => {
warnOnce('useRouter', 'You are using `useRouter`, which can be replaced with `useRouter` (import from `#app`).')
return getCurrentInstance().$router
return _useRouter()
}
export const useRoute = () => {
@ -256,7 +257,10 @@ export const useRoute = () => {
return computed(() => vm.$route)
}
export const useStore = () => getCurrentInstance().$store
export const useStore = () => {
warnOnce('useRoute', 'You are using `useStore`, which can be replaced with `useNuxtApp` (import from `#app`).')
return getCurrentInstance().$store
}
// useFetch and helper functions