Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Replace @vueuse/head with @unhead/vue #804

Merged
merged 11 commits into from
Jun 21, 2023
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 { 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 @@
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 @@

/**
* 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 All @@ -99,7 +154,7 @@
},

/**
* @typeTODO {typeof import('../src/types/meta').AppHeadMetaObject}

Check warning on line 157 in packages/bridge-schema/src/config/app.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest, 16)

Invalid JSDoc tag name "typeTODO"
* @deprecated - use `head` instead
*/
meta: {
Expand All @@ -123,7 +178,6 @@
* 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 @@
* 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 @@
* 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 @@
*
* 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 @@
*
* 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))
harlan-zw marked this conversation as resolved.
Show resolved Hide resolved
},
version
},
Expand Down
Loading
Loading