Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

feat(bridge): use useMeta in bridge projects #664

Merged
merged 14 commits into from Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/bridge/package.json
Expand Up @@ -19,6 +19,7 @@
"@nuxt/nitro": "3.0.0",
"@nuxt/postcss8": "^1.1.3",
"@vue/composition-api": "^1.2.3",
"@vueuse/head": "^0.6.0",
"acorn": "^8.5.0",
"defu": "^5.0.0",
"enhanced-resolve": "^5.8.3",
Expand Down
9 changes: 6 additions & 3 deletions packages/bridge/src/app.ts
Expand Up @@ -12,9 +12,12 @@ export function setupAppBridge (_options: any) {
// Transpile runtime/
nuxt.options.build.transpile.push(resolve(distDir, 'runtime'))

// Resolve to same vue2 path
nuxt.options.alias.vue = nuxt.options.alias.vue ||
resolveModule('vue/dist/vue.runtime.esm.js', { paths: nuxt.options.modulesDir })
// Alias vue to a vue3-compat version of vue2
nuxt.options.alias['#vue'] = nuxt.options.alias.vue || resolveModule('vue/dist/vue.runtime.esm.js', { paths: nuxt.options.modulesDir })
nuxt.options.alias['@vue/shared'] = 'vue'
nuxt.options.alias['@vue/reactivity'] = 'vue'
nuxt.options.alias.vue = resolve(distDir, 'runtime/vue.mjs')
nuxt.options.build.transpile.push('vue')

// Deprecate various Nuxt options
if (nuxt.options.globalName !== 'nuxt') {
Expand Down
4 changes: 3 additions & 1 deletion packages/bridge/src/global-imports.ts
Expand Up @@ -3,7 +3,6 @@ import globalImports from '../../nuxt3/src/global-imports/module'

// TODO: implement these: https://github.com/nuxt/framework/issues/549
const disabled = [
'useMeta',
'useAsyncData',
'asyncData'
]
Expand All @@ -17,6 +16,9 @@ const identifiers = {
'useRouter',
'useRuntimeConfig'
],
'#meta': [
'useMeta'
],
'@vue/composition-api': [
// lifecycle
'onActivated',
Expand Down
29 changes: 29 additions & 0 deletions packages/bridge/src/meta.ts
@@ -0,0 +1,29 @@
import { resolve } from 'pathe'
import { addTemplate, useNuxt, installModule } from '@nuxt/kit'
import metaModule from '../../nuxt3/src/meta/module'
import { distDir } from './dirs'

const checkDocsMsg = 'Please see https://v3.nuxtjs.org for more information.'
const msgPrefix = '[bridge] [meta]'

export const setupMeta = async (opts: { enable: true | null }) => {
const nuxt = useNuxt()

if (!opts.enable) {
const metaPath = addTemplate({
filename: 'meta.mjs',
getContents: () => `export const useMeta = () => console.warn('${msgPrefix} To use \`useMeta\`, please set \`bridge.meta\` to \`true\` in your \`nuxt.config\`. ${checkDocsMsg}')`
})
nuxt.options.alias['#meta'] = metaPath.dst
return
}

if (nuxt.options.head && typeof nuxt.options.head === 'function') {
throw new TypeError(`${msgPrefix} The head() function in \`nuxt.config\` has been deprecated and in nuxt3 will need to be moved to \`app.vue\`. ${checkDocsMsg}`)
}

const runtimeDir = resolve(distDir, 'runtime/meta')
nuxt.options.alias['#meta'] = runtimeDir

await installModule(nuxt, metaModule)
}
7 changes: 6 additions & 1 deletion packages/bridge/src/module.ts
Expand Up @@ -6,16 +6,17 @@ import { setupCAPIBridge } from './capi'
import { setupBetterResolve } from './resolve'
import { setupGlobalImports } from './global-imports'
import { setupTypescript } from './typescript'
import { setupMeta } from './meta'

export interface BridgeConfig {
nitro: boolean
vite: boolean
app: boolean | {}
capi: boolean | {}
globalImports: boolean
meta: boolean | null
constraints: boolean
postcss8: boolean
swc: boolean
resolve: boolean
typescript: boolean
}
Expand All @@ -30,6 +31,7 @@ export default defineNuxtModule({
capi: {},
globalImports: true,
constraints: true,
meta: null,
// TODO: Remove from 2.16
postcss8: true,
typescript: true,
Expand Down Expand Up @@ -78,6 +80,9 @@ export default defineNuxtModule({
}
})
}
if (opts.meta !== false && opts.capi) {
await setupMeta({ enable: opts.meta })
danielroe marked this conversation as resolved.
Show resolved Hide resolved
}
}
})

Expand Down
21 changes: 21 additions & 0 deletions packages/bridge/src/runtime/app.plugin.mjs
@@ -1,14 +1,31 @@
import Vue from 'vue'
import { createHooks } from 'hookable/dist/index.mjs'
import { setNuxtInstance } from '#app'

export default (ctx, inject) => {
const nuxt = {
app: {
component: Vue.component.bind(Vue),
config: {
globalProperties: {}
},
directive: Vue.directive.bind(Vue),
mixin: Vue.mixin.bind(Vue),
mount: () => {},
provide: inject,
unmount: () => {},
use (vuePlugin) {
vuePlugin.install(this)
},
version: Vue.version
},
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
Expand All @@ -17,6 +34,10 @@ export default (ctx, inject) => {
ctx.app.created = [ctx.app.created]
}

if (process.server) {
nuxt.ssrContext = ctx.ssrContext
}

ctx.app.created.push(function () {
nuxt.legacyApp = this
})
Expand Down
7 changes: 7 additions & 0 deletions packages/bridge/src/runtime/capi.plugin.mjs
Expand Up @@ -3,4 +3,11 @@ import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI.default || VueCompositionAPI)

Vue.mixin({
pi0 marked this conversation as resolved.
Show resolved Hide resolved
setup () {
const vm = getCurrentInstance()
vm.type = vm.type || vm.proxy?.$options
}
})

export default function () {}
1 change: 1 addition & 0 deletions packages/bridge/src/runtime/meta
50 changes: 36 additions & 14 deletions packages/bridge/src/runtime/nitro-bridge.server.mjs
@@ -1,27 +1,49 @@
export default ({ ssrContext }) => {
ssrContext.renderMeta = () => {
const meta = ssrContext.meta.inject({
isSSR: ssrContext.nuxt.serverRendered,
ln: process.env.NODE_ENV === 'development'
})
const vueMetaRenderer = (nuxt) => {
const meta = nuxt.ssrContext.meta.inject({
isSSR: nuxt.ssrContext.nuxt.serverRendered,
ln: process.env.NODE_ENV === 'development'
})

return {
htmlAttrs: meta.htmlAttrs.text(),
headAttrs: meta.headAttrs.text(),
headTags:
return {
htmlAttrs: meta.htmlAttrs.text(),
headAttrs: meta.headAttrs.text(),
headTags:
meta.title.text() + meta.base.text() +
meta.meta.text() + meta.link.text() +
meta.style.text() + meta.script.text() +
meta.noscript.text(),
bodyAttrs: meta.bodyAttrs.text(),
bodyScriptsPrepend:
bodyAttrs: meta.bodyAttrs.text(),
bodyScriptsPrepend:
meta.meta.text({ pbody: true }) + meta.link.text({ pbody: true }) +
meta.style.text({ pbody: true }) + meta.script.text({ pbody: true }) +
meta.noscript.text({ pbody: true }),
bodyScripts:
bodyScripts:
meta.meta.text({ body: true }) + meta.link.text({ body: true }) +
meta.style.text({ body: true }) + meta.script.text({ body: true }) +
meta.noscript.text({ body: true })
}
}
}

export default defineNuxtPlugin((nuxt) => {
const metaRenderers = [vueMetaRenderer]

nuxt.callHook('meta:register', metaRenderers)

nuxt.ssrContext.renderMeta = async () => {
const metadata = {
htmlAttrs: '',
headAttrs: '',
headTags: '',
bodyAttrs: '',
bodyScriptsPrepend: '',
bodyScripts: ''
}
for await (const renderer of metaRenderers) {
const result = await renderer(nuxt)
for (const key in result) {
metadata[key] += result[key]
}
}
return metadata
}
})
7 changes: 7 additions & 0 deletions packages/bridge/src/runtime/vue.mjs
@@ -0,0 +1,7 @@
import Vue from '#vue'

export * from '@vue/composition-api'

export const isFunction = fn => fn instanceof Function

export { Vue as default }
16 changes: 16 additions & 0 deletions packages/kit/src/config/schema/_app.ts
Expand Up @@ -103,6 +103,22 @@ export default {
script: []
},

/**
* Set default configuration for `<head>` on every page.
*
* @version 3
*/
meta: {
/** Each item in the array maps to a newly-created `<meta>` element, where object properties map to attributes. */
meta: [],
/** Each item in the array maps to a newly-created `<link>` element, where object properties map to attributes. */
link: [],
/** Each item in the array maps to a newly-created `<style>` element, where object properties map to attributes. */
style: [],
/** Each item in the array maps to a newly-created `<script>` element, where object properties map to attributes. */
script: []
},

/**
* Configuration for the Nuxt `fetch()` hook.
* @version 2
Expand Down
2 changes: 2 additions & 0 deletions packages/nuxt3/src/app/nuxt.ts
@@ -1,3 +1,4 @@
/* eslint-disable no-use-before-define */
import { getCurrentInstance, reactive } from 'vue'
import type { App, VNode } from 'vue'
import { createHooks, Hookable } from 'hookable'
Expand All @@ -21,6 +22,7 @@ export interface RuntimeNuxtHooks {
'app:rendered': () => HookResult
'page:start': (Component?: VNode) => HookResult
'page:finish': (Component?: VNode) => HookResult
'meta:register': (metaRenderers: Array<(nuxt: NuxtApp) => NuxtMeta | Promise<NuxtMeta>>) => HookResult
}

export interface NuxtApp {
Expand Down
11 changes: 6 additions & 5 deletions packages/nuxt3/src/meta/module.ts
@@ -1,5 +1,6 @@
import { resolve } from 'pathe'
import { addPlugin, addTemplate, defineNuxtModule } from '@nuxt/kit'
import { addPlugin, addTemplate, defineNuxtModule, isNuxt3 } from '@nuxt/kit'
import defu from 'defu'
import { distDir } from '../dirs'
import type { MetaObject } from './runtime'

Expand All @@ -10,7 +11,7 @@ export default defineNuxtModule({
viewport: 'width=device-width, initial-scale=1'
},
setup (options, nuxt) {
const runtimeDir = resolve(distDir, 'meta/runtime')
const runtimeDir = nuxt.options.alias['#meta'] || resolve(distDir, 'meta/runtime')

// Transpile @nuxt/meta and @vueuse/head
nuxt.options.build.transpile.push(runtimeDir, '@vueuse/head')
Expand All @@ -19,17 +20,17 @@ export default defineNuxtModule({
nuxt.options.alias['#meta'] = runtimeDir

// Global meta
const globalMeta: MetaObject = {
const globalMeta: MetaObject = defu(nuxt.options.meta, {
meta: [
{ charset: options.charset },
{ name: 'viewport', content: options.viewport }
]
}
})

// Add global meta configuration
addTemplate({
filename: 'meta.config.mjs',
getContents: () => 'export default ' + JSON.stringify({ globalMeta })
getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: isNuxt3() ? 'created' : 'setup' })
})

// Add generic plugin
Expand Down
8 changes: 4 additions & 4 deletions packages/nuxt3/src/meta/runtime/plugin.ts
Expand Up @@ -9,11 +9,11 @@ export default defineNuxtPlugin((nuxt) => {
useMeta(metaConfig.globalMeta)

nuxt.app.mixin({
created () {
const instance = getCurrentInstance()
if (!instance?.type || !('head' in instance.type)) { return }
[metaConfig.mixinKey] () {
const options = getCurrentInstance()?.type
if (!options || !('head' in options)) { return }

useMeta((instance.type as any).head)
useMeta(options.head)
}
})

Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/bridge/pages/index.vue
Expand Up @@ -3,11 +3,17 @@
</template>

<script>
import { useMeta } from '#meta'

export default defineComponent({
setup () {
useMeta({ meta: [{ name: 'description', content: 'This is a page to demo Nuxt Bridge.' }] })
return {
version: ref('2')
}
},
head: {
title: 'Bridge test fixture'
}
})
</script>
1 change: 1 addition & 0 deletions yarn.lock
Expand Up @@ -1427,6 +1427,7 @@ __metadata:
"@types/fs-extra": ^9.0.13
"@types/node-fetch": ^3.0.2
"@vue/composition-api": ^1.2.3
"@vueuse/head": ^0.6.0
acorn: ^8.5.0
defu: ^5.0.0
enhanced-resolve: ^5.8.3
Expand Down