@nuxtjs/seo 2.0.0-rc.16 → 2.0.0-rc.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -13,6 +13,10 @@ interface ModuleOptions {
13
13
  * @default true
14
14
  */
15
15
  automaticDefaults?: boolean;
16
+ /**
17
+ * When enabled, it will whitelist the query parameters that are allowed in the canonical URL.
18
+ */
19
+ canonicalQueryWhitelist?: string[];
16
20
  /**
17
21
  * When enabled, it will redirect any request to the canonical domain (site url) using a 301 redirect on non-dev environments.
18
22
  *
package/dist/module.d.ts CHANGED
@@ -13,6 +13,10 @@ interface ModuleOptions {
13
13
  * @default true
14
14
  */
15
15
  automaticDefaults?: boolean;
16
+ /**
17
+ * When enabled, it will whitelist the query parameters that are allowed in the canonical URL.
18
+ */
19
+ canonicalQueryWhitelist?: string[];
16
20
  /**
17
21
  * When enabled, it will redirect any request to the canonical domain (site url) using a 301 redirect on non-dev environments.
18
22
  *
package/dist/module.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "bridge": false
6
6
  },
7
7
  "configKey": "seo",
8
- "version": "2.0.0-rc.15",
8
+ "version": "2.0.0-rc.17",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "0.8.1",
11
11
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -44,15 +44,21 @@ const module = defineNuxtModule({
44
44
  await installNuxtSiteConfig();
45
45
  for (const module of Modules)
46
46
  await installModule(await resolvePath(module));
47
+ nuxt.options.runtimeConfig.public["nuxt-seo"] = {
48
+ canonicalQueryWhitelist: config.canonicalQueryWhitelist || [
49
+ "page",
50
+ "sort",
51
+ "filter",
52
+ "search",
53
+ "q",
54
+ "category",
55
+ "tag"
56
+ ]
57
+ };
47
58
  if (config.automaticDefaults) {
48
59
  if (hasNuxtModule("@nuxtjs/i18n")) {
49
60
  addPlugin({
50
- src: resolve(`./runtime/nuxt/plugin/defaultsWaitI18n.server`),
51
- mode: "server"
52
- });
53
- addPlugin({
54
- src: resolve(`./runtime/nuxt/plugin/defaults`),
55
- mode: "client"
61
+ src: resolve(`./runtime/nuxt/plugin/defaultsWaitI18n`)
56
62
  });
57
63
  } else {
58
64
  addPlugin({
@@ -5,6 +5,6 @@ export declare function useI18n(): {
5
5
  t: (_: string, fallback: string) => string;
6
6
  te: (_: string) => boolean;
7
7
  strategy: string;
8
- defaultLocale: import("#imports").Ref<any>;
9
- locale: import("#imports").Ref<any>;
8
+ defaultLocale: import("vue").Ref<any, any>;
9
+ locale: import("vue").Ref<any, any>;
10
10
  };
@@ -82,5 +82,5 @@ export interface BreadcrumbItemProps extends NuxtUIBreadcrumbItem {
82
82
  last: boolean;
83
83
  };
84
84
  }
85
- export declare function useBreadcrumbItems(options?: BreadcrumbProps): import("#imports").ComputedRef<BreadcrumbItemProps[]>;
85
+ export declare function useBreadcrumbItems(options?: BreadcrumbProps): import("vue").ComputedRef<BreadcrumbItemProps[]>;
86
86
  export {};
@@ -1,5 +1,6 @@
1
1
  import { withoutTrailingSlash } from "ufo";
2
2
  import { defu } from "defu";
3
+ import { fixSlashes } from "site-config-stack/urls";
3
4
  import { pathBreadcrumbSegments } from "../../pure/breadcrumbs.js";
4
5
  import {
5
6
  computed,
@@ -10,7 +11,7 @@ import {
10
11
  useRoute,
11
12
  useRouter,
12
13
  useSchemaOrg,
13
- withSiteTrailingSlash
14
+ useSiteConfig
14
15
  } from "#imports";
15
16
  function withoutQuery(path) {
16
17
  return path.split("?")[0];
@@ -26,6 +27,7 @@ export function useBreadcrumbItems(options = {}) {
26
27
  canonical: true,
27
28
  absolute: true
28
29
  });
30
+ const siteConfig = useSiteConfig();
29
31
  const items = computed(() => {
30
32
  let rootNode = "/";
31
33
  if (i18n) {
@@ -74,7 +76,7 @@ export function useBreadcrumbItems(options = {}) {
74
76
  return item;
75
77
  }).map((m) => {
76
78
  if (m && m.to) {
77
- m.to = withSiteTrailingSlash(m.to).value;
79
+ m.to = fixSlashes(siteConfig.trailingSlash, m.to);
78
80
  if (m.to === rootNode && toValue(options.hideRoot))
79
81
  return false;
80
82
  }
@@ -1 +1,4 @@
1
- export declare function applyDefaults(): void;
1
+ import type { Ref } from 'vue';
2
+ export declare function applyDefaults(i18n: {
3
+ locale: Ref<string>;
4
+ }): void;
@@ -1,38 +1,40 @@
1
+ import { stringifyQuery } from "ufo";
1
2
  import {
2
3
  computed,
3
4
  createSitePathResolver,
4
5
  useHead,
5
6
  useRoute,
7
+ useRuntimeConfig,
6
8
  useSeoMeta,
7
- useServerHead,
8
9
  useSiteConfig
9
10
  } from "#imports";
10
- export function applyDefaults() {
11
+ export function applyDefaults(i18n) {
12
+ const { canonicalQueryWhitelist } = useRuntimeConfig().public["nuxt-seo"];
11
13
  const siteConfig = useSiteConfig();
12
14
  const route = useRoute();
13
15
  const resolveUrl = createSitePathResolver({ withBase: true, absolute: true });
14
- const canonicalUrl = computed(() => resolveUrl(route.path || "/").value || route.path);
16
+ const canonicalUrl = computed(() => {
17
+ const { query } = route;
18
+ const url = resolveUrl(route.path || "/").value || route.path;
19
+ const filteredQuery = Object.fromEntries(
20
+ Object.entries(query).filter(([key]) => canonicalQueryWhitelist.includes(key))
21
+ );
22
+ return Object.keys(filteredQuery).length ? `${url}?${stringifyQuery(filteredQuery)}` : url;
23
+ });
15
24
  const minimalPriority = {
16
25
  // give nuxt.config values higher priority
17
26
  tagPriority: 101
18
27
  };
19
28
  useHead({
20
- link: [{ rel: "canonical", href: () => canonicalUrl.value }]
21
- });
22
- const locale = siteConfig.currentLocale || siteConfig.defaultLocale;
23
- if (locale) {
24
- useServerHead({
25
- htmlAttrs: { lang: locale }
26
- });
27
- }
28
- useHead({
29
+ htmlAttrs: { lang: i18n.locale },
29
30
  templateParams: { site: siteConfig, siteName: siteConfig.name || "" },
30
- titleTemplate: "%s %separator %siteName"
31
+ titleTemplate: "%s %separator %siteName",
32
+ link: [{ rel: "canonical", href: () => canonicalUrl.value }]
31
33
  }, minimalPriority);
32
34
  const seoMeta = {
33
35
  ogType: "website",
34
36
  ogUrl: () => canonicalUrl.value,
35
- ogLocale: locale,
37
+ ogLocale: () => i18n.locale.value,
36
38
  ogSiteName: siteConfig.name
37
39
  };
38
40
  if (siteConfig.description)
@@ -1,11 +1,20 @@
1
- import { applyDefaults as setup } from "../logic/applyDefaults.js";
1
+ import { applyDefaults } from "../logic/applyDefaults.js";
2
2
  import {
3
- defineNuxtPlugin
3
+ defineNuxtPlugin,
4
+ ref,
5
+ useSiteConfig
4
6
  } from "#imports";
5
7
  export default defineNuxtPlugin({
6
8
  name: "nuxt-seo:defaults",
9
+ order: 999,
7
10
  env: {
8
11
  islands: false
9
12
  },
10
- setup
13
+ setup() {
14
+ const siteConfig = useSiteConfig();
15
+ const locale = ref(siteConfig.currentLocale || siteConfig.defaultLocale);
16
+ applyDefaults({
17
+ locale
18
+ });
19
+ }
11
20
  });
@@ -0,0 +1,23 @@
1
+ import { applyDefaults } from "../logic/applyDefaults.js";
2
+ import { defineNuxtPlugin, ref, useSiteConfig } from "#imports";
3
+ export default defineNuxtPlugin({
4
+ name: "nuxt-seo:defaults",
5
+ env: {
6
+ islands: false
7
+ },
8
+ // we need to wait for the i18n plugin to run first
9
+ // @ts-expect-error dynamic
10
+ dependsOn: import.meta.server ? [
11
+ "nuxt-site-config:i18n"
12
+ ] : [
13
+ "i18n:plugin"
14
+ ],
15
+ setup(nuxtApp) {
16
+ const siteConfig = useSiteConfig();
17
+ const locale = ref(nuxtApp.$i18n?.locale?.value || siteConfig.currentLocale || siteConfig.defaultLocale);
18
+ nuxtApp.hook("i18n:localeSwitched", ({ newLocale }) => {
19
+ locale.value = newLocale;
20
+ });
21
+ applyDefaults({ locale });
22
+ }
23
+ });
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@nuxtjs/seo",
3
3
  "type": "module",
4
- "version": "2.0.0-rc.16",
4
+ "version": "2.0.0-rc.18",
5
+ "packageManager": "pnpm@9.5.0",
5
6
  "description": "The all-in-one SEO layer for Nuxt 3.",
6
7
  "author": {
7
8
  "name": "Harlan Wilton",
@@ -33,7 +34,7 @@
33
34
  "dependencies": {
34
35
  "@nuxt/kit": "^3.12.3",
35
36
  "@nuxtjs/robots": "^4.0.2",
36
- "@nuxtjs/sitemap": "^5.3.5",
37
+ "@nuxtjs/sitemap": "^6.0.0-beta.1",
37
38
  "defu": "^6.1.4",
38
39
  "nuxt-link-checker": "^3.0.2",
39
40
  "nuxt-og-image": "^3.0.0-rc.64",
@@ -47,15 +48,15 @@
47
48
  "devDependencies": {
48
49
  "@antfu/eslint-config": "^2.23.0",
49
50
  "@nuxt/module-builder": "^0.8.1",
50
- "@nuxt/schema": "^3.12.3",
51
- "@nuxt/test-utils": "3.13.1",
51
+ "@nuxt/schema": "^3.12.4",
52
+ "@nuxt/test-utils": "^3.14.0",
52
53
  "@nuxt/ui": "^2.17.0",
53
- "@nuxtjs/i18n": "^8.3.1",
54
+ "@nuxtjs/i18n": "^8.3.3",
54
55
  "bumpp": "^9.4.1",
55
56
  "eslint": "^9.7.0",
56
57
  "execa": "^9.3.0",
57
58
  "nitropack": "^2.9.7",
58
- "nuxt": "^3.12.3",
59
+ "nuxt": "^3.12.4",
59
60
  "typescript": "5.4.5",
60
61
  "vitest": "^2.0.3"
61
62
  },
@@ -66,6 +67,8 @@
66
67
  ]
67
68
  },
68
69
  "resolutions": {
70
+ "@nuxt/schema": "3.12.3",
71
+ "nuxt": "3.12.3",
69
72
  "shiki": "1.10.1"
70
73
  },
71
74
  "scripts": {
@@ -1,14 +0,0 @@
1
- import { applyDefaults as setup } from "../logic/applyDefaults.js";
2
- import { defineNuxtPlugin } from "#imports";
3
- export default defineNuxtPlugin({
4
- name: "nuxt-seo:defaults",
5
- env: {
6
- islands: false
7
- },
8
- // we need to wait for the i18n plugin to run first
9
- dependsOn: [
10
- // @ts-expect-error dynamic
11
- "nuxt-site-config:i18n"
12
- ],
13
- setup
14
- });