mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
docs: add migration guide for bridge composition api (#1669)
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
parent
bd7e3b41de
commit
875deefafc
@ -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 | ✅
|
||||
|
@ -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: {
|
||||
|
210
docs/content/1.getting-started/4.bridge-composition-api.md
Normal file
210
docs/content/1.getting-started/4.bridge-composition-api.md
Normal 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'
|
||||
},
|
||||
})
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user