nuxt-link-checker 0.1.5 → 0.2.0
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 +4 -2
- package/dist/module.d.ts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +21 -24
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
Improve your sites SEO by identifying and fixing link issues in your Nuxt
|
|
13
|
+
Improve your sites SEO by identifying and fixing link issues in your Nuxt 3 app.
|
|
14
14
|
</p>
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
@@ -27,6 +27,8 @@ Improve your sites SEO by identifying and fixing link issues in your Nuxt v3 app
|
|
|
27
27
|
</table>
|
|
28
28
|
</p>
|
|
29
29
|
|
|
30
|
+
ℹ️ Looking for a complete SEO solution? Check out [nuxt-seo-kit](https://github.com/harlan-zw/nuxt-seo-kit).
|
|
31
|
+
|
|
30
32
|
## Features
|
|
31
33
|
|
|
32
34
|
- ✅ Discover broken links - 404s and internal redirects
|
|
@@ -102,7 +104,7 @@ If set to `true`, the build will fail if any broken links are found.
|
|
|
102
104
|
### `host`
|
|
103
105
|
|
|
104
106
|
- Type: `string`
|
|
105
|
-
- Default: `runtimeConfig.public.siteUrl`
|
|
107
|
+
- Default: `runtimeConfig.public.siteUrl || localhost`
|
|
106
108
|
- Required: `false`
|
|
107
109
|
|
|
108
110
|
The host of your site. This is required to validate absolute URLs which may be internal.
|
package/dist/module.d.ts
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineNuxtModule } from '@nuxt/kit';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import {
|
|
3
|
+
import { parseURL, hasProtocol } from 'ufo';
|
|
4
4
|
import { load } from 'cheerio';
|
|
5
5
|
|
|
6
6
|
const linkMap = {};
|
|
@@ -11,36 +11,25 @@ function getExtension(path) {
|
|
|
11
11
|
}
|
|
12
12
|
function extractLinks(html, from, { host, trailingSlash }) {
|
|
13
13
|
const links = [];
|
|
14
|
-
const
|
|
14
|
+
const hostname = parseURL(host).host;
|
|
15
15
|
const $ = load(html);
|
|
16
16
|
$("[href]").each((i, el) => {
|
|
17
17
|
const href = $(el).attr("href");
|
|
18
18
|
if (!href)
|
|
19
19
|
return;
|
|
20
|
-
|
|
20
|
+
const url = parseURL(href);
|
|
21
|
+
if (hasProtocol(href) && !href.startsWith("/") && url.host !== hostname)
|
|
21
22
|
return;
|
|
22
23
|
if (!allowedExtensions.has(getExtension(href)))
|
|
23
24
|
return;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
links.push({
|
|
26
|
+
pathname: url.pathname || "/",
|
|
27
|
+
url,
|
|
28
|
+
badAbsolute: Boolean(hostname) && hostname === url.host,
|
|
29
|
+
badTrailingSlash: url.pathname !== "/" && (trailingSlash && !url.pathname.endsWith("/") || !trailingSlash && url.pathname.endsWith("/")),
|
|
27
30
|
element: $.html(el) || ""
|
|
28
31
|
});
|
|
29
32
|
});
|
|
30
|
-
for (const link of _links.filter(Boolean)) {
|
|
31
|
-
const parsed = parseURL(link.href);
|
|
32
|
-
if (parsed.protocol)
|
|
33
|
-
continue;
|
|
34
|
-
let { pathname } = parsed;
|
|
35
|
-
if (!pathname.startsWith("/")) {
|
|
36
|
-
const fromURL = new URL(from, "http://localhost");
|
|
37
|
-
pathname = new URL(pathname, fromURL).pathname;
|
|
38
|
-
}
|
|
39
|
-
links.push({
|
|
40
|
-
...link,
|
|
41
|
-
href: pathname
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
33
|
return links;
|
|
45
34
|
}
|
|
46
35
|
|
|
@@ -56,12 +45,14 @@ const module = defineNuxtModule({
|
|
|
56
45
|
},
|
|
57
46
|
defaults(nuxt) {
|
|
58
47
|
return {
|
|
59
|
-
host: nuxt.options.runtimeConfig.public?.siteUrl,
|
|
48
|
+
host: nuxt.options.runtimeConfig.public?.siteUrl || "localhost",
|
|
60
49
|
trailingSlash: nuxt.options.runtimeConfig.public?.trailingSlash || false,
|
|
61
50
|
failOn404: true
|
|
62
51
|
};
|
|
63
52
|
},
|
|
64
53
|
setup(config, nuxt) {
|
|
54
|
+
if (nuxt.options.dev)
|
|
55
|
+
return;
|
|
65
56
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
66
57
|
const invalidRoutes = {};
|
|
67
58
|
nitro.hooks.hook("prerender:generate", async (ctx) => {
|
|
@@ -71,15 +62,17 @@ const module = defineNuxtModule({
|
|
|
71
62
|
invalidRoutes[ctx.route] = ctx.error.statusCode;
|
|
72
63
|
});
|
|
73
64
|
nitro.hooks.hook("close", async () => {
|
|
74
|
-
nitro.logger.info("Scanning routes for broken links...");
|
|
75
65
|
const links = Object.entries(linkMap);
|
|
66
|
+
if (!links.length)
|
|
67
|
+
return;
|
|
68
|
+
nitro.logger.info(`Scanning routes for broken links... ${chalk.gray(`trailingSlashes: ${config.trailingSlash ? "`true`" : "`false`"}`)}`);
|
|
76
69
|
let routeCount = 0;
|
|
77
70
|
let badLinkCount = 0;
|
|
78
71
|
links.forEach(([route, routes]) => {
|
|
79
72
|
const brokenLinks = routes.map((r) => {
|
|
80
73
|
return {
|
|
81
74
|
...r,
|
|
82
|
-
statusCode: invalidRoutes[r.
|
|
75
|
+
statusCode: invalidRoutes[r.pathname] || 200
|
|
83
76
|
};
|
|
84
77
|
}).filter((r) => r.statusCode !== 200 || r.badTrailingSlash);
|
|
85
78
|
if (brokenLinks.length) {
|
|
@@ -93,9 +86,13 @@ const module = defineNuxtModule({
|
|
|
93
86
|
nitro.logger.log(chalk.red(
|
|
94
87
|
` ${link.statusCode} ${link.statusCode === 404 ? "Not Found" : "Redirect"}`
|
|
95
88
|
));
|
|
89
|
+
} else if (link.badAbsolute) {
|
|
90
|
+
nitro.logger.log(chalk.yellow(
|
|
91
|
+
" Absolute link, should be relative"
|
|
92
|
+
));
|
|
96
93
|
} else if (link.badTrailingSlash) {
|
|
97
94
|
nitro.logger.log(chalk.yellow(
|
|
98
|
-
|
|
95
|
+
" Incorrect trailing slash"
|
|
99
96
|
));
|
|
100
97
|
}
|
|
101
98
|
nitro.logger.log(` ${chalk.gray(link.element)}`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-link-checker",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"packageManager": "pnpm@7.18.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/harlan-zw",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"@nuxt/test-utils": "3.0.0",
|
|
39
39
|
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
|
40
40
|
"bumpp": "^8.2.1",
|
|
41
|
-
"eslint": "8.
|
|
41
|
+
"eslint": "8.31.0",
|
|
42
42
|
"execa": "^6.1.0",
|
|
43
43
|
"nuxt": "^3.0.0",
|
|
44
44
|
"pathe": "^1.0.0",
|
|
45
|
-
"vitest": "^0.
|
|
45
|
+
"vitest": "^0.26.3"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"lint": "eslint \"**/*.{ts,vue,json,yml}\" --fix",
|