nuxt-link-checker 0.1.6 → 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 +17 -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,7 +45,7 @@ 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
|
};
|
|
@@ -76,14 +65,14 @@ const module = defineNuxtModule({
|
|
|
76
65
|
const links = Object.entries(linkMap);
|
|
77
66
|
if (!links.length)
|
|
78
67
|
return;
|
|
79
|
-
nitro.logger.info(
|
|
68
|
+
nitro.logger.info(`Scanning routes for broken links... ${chalk.gray(`trailingSlashes: ${config.trailingSlash ? "`true`" : "`false`"}`)}`);
|
|
80
69
|
let routeCount = 0;
|
|
81
70
|
let badLinkCount = 0;
|
|
82
71
|
links.forEach(([route, routes]) => {
|
|
83
72
|
const brokenLinks = routes.map((r) => {
|
|
84
73
|
return {
|
|
85
74
|
...r,
|
|
86
|
-
statusCode: invalidRoutes[r.
|
|
75
|
+
statusCode: invalidRoutes[r.pathname] || 200
|
|
87
76
|
};
|
|
88
77
|
}).filter((r) => r.statusCode !== 200 || r.badTrailingSlash);
|
|
89
78
|
if (brokenLinks.length) {
|
|
@@ -97,9 +86,13 @@ const module = defineNuxtModule({
|
|
|
97
86
|
nitro.logger.log(chalk.red(
|
|
98
87
|
` ${link.statusCode} ${link.statusCode === 404 ? "Not Found" : "Redirect"}`
|
|
99
88
|
));
|
|
89
|
+
} else if (link.badAbsolute) {
|
|
90
|
+
nitro.logger.log(chalk.yellow(
|
|
91
|
+
" Absolute link, should be relative"
|
|
92
|
+
));
|
|
100
93
|
} else if (link.badTrailingSlash) {
|
|
101
94
|
nitro.logger.log(chalk.yellow(
|
|
102
|
-
|
|
95
|
+
" Incorrect trailing slash"
|
|
103
96
|
));
|
|
104
97
|
}
|
|
105
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",
|