Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unjs/unhead
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.0.0-rc.9
Choose a base ref
...
head repository: unjs/unhead
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.0.0-rc.10
Choose a head ref
  • 14 commits
  • 26 files changed
  • 3 contributors

Commits on Mar 8, 2025

  1. chore: missing test

    harlan-zw committed Mar 8, 2025
    Copy the full SHA
    c795edc View commit details

Commits on Mar 10, 2025

  1. doc: fix typo in import statement on Template Params page

    Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
    Roman3349 committed Mar 10, 2025
    Copy the full SHA
    e206b0a View commit details

Commits on Mar 11, 2025

  1. fix(vue): broken reactivity

    harlan-zw committed Mar 11, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    Zuoqiu-Yingyi Yingyi / 颖逸
    Copy the full SHA
    a255df0 View commit details
  2. chore: lint

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    5b55b25 View commit details
  3. fix(addons): implicit peer dependencies

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    48e81b2 View commit details
  4. chore: update bundle stats [skip ci]

    github-actions[bot] committed Mar 11, 2025
    Copy the full SHA
    6a50e40 View commit details
  5. Merge pull request #518 from Roman3349/fix/typo/docs-plugin-template-…

    …params
    
    doc: fix typo in import statement on Template Params page
    harlan-zw authored Mar 11, 2025
    Copy the full SHA
    38547f3 View commit details
  6. chore: broken test

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    9fe253e View commit details
  7. Merge remote-tracking branch 'origin/main'

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    d55a91e View commit details
  8. chore: update bundle stats [skip ci]

    github-actions[bot] committed Mar 11, 2025
    Copy the full SHA
    2dc840f View commit details
  9. chore: broken build

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    01796a4 View commit details
  10. Merge remote-tracking branch 'origin/main'

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    768d2d1 View commit details
  11. chore: broken types

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    abce0ff View commit details
  12. chore: release v2.0.0-rc.10

    harlan-zw committed Mar 11, 2025
    Copy the full SHA
    9d837c2 View commit details
8 changes: 4 additions & 4 deletions bench/bundle/last.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"client": {
"size": 11030,
"gz": 4593
"size": 10978,
"gz": 4574
},
"server": {
"size": 8242,
"gz": 3467
"size": 8181,
"gz": 3448
}
}
2 changes: 1 addition & 1 deletion docs/plugins/6.template-params.md
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ First, add the plugin to your Unhead configuration:

::code-block
```ts [Input]
import { TemplateParamsPlugin } from '@unhead/plugins'
import { TemplateParamsPlugin } from 'unhead/plugins'
import { createHead } from 'unhead'

const head = createHead({
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "unhead-monorepo",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"private": "true",
"packageManager": "pnpm@10.5.2",
"author": "Harlan Wilton <harlan@harlanzw.com>",
@@ -28,8 +28,8 @@
"twoslash:verify": "nuxt-content-twoslash verify --content-dir docs"
},
"devDependencies": {
"@arethetypeswrong/cli": "0.17.4",
"@antfu/eslint-config": "^4.5.1",
"@arethetypeswrong/cli": "0.17.4",
"@types/fs-extra": "^11.0.4",
"@types/jsdom": "^21.1.7",
"acorn-loose": "^8.4.0",
3 changes: 3 additions & 0 deletions packages/addons/build.config.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,9 @@ export default defineBuildConfig({
'vite',
'webpack',
'rollup',
'unhead',
'unplugin',
'unhead/plugins',
'unhead/utils'
],
})
9 changes: 3 additions & 6 deletions packages/addons/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/addons",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/harlan-zw",
@@ -47,17 +47,14 @@
}
},
"files": [
"dist",
"*.d.ts"
"*.d.ts",
"dist"
],
"scripts": {
"build": "unbuild",
"stub": "unbuild --stub",
"test:attw": "attw --pack"
},
"peerDependencies": {
"unhead": "workspace:*"
},
"dependencies": {
"@rollup/pluginutils": "^5.1.4",
"estree-walker": "^3.0.3",
1 change: 0 additions & 1 deletion packages/addons/vite.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

export * from './dist/client'
2 changes: 1 addition & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/angular",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"description": "Full-stack <head> manager built for Angular.",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/react",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/harlan-zw",
7 changes: 7 additions & 0 deletions packages/schema-org/build.config.ts
Original file line number Diff line number Diff line change
@@ -25,5 +25,12 @@ export default defineBuildConfig({
'unplugin-vue-components',
'vue',
'@vue/runtime-core',
'@unhead/react',
'@unhead/solid-js',
'@unhead/svelte',
'@unhead/vue',
'unhead',
'unhead/utils',
'unhead/plugins',
],
})
23 changes: 1 addition & 22 deletions packages/schema-org/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/schema-org",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"description": "Unhead Schema.org for Simple and Automated Google Rich Results",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
@@ -76,27 +76,6 @@
"lint": "eslint \"{src,test}/**/*.{ts,vue,json,yml}\" --fix",
"test:attw": "attw --pack"
},
"peerDependencies": {
"@unhead/react": "^2",
"@unhead/solid-js": "^2",
"@unhead/svelte": "^2",
"@unhead/vue": "^2",
"unhead": "^2"
},
"peerDependenciesMeta": {
"@unhead/react": {
"optional": true
},
"@unhead/solid-js": {
"optional": true
},
"@unhead/svelte": {
"optional": true
},
"@unhead/vue": {
"optional": true
}
},
"dependencies": {
"defu": "^6.1.4",
"ohash": "^2.0.10",
72 changes: 71 additions & 1 deletion packages/schema-org/test/vue/vue.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { defineArticle, defineWebPage, useSchemaOrg } from '@unhead/schema-org/vue'
import { defineArticle, defineWebPage, defineWebSite, useSchemaOrg } from '@unhead/schema-org/vue'
import { useHead } from '@unhead/vue'
import { createHead as createClientHead, renderDOMHead } from '@unhead/vue/client'
import { renderSSRHead } from '@unhead/vue/server'
import { describe, expect, it } from 'vitest'
import { computed, ref } from 'vue'
import { useDom } from '../../../unhead/test/fixtures'
import { createHead as createServerHead } from '../../../vue/src/server'
import { ssrVueAppWithUnhead } from '../../../vue/test/util'

describe('schema.org e2e', () => {
@@ -150,4 +152,72 @@ describe('schema.org e2e', () => {
}
`)
})
it('ref simple', async () => {
const head = createServerHead({
disableDefaults: true,
})
useSchemaOrg([
defineWebSite(ref({
name: 'Test',
})),
], { head })

const data = await renderSSRHead(head)
expect(data.bodyTags).toMatchInlineSnapshot(`
"<script type="application/ld+json" data-hid="schema-org-graph">{
"@context": "https://schema.org",
"@graph": [
{
"@id": "#/schema//d006e97",
"name": "Test"
}
]
}</script>"
`)
})

it('refs', async () => {
const head = createServerHead({
disableDefaults: true,
init: [
{
templateParams: {
// @ts-expect-error untyped
schemaOrg: computed(() => {
return {
inLanguage: ref('foo'),
}
}),
},
},
],
})
useSchemaOrg([
defineWebPage(computed(() => ({
name: ref('test'),
foo: computed(() => 'bar'),
}))),
defineWebSite(ref({
name: 'Test',
})),
], { head })

const data = await renderSSRHead(head)
expect(data.bodyTags).toMatchInlineSnapshot(`
"<script type="application/ld+json" data-hid="schema-org-graph">{
"@context": "https://schema.org",
"@graph": [
{
"@id": "#/schema//6b94a87",
"foo": "bar",
"name": "test"
},
{
"@id": "#/schema//d006e97",
"name": "Test"
}
]
}</script>"
`)
})
})
2 changes: 1 addition & 1 deletion packages/solid-js/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/solid-js",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/harlan-zw",
2 changes: 1 addition & 1 deletion packages/svelte/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/svelte",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/harlan-zw",
2 changes: 1 addition & 1 deletion packages/unhead/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "unhead",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"description": "Full-stack <head> manager built for any framework.",
"author": {
"name": "Harlan Wilton",
2 changes: 1 addition & 1 deletion packages/unhead/src/scripts/useScript.ts
Original file line number Diff line number Diff line change
@@ -145,7 +145,7 @@ export function useScript<T extends Record<symbol | string, any> = Record<symbol
href,
rel,
crossorigin: typeof input.crossorigin !== 'undefined' ? input.crossorigin : (isCrossOrigin ? 'anonymous' : undefined),
referrerpolicy: typeof input.referrerpolicy !== 'undefined' ? input.referrerpolicy : (isCrossOrigin ? 'no-referrer' : undefined),
referrerpolicy: typeof input.referrerpolicy !== 'undefined' ? input.referrerpolicy : (isCrossOrigin ? 'no-referrer' : undefined),
fetchpriority: typeof input.fetchpriority !== 'undefined' ? input.fetchpriority : 'low',
integrity: input.integrity,
as: rel === 'preload' ? 'script' : undefined,
1 change: 1 addition & 0 deletions packages/unhead/src/server/createHead.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ export function createHead<T = ResolvableHead>(options: CreateServerHeadOptions
if (k && k.startsWith('on') && typeof v === 'function') {
return `this.dataset.${k}fired = true`
}
return v
},
],
init: [
2 changes: 1 addition & 1 deletion packages/unhead/src/types/head.ts
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ export interface ActiveHeadEntry<Input> {
_poll: (rm?: boolean) => void
}

export type PropResolver = (key: string, value: any, tag?: HeadTag) => any
export type PropResolver = (key?: string, value?: any, tag?: HeadTag) => any

export interface CreateHeadOptions {
document?: Document
24 changes: 11 additions & 13 deletions packages/unhead/src/utils/normalize.ts
Original file line number Diff line number Diff line change
@@ -112,7 +112,6 @@ function normalizeTag(tagName: HeadTag['tag'], _input: HeadTag['props'] | string
: { [(tagName === 'script' || tagName === 'noscript' || tagName === 'style') ? 'innerHTML' : 'textContent']: _input }

const tag = normalizeProps({ tag: tagName, props: {} }, input)

if (tag.key && DupeableTags.has(tag.tag)) {
tag.props['data-hid'] = tag._h = tag.key
}
@@ -131,22 +130,21 @@ export function normalizeEntryToTags(input: any, propResolvers: PropResolver[]):
if (!input) {
return []
}

const tags: (HeadTag | HeadTag[])[] = []

if (typeof input === 'function') {
return normalizeEntryToTags(input(), propResolvers)
input = input()
}
input = walkResolver(input, (key, val) => {
let res = val
const resolvers = (key?: string, val?: any) => {
for (let i = 0; i < propResolvers.length; i++) {
const v = propResolvers[i](key, res)
if (v !== undefined)
res = v
val = propResolvers[i](key, val)
}
return res
})
Object.entries(input).forEach(([key, value]) => {
return val
}
input = resolvers(undefined, input)

const tags: (HeadTag | HeadTag[])[] = []

input = walkResolver(input, resolvers)
Object.entries(input || {}).forEach(([key, value]) => {
if (value === undefined)
return
for (const v of (Array.isArray(value) ? value : [value]))
13 changes: 6 additions & 7 deletions packages/unhead/src/utils/walkResolver.ts
Original file line number Diff line number Diff line change
@@ -4,16 +4,15 @@ export function walkResolver(val: any, resolve?: PropResolver, key?: string): an
// Combined primitive type check
const type = typeof val

let v: any
if (!resolve || !key) {
v = type === 'function' ? val() : val
if (type === 'function') {
if (!key || (key !== 'titleTemplate' && !(key[0] === 'o' && key[1] === 'n'))) {
val = val()
}
}
else if (resolve && (key === 'titleTemplate' || (key[0] === 'o' && key[1] === 'n'))) {
let v: any
if (resolve) {
v = resolve(key, val)
}
else if (resolve) {
v = type === 'function' ? resolve(key, val()) : resolve(key, val)
}

if (Array.isArray(v)) {
return v.map(r => walkResolver(r, resolve))
2 changes: 1 addition & 1 deletion packages/unhead/test/fixtures.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import { JSDOM } from 'jsdom'
export function useDom(payload?: Partial<SSRHeadPayload>, extra?: Partial<SSRHeadPayload>) {
if (typeof window !== 'undefined') {
// reset all window.document.documentElement attributes
window.document.documentElement.getAttributeNames().forEach(name => {
window.document.documentElement.getAttributeNames().forEach((name) => {
window.document.documentElement.removeAttribute(name)
})
// just apply the below to the current document
7 changes: 6 additions & 1 deletion packages/unhead/test/unit/server/util.test.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,12 @@ describe('propsToString', () => {
})).toStrictEqual(' a="b"')
expect(propsToString({})).toStrictEqual('')
})

it ('class / style strings', () => {
expect(propsToString({
class: 'a b',
style: 'color: red; font-size: 12px',
})).toStrictEqual(' class="a b" style="color: red; font-size: 12px"')
})
it('stringifies all properties correctly', async () => {
expect(propsToString({
'array': ['a', 1],
2 changes: 1 addition & 1 deletion packages/vue/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@unhead/vue",
"type": "module",
"version": "2.0.0-rc.9",
"version": "2.0.0-rc.10",
"description": "Full-stack <head> manager built for Vue.",
"author": "Harlan Wilton <harlan@harlanzw.com>",
"license": "MIT",
22 changes: 22 additions & 0 deletions packages/vue/test/unit/ssr/examples.test.ts
Original file line number Diff line number Diff line change
@@ -147,4 +147,26 @@ describe('vue ssr examples', () => {
}
`)
})
it('https://github.com/vite-pwa/vite-plugin-pwa/discussions/832', async () => {
const head = await ssrVueAppWithUnhead(() => {
useHead(ref({
link: [
{
rel: 'manifest',
href: '/manifest.webmanifest',
},
],
}))
})
const ctx = await renderSSRHead(head)
expect(ctx).toMatchInlineSnapshot(`
{
"bodyAttrs": "",
"bodyTags": "",
"bodyTagsOpen": "",
"headTags": "<link rel="manifest" href="/manifest.webmanifest">",
"htmlAttrs": "",
}
`)
})
})
2 changes: 1 addition & 1 deletion packages/vue/test/unit/useScript.test.ts
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@ import { renderSSRHead } from '@unhead/vue/server'
import { describe, it } from 'vitest'
import { ref, watch } from 'vue'
import { useDom } from '../../../unhead/test/util'
import { useScript } from '../../src/scripts/useScript'
import { createHeadCore } from '../../src'
import { useScript } from '../../src/scripts/useScript'

describe('vue e2e scripts', () => {
it('multiple active promise handles', async () => {
4 changes: 2 additions & 2 deletions packages/vue/test/util.ts
Original file line number Diff line number Diff line change
@@ -30,14 +30,14 @@ export function csrVueAppWithUnhead(dom: JSDOM, fn: () => void | Promise<void>,
return head
}

export async function ssrVueAppWithUnhead(fn: () => void | Promise<void>, options?: CreateHeadOptions) {
export async function ssrVueAppWithUnhead(fn: (head: ReturnType<typeof createServerHead>) => void | Promise<void>, options?: CreateHeadOptions) {
const head = createServerHead({
disableDefaults: true,
...options,
})
const app = createSSRApp({
async setup() {
fn()
fn(head)
return () => '<div>hi</div>'
},
})
21 changes: 9 additions & 12 deletions pnpm-lock.yaml