Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export default defineNuxtConfig({
})
```

This `useHead` composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`.
This `useHead` composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`.
Accordingly, we recommend not to use both the native Nuxt 2 `head()` properties as well as `useHead`, as they may conflict.

For more information on how to use this composable, see [the docs](https://nuxt.com/docs/getting-started/seo-meta#seo-and-meta).
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-schema/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export default defineBuildConfig({
'vue-meta',
'vue-router',
'vue-bundle-renderer',
'@vueuse/head',
'vue',
'hookable',
'nitropack',
Expand All @@ -57,6 +56,7 @@ export default defineBuildConfig({
'postcss',
'consola',
'ignore',
'@unhead/schema',
// Implicit
'@vue/compiler-core',
'@vue/shared',
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"devDependencies": {
"@types/lodash.template": "^4.5.1",
"@types/semver": "^7.5.0",
"@vueuse/head": "^1.1.26",
"@unhead/schema": "^1.1.27",
"nitropack": "^2.4.1",
"unbuild": "latest",
"vite": "~4.3.9"
Expand Down
70 changes: 60 additions & 10 deletions packages/bridge-schema/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { existsSync, readdirSync } from 'node:fs'
import { defineUntypedSchema } from 'untyped'
import { resolve, join } from 'pathe'
import defu from 'defu'
import { AppHeadMetaObject } from '../types/head'

export default defineUntypedSchema({
vue: {
/**
* Properties that will be set directly on `Vue.config` for vue@2.
*
* @see [vue@2 Documentation](https://v2.vuejs.org/v2/api/#Global-Config)
* @type {typeof import('vue/types/vue').VueConfiguration}
*/
Expand All @@ -24,18 +24,75 @@ export default defineUntypedSchema({
app: {
/**
* The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set).
*
* @deprecated - use `buildAssetsDir` instead
*/
assetsPath: {
$resolve: async (val, get) => val ?? (await get('buildAssetsDir'))
},
/**
* Set default configuration for `<head>` on every page.
* @example
* ```js
* app: {
* head: {
* meta: [
* // <meta name="viewport" content="width=device-width, initial-scale=1">
* { name: 'viewport', content: 'width=device-width, initial-scale=1' }
* ],
* script: [
* // <script src="https://myawesome-lib.js"></script>
* { src: 'https://awesome-lib.js' }
* ],
* link: [
* // <link rel="stylesheet" href="https://myawesome-lib.css">
* { rel: 'stylesheet', href: 'https://awesome-lib.css' }
* ],
* // please note that this is an area that is likely to change
* style: [
* // <style type="text/css">:root { color: red }</style>
* { children: ':root { color: red }', type: 'text/css' }
* ],
* noscript: [
* // <noscript>JavaScript is required</noscript>
* { children: 'JavaScript is required' }
* ]
* }
* }
* ```
* @type {typeof import('../src/types/head').AppHeadMetaObject}
*/
head: {
$resolve: async (val, get) => {
const resolved: Required<AppHeadMetaObject> = defu(val, await get('meta'), {
meta: [],
link: [],
style: [],
script: [],
noscript: []
})

// provides default charset and viewport if not set
if (!resolved.meta.find(m => m.charset)?.charset) {
resolved.meta.unshift({ charset: resolved.charset || 'utf-8' })
}
if (!resolved.meta.find(m => m.name === 'viewport')?.content) {
resolved.meta.unshift({ name: 'viewport', content: resolved.viewport || 'width=device-width, initial-scale=1' })
}

resolved.meta = resolved.meta.filter(Boolean)
resolved.link = resolved.link.filter(Boolean)
resolved.style = resolved.style.filter(Boolean)
resolved.script = resolved.script.filter(Boolean)
resolved.noscript = resolved.noscript.filter(Boolean)

return resolved
}
}
},

/**
* The path to an HTML template file for rendering Nuxt responses.
* Uses `<srcDir>/app.html` if it exists, or the Nuxt's default template if not.
*
* @example
* ```html
* <!DOCTYPE html>
Expand Down Expand Up @@ -75,15 +132,13 @@ export default defineUntypedSchema({

/**
* Options to pass directly to `vue-meta`.
*
* @see [documentation](https://vue-meta.nuxtjs.org/api/#plugin-options).
* @type {typeof import('vue-meta').VueMetaOptions}
*/
vueMeta: null,

/**
* Set default configuration for `<head>` on every page.
*
* @see [documentation](https://vue-meta.nuxtjs.org/api/#metainfo-properties) for specifics.
* @type {typeof import('vue-meta').MetaInfo}
*/
Expand Down Expand Up @@ -123,7 +178,6 @@ export default defineUntypedSchema({
* You may want to extend plugins or change their order. For this, you can pass
* a function using `extendPlugins`. It accepts an array of plugin objects and
* should return an array of plugin objects.
*
* @type {(plugins: Array<{ src: string, mode?: 'client' | 'server' }>) => Array<{ src: string, mode?: 'client' | 'server' }>}
*/
extendPlugins: null,
Expand All @@ -132,7 +186,6 @@ export default defineUntypedSchema({
* An object where each key name maps to a path to a layout .vue file.
*
* Normally, there is no need to configure this directly.
*
* @type {Record<string, string>}
*/
layouts: {},
Expand All @@ -141,7 +194,6 @@ export default defineUntypedSchema({
* Set a custom error page layout.
*
* Normally, there is no need to configure this directly.
*
* @type {string}
*/
ErrorPage: null,
Expand Down Expand Up @@ -206,7 +258,6 @@ export default defineUntypedSchema({
*
* You can either pass a string (the transition name) or an object with properties to bind
* to the `<Transition>` component that will wrap your pages.
*
* @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html)
* @see [vue@3 documentation](https://vuejs.org/guide/built-ins/transition-group.html#enter-leave-transitions)
*/
Expand All @@ -229,7 +280,6 @@ export default defineUntypedSchema({
*
* You can either pass a string (the transition name) or an object with properties to bind
* to the `<Transition>` component that will wrap your layouts.
*
* @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html)
*/
layoutTransition: {
Expand Down
31 changes: 31 additions & 0 deletions packages/bridge-schema/src/types/head.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Head, MergeHead } from '@unhead/schema'

/** @deprecated Extend types from `@unhead/schema` directly. This may be removed in a future minor version. */
export interface HeadAugmentations extends MergeHead {
// runtime type modifications
base?: {}
link?: {}
meta?: {}
style?: {}
script?: {}
noscript?: {}
htmlAttrs?: {}
bodyAttrs?: {}
}

export type MetaObjectRaw = Head<HeadAugmentations>
export type MetaObject = MetaObjectRaw

export type AppHeadMetaObject = MetaObjectRaw & {
/**
* The character encoding in which the document is encoded => `<meta charset="<value>" />`
* @default `'utf-8'`
*/
charset?: string
/**
* Configuration of the viewport (the area of the window in which web content can be seen),
* mapped to => `<meta name="viewport" content="<value>" />`
* @default `'width=device-width, initial-scale=1'`
*/
viewport?: string
}
3 changes: 2 additions & 1 deletion packages/bridge/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineBuildConfig({
'webpack',
'vite',
'vue',
'vue-meta'
'vue-meta',
'@unhead/vue'
]
})
3 changes: 2 additions & 1 deletion packages/bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"@nuxt/postcss8": "^1.1.3",
"@nuxt/schema": "3.5.3",
"@nuxt/ui-templates": "^1.2.0",
"@unhead/ssr": "^1.1.27",
"@unhead/vue": "^1.1.27",
"@vitejs/plugin-legacy": "^4.0.4",
"@vitejs/plugin-vue2": "^2.2.0",
"acorn": "^8.9.0",
Expand Down Expand Up @@ -79,7 +81,6 @@
"@types/fs-extra": "^9.0.13",
"@types/hash-sum": "^1.0.0",
"@types/node-fetch": "^3.0.2",
"@vueuse/head": "^1.1.26",
"nuxt": "^2.17.0",
"unbuild": "1.2.1",
"vue": "^2.7.14",
Expand Down
41 changes: 33 additions & 8 deletions packages/bridge/src/head.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { resolve } from 'pathe'
import { addPlugin, addTemplate, defineNuxtModule, tryResolveModule } from '@nuxt/kit'
import { addComponent, addImportsSources, addPlugin, addTemplate, defineNuxtModule } from '@nuxt/kit'
import { defu } from 'defu'
import type { MetaObject } from '@nuxt/schema'
import { distDir } from './dirs'

const components = ['NoScript', 'Link', 'Base', 'Title', 'Meta', 'Style', 'Head', 'Html', 'Body']

export default defineNuxtModule({
meta: {
name: 'meta'
Expand All @@ -15,13 +17,26 @@ export default defineNuxtModule({
setup (options, nuxt) {
const runtimeDir = nuxt.options.alias['#head'] || resolve(distDir, 'head/runtime')

// Transpile @nuxt/meta and @vueuse/head
nuxt.options.build.transpile.push('@vueuse/head')
// Transpile @unhead/vue and @unhead/ssr
nuxt.options.build.transpile.push('unhead')

// Add #head alias
nuxt.options.alias['#head'] = runtimeDir

// Register components
const componentsPath = resolve(runtimeDir, 'components')
for (const componentName of components) {
addComponent({
name: componentName,
filePath: componentsPath,
export: componentName,
// built-in that we do not expect the user to override
priority: 10,
// kebab case version of these tags is not valid
kebabName: componentName
})
}

// Global meta -for Bridge, this is necessary to repeat here
// and in packages/schema/src/config/_app.ts
const globalMeta: MetaObject = defu(nuxt.options.app.head, {
Expand All @@ -35,14 +50,24 @@ export default defineNuxtModule({
getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' })
})

if (!tryResolveModule('@vueuse/head')) {
console.warn('[bridge] Could not find `@vueuse/head`. You may need to install it.')
}
addImportsSources({
from: '@unhead/vue',
// hard-coded for now we so don't support auto-imports on the deprecated composables
imports: [
'injectHead',
'useHead',
'useSeoMeta',
'useHeadSafe',
'useServerHead',
'useServerSeoMeta',
'useServerHeadSafe'
]
})

// Add generic plugin
addPlugin({ src: resolve(runtimeDir, 'plugin') })

// Add library specific plugin
addPlugin({ src: resolve(runtimeDir, 'vueuse-head.plugin') })
// Add library-specific plugin
addPlugin({ src: resolve(runtimeDir, 'plugins/unhead') })
}
})
1 change: 0 additions & 1 deletion packages/bridge/src/imports/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const commonPresets: InlinePreset[] = [
defineUnimportPreset({
from: '#head',
imports: [
'useHead',
'useMeta'
]
}),
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge/src/runtime/app.plugin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default async (ctx, inject) => {
provide: inject,
unmount: () => { },
use (vuePlugin) {
runOnceWith(vuePlugin, () => vuePlugin.install(this))
runOnceWith(vuePlugin, () => Vue.use(vuePlugin))
Comment thread
harlan-zw marked this conversation as resolved.
},
version
},
Expand Down
Loading