diff --git a/docs/.npmrc b/docs/.npmrc deleted file mode 100644 index bac7fb07..00000000 --- a/docs/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -shamefully-hoist=true -ignore-workspace-root-check=true diff --git a/docs/content/1.setup/4.vue/0.installation.md b/docs/0.angular/1.installation.md similarity index 98% rename from docs/content/1.setup/4.vue/0.installation.md rename to docs/0.angular/1.installation.md index 9709c1a7..c6fbd7f0 100644 --- a/docs/content/1.setup/4.vue/0.installation.md +++ b/docs/0.angular/1.installation.md @@ -1,5 +1,5 @@ --- -title: Install Vue Unhead +title: Installing Unhead with Vue description: Learn how to start using Unhead with Vue. navigation: title: 'Installation' @@ -160,5 +160,6 @@ export default { Your Vue app is now setup for head management, congrats! ๐ Try next: + 1. Optional: [Setup SSR](/setup/ssr/installation) 2. Explore the [Composables](/usage/composables/use-head) diff --git a/docs/0.angular/3.troubleshooting.md b/docs/0.angular/3.troubleshooting.md new file mode 100644 index 00000000..d742f74f --- /dev/null +++ b/docs/0.angular/3.troubleshooting.md @@ -0,0 +1,12 @@ +--- +title: Troubleshooting +description: Learn how Unhead works under the hood. +--- + +Unhead manages the `
`{lang="html"} of your site with support for SSR (Server-Side Rendering) and CSR (Client-Side Rendering). It's split into multiple packages to improve modularization and flexibility, allowing developers to choose and use only the components they actually need. + +The core package is framework-agnostic and should work in any setup. + +Framework packages are provided to improve the DX of using Unhead with the framework. + +Optional packages exist to add extra functionality and optimisations to Unhead. diff --git a/docs/content/1.setup/4.vue/4.how-it-works.md b/docs/0.angular/guides/0.reactivity.md similarity index 69% rename from docs/content/1.setup/4.vue/4.how-it-works.md rename to docs/0.angular/guides/0.reactivity.md index 31e5361d..05e5add9 100644 --- a/docs/content/1.setup/4.vue/4.how-it-works.md +++ b/docs/0.angular/guides/0.reactivity.md @@ -1,13 +1,14 @@ --- -title: How Vue Unhead Works -description: Learn how to use reactivity with Vue Unhead. -navigation: - title: How it works +title: Vue Reactivity +description: Master Vue and Unhead by following the best practices. --- +## How Reactivity Works + When using any of the provided composables, such as `useHead`, full reactivity is provided out of the box. All values are reactive and support: + - ref - computed getter - computed (not recommended) @@ -37,3 +38,27 @@ It's recommended to avoid using `computed`, as you will have simpler and more pe When using reactivity in SSR, only at the time of rendering the SSR tags will be refs be resolved. When using reactivity in CSR, any ref changes will trigger a request to update the DOM. + +## Avoid Watch and useHead + +Avoid wrapping `useHead` in a watcher. + +```ts +// bad +watch((title) => { + useHead({ + title, + }) +}) +``` + +This is because each call of `useHead` will add a new entry, which has its own side effects. + +Instead, use a computed getter. + +```ts +// good +useHead({ + title: () => title +}) +``` diff --git a/docs/content/1.setup/4.vue/1.components.md b/docs/0.angular/guides/1.components.md similarity index 63% rename from docs/content/1.setup/4.vue/1.components.md rename to docs/0.angular/guides/1.components.md index c861fdff..c9193082 100644 --- a/docs/content/1.setup/4.vue/1.components.md +++ b/docs/0.angular/guides/1.components.md @@ -1,16 +1,16 @@ --- -title: Components +title: Component description: Use the component to manage your head tags. navigation: - title: 'Components' + title: ' Component' --- -The Unhead Vue package exports a `` component that can be used to manage your head tags. +The Unhead Vue package exports a ``{lang="html"} component that can be used to manage your head tags. While it's recommended to use the `useHead` composable as it offers a more flexible API with full TypeScript support, -the `` component may make more sense for your project. +the ``{lang="html"} component may make more sense for your project. -The component will takes any child elements that you would normally put in your actual `` and renders them +The component will takes any child elements that you would normally put in your actual ``{lang="html"} and renders them with Unhead. ```vue @@ -24,3 +24,4 @@ import { Head } from '@unhead/vue/components' +``` diff --git a/docs/0.angular/guides/2.managing-context.md b/docs/0.angular/guides/2.managing-context.md new file mode 100644 index 00000000..5e5f67f7 --- /dev/null +++ b/docs/0.angular/guides/2.managing-context.md @@ -0,0 +1,243 @@ +--- +title: Understanding Async Context and useHead() +description: Manage head tags with useHead() in Vue across async operations, component lifecycles, and server-side rendering. +navigation: + title: 'Async Context' +--- + +## Introduction + +This injection pattern is fundamental to how Vue manages component state and dependencies in the Composition API. + +When we call `useHead()`{lang="ts"}, behind the scenes, it's calling the Vue [inject](https://vuejs.org/api/composition-api-dependency-injection.html#inject) function to get the Unhead instance +attached to the Vue instance. + +```ts +import { inject } from 'vue' + +function useHead(input) { + const head = inject(HEAD_KEY) + head.push(input) +} + +function injectHead() { + return inject(HEAD_KEY) +} +``` + +The `inject()`{lang="ts"} function keeps track of your Vue component instance, however, after async operations within lifecycle hooks or nested functions, Vue loses track of this context. + +```vue + +``` + +When trying to inject once Vue has lost the context, you'll receive an error from Unhead: + +> useHead() was called without provide context. + +We'll look at how we can prevent this error and ensure our head updates work correctly across async operations. + +## Use Top Level Await + +Vue's script setup handles async operations through [compile-time transforms](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md#top-level-await) that preserve the component instance context. As explained in Anthony's [article on async composition](https://antfu.me/posts/async-with-composition-api), this makes most async operations work seamlessly. + +At the top level of script setup, context is automatically preserved: + +```vue + +``` + +This is the simplest and most effective way to handle async operations in Vue. + +## Using `effectScope()`{lang="ts"} + +The `effectScope()`{lang="ts"} API allows you to re-run a code block using the same component context, making it ideal for solving +the async context loss issue. + +```vue + +``` + +## Using `injectHead()`{lang="ts"} + +The `injectHead()` function lets us grab a reference to Unhead's instance before any async operations occur. + +Here's how to use it effectively: + +```vue + +``` + +The key idea is that `injectHead()`{lang="ts"} should be called at the top level of your component, before any async operations. This ensures you have a stable reference to use throughout your component's lifecycle. + +## Using Reactive State + +A more elegant way to handle async head updates is to combine reactive state with useHead. This approach lets you define your head configuration once and have it automatically update as your data changes: + +```vue + +``` + +### Pinia Store + +You can also use this pattern with more complex state management: + +```vue + +``` + +This reactive state pattern aligns well with Vue's composition API design and often results in cleaner, more maintainable code than manually updating the head after each async operation. + +## Async Context in Nuxt + +When using Nuxt, you don't need to worry about managing async context for head updates. This is because Nuxt attaches Unhead directly to the Nuxt application instance which is globally accessible regardless of the async operation. + +This decision allows you to use `useHead()`{lang="ts"} anywhere, including plugins, middleware and layouts without worrying about context. + +## Learn More + +The Vue team's solution for async context through script setup transforms is quite elegant. You can read more about the technical implementation in the [Script Setup RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md#top-level-await). For a deeper understanding of how async context evolved in Vue's Composition API, check out Anthony Fu's [detailed exploration](https://antfu.me/posts/async-with-composition-api) of the topic. diff --git a/docs/0.introduction.md b/docs/0.introduction.md new file mode 100644 index 00000000..e5e49354 --- /dev/null +++ b/docs/0.introduction.md @@ -0,0 +1,55 @@ +--- +title: "Unhead: Full Stack Head Manager" +description: Learn how Unhead can help you manage the head of your document in both server and client-rendered environments. +navigation: + title: Introduction +--- + +## What is head manager? + +Setting tags in your ``{lang="html"} is one of the fundamental tasks in web development. Whether it be setting a page title using `- Unhead needs you! -
-- By allowing unhead.unjs.io on your Ad-Blocker, you support our work and help us financially. -
-- Prop - | -- Default - | -Description | -
---|---|---|
- {{ prop.name }} *
- |
-
- {{ prop.default }}
- |
-
-
- {{ prop.type }}
-
-
- {{ prop.type }}
-
- |
-
Slot | -
---|
- {{ slot.name }}
- |
-
- {{ group.title }} -
-- {{ group2.title }} -
-- {{ page._dir?.title ? page._dir.title : useLowerCase(page._dir) }} -
-- {{ page.description }} -
-- {{ title }} -
- -- {{ description }} -
-- {{ siteConfig.description }} -
- -