feat(bridge): add `useNuxtApp` and `defineNuxtPlugin` composables (#576)

This commit is contained in:
Daniel Roe 2021-09-25 09:24:37 +01:00 committed by GitHub
parent c5979d9fb5
commit 3bf856830b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 7 deletions

View File

@ -1,4 +1,4 @@
import { useNuxt, addPluginTemplate } from '@nuxt/kit'
import { useNuxt, addPlugin, addPluginTemplate } from '@nuxt/kit'
import { resolve } from 'upath'
import { distDir } from './dirs'
@ -14,6 +14,11 @@ export function setupCAPIBridge (_options: any) {
nuxt.options.alias['@vue/composition-api'] = require.resolve('@vue/composition-api/dist/vue-composition-api.mjs')
const capiPluginPath = resolve(distDir, 'runtime/capi.plugin.mjs')
addPluginTemplate({ filename: 'capi.plugin.mjs', src: capiPluginPath })
// Add support for useNuxtApp
addPlugin(resolve(distDir, 'runtime/app.plugin.mjs'))
// Register Composition API before loading the rest of app
nuxt.hook('webpack:config', (configs) => {
// @ts-ignore
configs.forEach(config => config.entry.app.unshift(capiPluginPath))

View File

@ -1,5 +0,0 @@
const mock = () => () => { throw new Error('not implemented') }
export const defineNuxtPlugin = mock()
export const defineNuxtComponent = mock()
export const useNuxtApp = mock()

View File

@ -0,0 +1,27 @@
import { createHooks } from 'hookable/dist/index.mjs'
import { setNuxtInstance } from '#app'
export default (ctx, inject) => {
const nuxt = {
provide: inject,
globalName: 'nuxt',
payload: process.client ? ctx.nuxtState : ctx.ssrContext.nuxt,
isHydrating: ctx.isHMR,
legacyNuxt: ctx.app
}
nuxt.hooks = createHooks()
nuxt.hook = nuxt.hooks.hook
nuxt.callHook = nuxt.hooks.callHook
if (!Array.isArray(ctx.app.created)) {
ctx.app.created = [ctx.app.created]
}
ctx.app.created.push(function () {
nuxt.legacyApp = this
})
setNuxtInstance(nuxt)
inject('_nuxtApp', nuxt)
}

View File

@ -0,0 +1,59 @@
import type { Hookable } from 'hookable'
// @ts-ignore
import type { Vue } from 'vue/types/vue'
import type { ComponentOptions } from 'vue'
import { defineComponent, getCurrentInstance } from './composables'
export const defineNuxtComponent = defineComponent
export interface RuntimeNuxtHooks { }
export interface NuxtAppCompat {
legacyNuxt: Vue
legacyApp: ComponentOptions<Vue>
globalName: string
hooks: Hookable<RuntimeNuxtHooks>
hook: NuxtAppCompat['hooks']['hook']
callHook: NuxtAppCompat['hooks']['callHook']
[key: string]: any
ssrContext?: Record<string, any>
payload: {
[key: string]: any
}
provide: (name: string, value: any) => void
}
export interface Context {
// eslint-disable-next-line
$_nuxtApp: NuxtAppCompat
}
let currentNuxtInstance: NuxtAppCompat | null
export const setNuxtInstance = (nuxt: NuxtAppCompat | null) => {
currentNuxtInstance = nuxt
}
export const defineNuxtPlugin = plugin => (ctx: Context) => {
setNuxtInstance(ctx.$_nuxtApp)
plugin(ctx.$_nuxtApp)
setNuxtInstance(null)
}
export const useNuxtApp = () => {
const vm = getCurrentInstance()
if (!vm) {
if (!currentNuxtInstance) {
throw new Error('nuxt instance unavailable')
}
return currentNuxtInstance
}
return vm?.proxy.$_nuxtApp
}

View File

@ -68,7 +68,6 @@ export function createNuxt (options: CreateOptions) {
const nuxt: NuxtApp = {
provide: undefined,
globalName: 'nuxt',
state: {},
payload: {},
isHydrating: process.client,
...options