nuxt-seo-utils 7.0.18 → 8.0.1
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/README.md +9 -2
- package/bin/nuxt-seo-utils.mjs +2 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.mjs +118 -0
- package/dist/module.d.mts +25 -0
- package/dist/module.d.ts +140 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +229 -18
- package/dist/runtime/app/composables/polyfills.d.ts +4 -3
- package/dist/runtime/app/composables/polyfills.js +1 -2
- package/dist/runtime/app/composables/useBreadcrumbItems.d.ts +2 -2
- package/dist/runtime/app/composables/useBreadcrumbItems.js +7 -7
- package/dist/runtime/app/composables/useFallbackTitle.d.ts +1 -0
- package/dist/runtime/app/composables/useFallbackTitle.js +31 -0
- package/dist/runtime/app/composables/useShareLinks.d.ts +78 -0
- package/dist/runtime/app/composables/useShareLinks.js +94 -0
- package/dist/runtime/app/logic/applyDefaults.js +10 -6
- package/dist/runtime/app/plugins/0.routeRules.js +10 -5
- package/dist/runtime/app/plugins/1.absoluteImageUrls.server.js +1 -1
- package/dist/runtime/app/plugins/inferSeoMetaPlugin.js +1 -1
- package/dist/runtime/app/plugins/minifyScripts.server.d.ts +2 -0
- package/dist/runtime/app/plugins/minifyScripts.server.js +52 -0
- package/dist/runtime/app/plugins/siteConfig.js +4 -3
- package/dist/runtime/app/plugins/titles.js +6 -17
- package/dist/runtime/server/middleware/redirectCanonical.js +2 -2
- package/dist/runtime/server/routes/__nuxt-seo-utils/debug.d.ts +6 -0
- package/dist/runtime/server/routes/__nuxt-seo-utils/debug.js +10 -0
- package/dist/runtime/shared/minify.d.ts +14 -0
- package/dist/runtime/shared/minify.js +133 -0
- package/package.json +75 -40
- package/dist/runtime/server/tsconfig.json +0 -3
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ While there are several features covering many aspects of SEO, it covers importa
|
|
|
29
29
|
- 🧩 Site config template params `useHead({ title: '%site.title' })`
|
|
30
30
|
- 🍞 Breadcrumb composable
|
|
31
31
|
- 🧙 Best practice defaults and enhanced titles
|
|
32
|
+
- ⚡ Inline minification of `<script>` and `<style>` tags (esbuild + lightningcss at build, lightweight runtime fallback)
|
|
32
33
|
|
|
33
34
|
## Installation
|
|
34
35
|
|
|
@@ -38,11 +39,17 @@ Install `nuxt-seo-utils` dependency to your project:
|
|
|
38
39
|
npx nuxi@latest module add nuxt-seo-utils
|
|
39
40
|
```
|
|
40
41
|
|
|
42
|
+
> [!TIP]
|
|
43
|
+
> Generate an Agent Skill for this package using [skilld](https://github.com/harlan-zw/skilld):
|
|
44
|
+
> ```bash
|
|
45
|
+
> npx skilld add nuxt-seo-utils
|
|
46
|
+
> ```
|
|
47
|
+
|
|
41
48
|
💡 Need a complete SEO solution for Nuxt? Check out [Nuxt SEO](https://nuxtseo.com).
|
|
42
49
|
|
|
43
50
|
## Documentation
|
|
44
51
|
|
|
45
|
-
[📖 Read the full documentation](https://nuxtseo.com/docs/utils) for more information.
|
|
52
|
+
[📖 Read the full documentation](https://nuxtseo.com/docs/seo-utils) for more information.
|
|
46
53
|
|
|
47
54
|
## Demos
|
|
48
55
|
|
|
@@ -70,5 +77,5 @@ Licensed under the [MIT license](https://github.com/harlan-zw/nuxt-seo-utils/blo
|
|
|
70
77
|
[license-src]: https://img.shields.io/github/license/harlan-zw/nuxt-seo-utils.svg?style=flat&colorA=18181B&colorB=28CF8D
|
|
71
78
|
[license-href]: https://github.com/harlan-zw/nuxt-seo-utils/blob/main/LICENSE.md
|
|
72
79
|
|
|
73
|
-
[nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt
|
|
80
|
+
[nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt
|
|
74
81
|
[nuxt-href]: https://nuxt.com
|
package/dist/cli.d.mts
ADDED
package/dist/cli.d.ts
ADDED
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
import { loadNuxtConfig } from '@nuxt/kit';
|
|
6
|
+
import { defineCommand, runMain } from 'citty';
|
|
7
|
+
import { colors } from 'consola/utils';
|
|
8
|
+
import { resolve } from 'pathe';
|
|
9
|
+
|
|
10
|
+
const name = "nuxt-seo-utils";
|
|
11
|
+
const version = "8.0.1";
|
|
12
|
+
const description = "SEO utilities to improve your Nuxt sites discoverability and shareability";
|
|
13
|
+
|
|
14
|
+
const ICON_SIZES = [
|
|
15
|
+
{ name: "icon-16x16.png", width: 16, height: 16 },
|
|
16
|
+
{ name: "icon-32x32.png", width: 32, height: 32 },
|
|
17
|
+
{ name: "apple-touch-icon.png", width: 180, height: 180 },
|
|
18
|
+
{ name: "icon-192x192.png", width: 192, height: 192 },
|
|
19
|
+
{ name: "icon-512x512.png", width: 512, height: 512 }
|
|
20
|
+
];
|
|
21
|
+
const SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["svg", "png", "jpg", "jpeg", "webp"]);
|
|
22
|
+
const cwdArgs = {
|
|
23
|
+
cwd: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Specify the working directory",
|
|
26
|
+
valueHint: "directory",
|
|
27
|
+
default: "."
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function pngToIco(pngBuffers) {
|
|
31
|
+
const count = pngBuffers.length;
|
|
32
|
+
const headerSize = 6;
|
|
33
|
+
const dirEntrySize = 16;
|
|
34
|
+
const dataOffset = headerSize + dirEntrySize * count;
|
|
35
|
+
const header = Buffer.alloc(headerSize);
|
|
36
|
+
header.writeUInt16LE(0, 0);
|
|
37
|
+
header.writeUInt16LE(1, 2);
|
|
38
|
+
header.writeUInt16LE(count, 4);
|
|
39
|
+
const dirEntries = [];
|
|
40
|
+
let offset = dataOffset;
|
|
41
|
+
for (const png of pngBuffers) {
|
|
42
|
+
const entry = Buffer.alloc(dirEntrySize);
|
|
43
|
+
const size = Math.min(256, 32);
|
|
44
|
+
entry.writeUInt8(size === 256 ? 0 : size, 0);
|
|
45
|
+
entry.writeUInt8(size === 256 ? 0 : size, 1);
|
|
46
|
+
entry.writeUInt8(0, 2);
|
|
47
|
+
entry.writeUInt8(0, 3);
|
|
48
|
+
entry.writeUInt16LE(1, 4);
|
|
49
|
+
entry.writeUInt16LE(32, 6);
|
|
50
|
+
entry.writeUInt32LE(png.length, 8);
|
|
51
|
+
entry.writeUInt32LE(offset, 12);
|
|
52
|
+
dirEntries.push(entry);
|
|
53
|
+
offset += png.length;
|
|
54
|
+
}
|
|
55
|
+
return Buffer.concat([header, ...dirEntries, ...pngBuffers]);
|
|
56
|
+
}
|
|
57
|
+
async function loadSharp() {
|
|
58
|
+
const mod = await import('sharp').catch(() => {
|
|
59
|
+
console.error(colors.red("sharp is required for icon generation. Install it with:"));
|
|
60
|
+
console.error(colors.cyan(" pnpm add -D sharp"));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
return mod.default;
|
|
64
|
+
}
|
|
65
|
+
const main = defineCommand({
|
|
66
|
+
meta: { name, version, description },
|
|
67
|
+
args: {
|
|
68
|
+
command: {
|
|
69
|
+
type: "positional",
|
|
70
|
+
required: false
|
|
71
|
+
},
|
|
72
|
+
...cwdArgs
|
|
73
|
+
},
|
|
74
|
+
subCommands: {
|
|
75
|
+
icons: defineCommand({
|
|
76
|
+
meta: {
|
|
77
|
+
name: "icons",
|
|
78
|
+
description: "Generate favicon and icon variants from a source image"
|
|
79
|
+
},
|
|
80
|
+
args: {
|
|
81
|
+
...cwdArgs,
|
|
82
|
+
source: {
|
|
83
|
+
type: "string",
|
|
84
|
+
description: "Source image file relative to the public directory (e.g. logo.svg)",
|
|
85
|
+
required: true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
async run(ctx) {
|
|
89
|
+
const cwd = resolve(String(ctx.args.cwd));
|
|
90
|
+
const nuxtConfig = await loadNuxtConfig({ cwd });
|
|
91
|
+
const publicDir = resolve(cwd, nuxtConfig.dir?.public ?? "public");
|
|
92
|
+
const source = String(ctx.args.source);
|
|
93
|
+
const sourcePath = resolve(publicDir, source);
|
|
94
|
+
if (!existsSync(sourcePath)) {
|
|
95
|
+
console.error(colors.red(`Source file not found: ${sourcePath}`));
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const ext = source.split(".").pop()?.toLowerCase();
|
|
99
|
+
if (!ext || !SUPPORTED_FORMATS.has(ext)) {
|
|
100
|
+
console.error(colors.red(`Unsupported format "${ext}". Use: ${[...SUPPORTED_FORMATS].join(", ")}`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const sharp = await loadSharp();
|
|
104
|
+
console.log(colors.cyan(`Generating icons from ${colors.bold(String(source))}...`));
|
|
105
|
+
for (const icon of ICON_SIZES) {
|
|
106
|
+
const outputPath = resolve(publicDir, icon.name);
|
|
107
|
+
await sharp(sourcePath).resize(icon.width, icon.height, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }).png().toFile(outputPath);
|
|
108
|
+
console.log(colors.green(` ${icon.name} (${icon.width}x${icon.height})`));
|
|
109
|
+
}
|
|
110
|
+
const faviconPng = await sharp(sourcePath).resize(32, 32, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }).png().toBuffer();
|
|
111
|
+
await writeFile(resolve(publicDir, "favicon.ico"), pngToIco([faviconPng]));
|
|
112
|
+
console.log(colors.green(" favicon.ico (32x32)"));
|
|
113
|
+
console.log(colors.bold(colors.green("\nDone! Generated all icon variants.")));
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
runMain(main);
|
package/dist/module.d.mts
CHANGED
|
@@ -98,10 +98,35 @@ interface ModuleOptions {
|
|
|
98
98
|
* @default false
|
|
99
99
|
*/
|
|
100
100
|
redirectToCanonicalSiteUrl?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Sets the `tagPriority` for SEO and Open Graph meta tags generated by this module.
|
|
103
|
+
* Lower numbers appear earlier in the `<head>`. Style blocks default to 40-60,
|
|
104
|
+
* so a value below 40 ensures SEO tags appear before them, which is important
|
|
105
|
+
* for OG crawlers that only parse the first 1MB of a page.
|
|
106
|
+
*
|
|
107
|
+
* @default 30
|
|
108
|
+
*/
|
|
109
|
+
tagPriority: number;
|
|
101
110
|
/**
|
|
102
111
|
* The SEO meta object to be used as defaults.
|
|
103
112
|
*/
|
|
104
113
|
meta: MetaFlatSerializable;
|
|
114
|
+
/**
|
|
115
|
+
* Minify inline `<script>` and `<style>` tags in SSR responses. Both toggles are independent.
|
|
116
|
+
*
|
|
117
|
+
* - `true`: Enables both build and runtime minification.
|
|
118
|
+
* - `false`: Disabled.
|
|
119
|
+
* - `{ build?: boolean, runtime?: boolean }`: Toggle each mode independently.
|
|
120
|
+
*
|
|
121
|
+
* **Build mode**: Minifies static `app.head` scripts/styles and prerendered route HTML using esbuild (JS) and lightningcss (CSS).
|
|
122
|
+
* **Runtime mode**: Minifies all inline scripts/styles per SSR request via an Unhead `ssr:render` plugin using lightweight pure JS minifiers.
|
|
123
|
+
*
|
|
124
|
+
* @default true
|
|
125
|
+
*/
|
|
126
|
+
minify: boolean | {
|
|
127
|
+
build?: boolean;
|
|
128
|
+
runtime?: boolean;
|
|
129
|
+
};
|
|
105
130
|
/**
|
|
106
131
|
* Enables debug logs and a debug endpoint.
|
|
107
132
|
*
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { MetaFlatSerializable } from '../dist/runtime/types.js';
|
|
3
|
+
|
|
4
|
+
interface ModuleOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the SEO experiements should run.
|
|
7
|
+
*
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Should the files in the public directory be used to infer tags such as favicon, apple-touch-icon, and
|
|
13
|
+
* open graph images.
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
metaDataFiles: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Should head data be inferred from the current input to fill in the gaps.
|
|
20
|
+
*
|
|
21
|
+
* For example:
|
|
22
|
+
* - If you supply a title, this will automatically add an og:title.
|
|
23
|
+
* - If you provide an og:image, it will automatically add a twitter:image.
|
|
24
|
+
*
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
automaticOgAndTwitterTags: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Attempts to treeshake the `useSeoMeta` function. Can save around 5kb in the client bundle.
|
|
30
|
+
*
|
|
31
|
+
* @default true
|
|
32
|
+
*/
|
|
33
|
+
treeShakeUseSeoMeta: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Injects site config into the `useHead` composable such as setting the title template
|
|
36
|
+
*
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
mergeWithSiteConfig: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Adds `head` and `seoMeta` to the route rules and app config.
|
|
42
|
+
*
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
45
|
+
extendRouteRules: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Tries to convert relative image paths to absolute paths in meta tags.
|
|
48
|
+
*
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
fixRequiredAbsoluteMetaTagsLinks: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Extends the `head` in the Nuxt config with the `seoMeta` object.
|
|
54
|
+
*
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
extendNuxtConfigAppHeadSeoMeta: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Augments the head schema with `/public` files making it easier to reference them in the head.
|
|
60
|
+
*
|
|
61
|
+
* @default true
|
|
62
|
+
*/
|
|
63
|
+
extendNuxtConfigAppHeadTypes: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* @dead
|
|
66
|
+
*/
|
|
67
|
+
setupNuxtConfigAppHeadWithMoreDefaults: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Will ensure a title is always set by providing a fallback title based on the casing the last slug segment.
|
|
70
|
+
*
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
fallbackTitle?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Will set up a number of defaults for meta tags and Schema.org, if the modules and config are available.
|
|
76
|
+
*
|
|
77
|
+
* @default true
|
|
78
|
+
*/
|
|
79
|
+
automaticDefaults?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* When enabled, it will whitelist the query parameters that are allowed in the canonical URL.
|
|
82
|
+
*/
|
|
83
|
+
canonicalQueryWhitelist?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* When enabled, it will lowercase the canonical URL.
|
|
86
|
+
*
|
|
87
|
+
* @default true
|
|
88
|
+
*/
|
|
89
|
+
canonicalLowercase?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* When enabled, it will redirect any request to the canonical domain (site url) using a 301 redirect on non-dev environments.
|
|
92
|
+
*
|
|
93
|
+
* E.g if the site url is 'www.example.com' and the user visits 'example.com',
|
|
94
|
+
* they will be redirected to 'www.example.com'.
|
|
95
|
+
*
|
|
96
|
+
* This is useful for SEO as it prevents duplicate content and consolidates page rank.
|
|
97
|
+
*
|
|
98
|
+
* @default false
|
|
99
|
+
*/
|
|
100
|
+
redirectToCanonicalSiteUrl?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Sets the `tagPriority` for SEO and Open Graph meta tags generated by this module.
|
|
103
|
+
* Lower numbers appear earlier in the `<head>`. Style blocks default to 40-60,
|
|
104
|
+
* so a value below 40 ensures SEO tags appear before them, which is important
|
|
105
|
+
* for OG crawlers that only parse the first 1MB of a page.
|
|
106
|
+
*
|
|
107
|
+
* @default 30
|
|
108
|
+
*/
|
|
109
|
+
tagPriority: number;
|
|
110
|
+
/**
|
|
111
|
+
* The SEO meta object to be used as defaults.
|
|
112
|
+
*/
|
|
113
|
+
meta: MetaFlatSerializable;
|
|
114
|
+
/**
|
|
115
|
+
* Minify inline `<script>` and `<style>` tags in SSR responses. Both toggles are independent.
|
|
116
|
+
*
|
|
117
|
+
* - `true`: Enables both build and runtime minification.
|
|
118
|
+
* - `false`: Disabled.
|
|
119
|
+
* - `{ build?: boolean, runtime?: boolean }`: Toggle each mode independently.
|
|
120
|
+
*
|
|
121
|
+
* **Build mode**: Minifies static `app.head` scripts/styles and prerendered route HTML using esbuild (JS) and lightningcss (CSS).
|
|
122
|
+
* **Runtime mode**: Minifies all inline scripts/styles per SSR request via an Unhead `ssr:render` plugin using lightweight pure JS minifiers.
|
|
123
|
+
*
|
|
124
|
+
* @default true
|
|
125
|
+
*/
|
|
126
|
+
minify: boolean | {
|
|
127
|
+
build?: boolean;
|
|
128
|
+
runtime?: boolean;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Enables debug logs and a debug endpoint.
|
|
132
|
+
*
|
|
133
|
+
* @default false
|
|
134
|
+
*/
|
|
135
|
+
debug: boolean;
|
|
136
|
+
}
|
|
137
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
138
|
+
|
|
139
|
+
export { _default as default };
|
|
140
|
+
export type { ModuleOptions };
|