vite-plugin-sitemap-ts 1.0.0 → 1.1.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 +11 -7
- package/dist/index.cjs +93 -17
- package/dist/index.d.cts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +83 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A Vite plugin to generate `sitemap.xml`. Works in development mode by proxying middleware to `/sitemap.xml`.
|
|
4
4
|
|
|
5
|
-
> [!
|
|
6
|
-
> This plugin is actively being devloped.
|
|
5
|
+
> [!WARNING]
|
|
6
|
+
> **DO NOT USE IN PRODUCTION!** This plugin is actively being devloped.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -23,16 +23,20 @@ import { sitemap } from 'vite-plugin-sitemap-ts'
|
|
|
23
23
|
|
|
24
24
|
export default {
|
|
25
25
|
plugins: [
|
|
26
|
-
sitemap(
|
|
26
|
+
sitemap({
|
|
27
|
+
hostname: 'https://example.com',
|
|
28
|
+
}),
|
|
27
29
|
],
|
|
28
30
|
}
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
## Options
|
|
32
34
|
|
|
33
|
-
All options are optional.
|
|
35
|
+
The `hostname` option is required. All other options are optional.
|
|
34
36
|
|
|
35
|
-
| Option
|
|
36
|
-
|
|
37
|
-
|
|
|
37
|
+
| Option | Type | Default | Description |
|
|
38
|
+
|----------|------------|---------|----------------------------------------------------------------------|
|
|
39
|
+
| hostname | *string* | - | The hostname of the site, used to build the full URLs in the sitemap |
|
|
40
|
+
| enabled | *boolean* | `true` | Toggle the plugin on or off |
|
|
41
|
+
| routes | *string[]* | `['/']` | An array of routes to include in the sitemap |
|
|
38
42
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -24,10 +34,69 @@ __export(index_exports, {
|
|
|
24
34
|
});
|
|
25
35
|
module.exports = __toCommonJS(index_exports);
|
|
26
36
|
|
|
37
|
+
// src/plugin.ts
|
|
38
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
39
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
40
|
+
|
|
27
41
|
// src/utils.ts
|
|
28
|
-
var
|
|
29
|
-
|
|
42
|
+
var SPACER = " ";
|
|
43
|
+
var DSPACER = SPACER + SPACER;
|
|
44
|
+
var xmlHeader = `<?xml version="1.0" encoding="UTF-8"?>`;
|
|
45
|
+
var xmlSchema = (content) => {
|
|
46
|
+
return `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
47
|
+
${content}
|
|
30
48
|
</urlset>`;
|
|
49
|
+
};
|
|
50
|
+
var escapeXml = (value) => {
|
|
51
|
+
return String(value).replace(/[&<>"']/g, (ch) => {
|
|
52
|
+
switch (ch) {
|
|
53
|
+
case "&":
|
|
54
|
+
return "&";
|
|
55
|
+
case "<":
|
|
56
|
+
return "<";
|
|
57
|
+
case ">":
|
|
58
|
+
return ">";
|
|
59
|
+
case '"':
|
|
60
|
+
return """;
|
|
61
|
+
case "'":
|
|
62
|
+
return "'";
|
|
63
|
+
default:
|
|
64
|
+
return ch;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
var generateSitemap = (entries) => {
|
|
69
|
+
const urls = entries.map((entry) => {
|
|
70
|
+
let sitemapEntry = `${DSPACER}<loc>${escapeXml(entry.loc)}</loc>`;
|
|
71
|
+
if (entry.lastmod) {
|
|
72
|
+
sitemapEntry += `
|
|
73
|
+
${DSPACER}<lastmod>${escapeXml(entry.lastmod)}</lastmod>`;
|
|
74
|
+
}
|
|
75
|
+
if (entry.changefreq) {
|
|
76
|
+
sitemapEntry += `
|
|
77
|
+
${DSPACER}<changefreq>${escapeXml(entry.changefreq)}</changefreq>`;
|
|
78
|
+
}
|
|
79
|
+
if (entry.priority !== void 0) {
|
|
80
|
+
sitemapEntry += `
|
|
81
|
+
${DSPACER}<priority>${escapeXml(entry.priority)}</priority>`;
|
|
82
|
+
}
|
|
83
|
+
return `${SPACER}<url>
|
|
84
|
+
${sitemapEntry}
|
|
85
|
+
${SPACER}</url>`;
|
|
86
|
+
}).join("\n");
|
|
87
|
+
return `${xmlHeader}
|
|
88
|
+
${xmlSchema(urls)}`;
|
|
89
|
+
};
|
|
90
|
+
var buildSitemapEntries = (options) => {
|
|
91
|
+
const host = options.hostname.replace(/\/$/, "");
|
|
92
|
+
const lastmod = (/* @__PURE__ */ new Date()).toISOString();
|
|
93
|
+
return options.routes.map((route) => {
|
|
94
|
+
return {
|
|
95
|
+
loc: `${host}/${route.replace(/^\/+/, "")}`,
|
|
96
|
+
lastmod
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
};
|
|
31
100
|
var logColor = (color, text, bold = false) => {
|
|
32
101
|
const colorCode = {
|
|
33
102
|
red: bold ? "\x1B[1;31m" : "\x1B[31m",
|
|
@@ -45,11 +114,15 @@ var LOGGER_FAILURE = logColor("red", "\u2717", true);
|
|
|
45
114
|
var BASE_PATH = "/";
|
|
46
115
|
var FILE_NAME = "sitemap.xml";
|
|
47
116
|
var SITEMAP_PATH = `${BASE_PATH}${FILE_NAME}`;
|
|
48
|
-
function sitemap(options
|
|
117
|
+
function sitemap(options) {
|
|
49
118
|
let config;
|
|
50
119
|
let success = false;
|
|
51
|
-
const sitemapContent = SITEMAP_CONTENT;
|
|
52
120
|
const enabled = options.enabled ?? true;
|
|
121
|
+
const host = options.hostname ?? void 0;
|
|
122
|
+
const routes = options.routes ?? ["/"];
|
|
123
|
+
if (!host) {
|
|
124
|
+
throw new Error("Sitemap hostname is not set and required to build the sitemap.");
|
|
125
|
+
}
|
|
53
126
|
return {
|
|
54
127
|
name: "vite-plugin-sitemap-ts",
|
|
55
128
|
apply: () => enabled,
|
|
@@ -58,27 +131,30 @@ function sitemap(options = {}) {
|
|
|
58
131
|
},
|
|
59
132
|
configureServer(server) {
|
|
60
133
|
server.middlewares.use(SITEMAP_PATH, (_req, res) => {
|
|
134
|
+
const entries = buildSitemapEntries({ hostname: host, routes });
|
|
135
|
+
const content = generateSitemap(entries);
|
|
61
136
|
res.setHeader("Content-Type", "text/xml; charset=utf-8");
|
|
62
|
-
res.end(
|
|
137
|
+
res.end(content);
|
|
63
138
|
});
|
|
64
139
|
config.logger.info(
|
|
65
140
|
`${LOGGER_CLEAR}${LOGGER_SUCCESS} ${LOGGER_PREFIX} Exposed new route: ${logColor("green", SITEMAP_PATH)}`
|
|
66
141
|
);
|
|
67
142
|
},
|
|
68
|
-
|
|
69
|
-
if (this.environment
|
|
70
|
-
|
|
143
|
+
closeBundle() {
|
|
144
|
+
if (this.environment) {
|
|
145
|
+
if (this.environment.name !== "client" || this.environment.mode === "dev") {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
71
148
|
}
|
|
72
|
-
config.
|
|
73
|
-
|
|
74
|
-
- ${LOGGER_CLEAR}${LOGGER_PREFIX} Writing sitemap.xml at ${
|
|
75
|
-
);
|
|
149
|
+
const outDir = config.build.outDir.replace("server", "client");
|
|
150
|
+
config.logger.info(`
|
|
151
|
+
- ${LOGGER_CLEAR}${LOGGER_PREFIX} Writing sitemap.xml at ${outDir}${SITEMAP_PATH}`);
|
|
76
152
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
153
|
+
const entries = buildSitemapEntries({ hostname: host, routes });
|
|
154
|
+
const content = generateSitemap(entries);
|
|
155
|
+
const outDirPath = import_node_path.default.resolve(config.root, outDir);
|
|
156
|
+
const filePath = import_node_path.default.join(outDirPath, FILE_NAME);
|
|
157
|
+
import_node_fs.default.writeFileSync(filePath, content, "utf-8");
|
|
82
158
|
success = true;
|
|
83
159
|
} catch (_err) {
|
|
84
160
|
success = false;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
+
type ChangeFreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
4
|
+
type SitemapEntry = {
|
|
5
|
+
loc: string;
|
|
6
|
+
lastmod?: string;
|
|
7
|
+
priority?: number;
|
|
8
|
+
changefreq?: ChangeFreq;
|
|
9
|
+
};
|
|
3
10
|
type Options = {
|
|
4
11
|
/**
|
|
5
12
|
* Toggle the plugin on or off. Useful if you want to disable the plugin, e.g. in development mode.
|
|
@@ -7,8 +14,20 @@ type Options = {
|
|
|
7
14
|
* **Default: `true`**
|
|
8
15
|
*/
|
|
9
16
|
enabled?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The hostname of the site, used to build the full URLs in the sitemap.
|
|
19
|
+
*
|
|
20
|
+
* **Example: `'https://example.com'`**
|
|
21
|
+
*/
|
|
22
|
+
hostname: string;
|
|
23
|
+
/**
|
|
24
|
+
* An array of routes to include in the sitemap.
|
|
25
|
+
*
|
|
26
|
+
* **Default: `['/']`**
|
|
27
|
+
*/
|
|
28
|
+
routes?: string[];
|
|
10
29
|
};
|
|
11
30
|
|
|
12
|
-
declare function sitemap(options
|
|
31
|
+
declare function sitemap(options: Options): Plugin;
|
|
13
32
|
|
|
14
|
-
export { type Options, sitemap };
|
|
33
|
+
export { type ChangeFreq, type Options, type SitemapEntry, sitemap };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
+
type ChangeFreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
4
|
+
type SitemapEntry = {
|
|
5
|
+
loc: string;
|
|
6
|
+
lastmod?: string;
|
|
7
|
+
priority?: number;
|
|
8
|
+
changefreq?: ChangeFreq;
|
|
9
|
+
};
|
|
3
10
|
type Options = {
|
|
4
11
|
/**
|
|
5
12
|
* Toggle the plugin on or off. Useful if you want to disable the plugin, e.g. in development mode.
|
|
@@ -7,8 +14,20 @@ type Options = {
|
|
|
7
14
|
* **Default: `true`**
|
|
8
15
|
*/
|
|
9
16
|
enabled?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The hostname of the site, used to build the full URLs in the sitemap.
|
|
19
|
+
*
|
|
20
|
+
* **Example: `'https://example.com'`**
|
|
21
|
+
*/
|
|
22
|
+
hostname: string;
|
|
23
|
+
/**
|
|
24
|
+
* An array of routes to include in the sitemap.
|
|
25
|
+
*
|
|
26
|
+
* **Default: `['/']`**
|
|
27
|
+
*/
|
|
28
|
+
routes?: string[];
|
|
10
29
|
};
|
|
11
30
|
|
|
12
|
-
declare function sitemap(options
|
|
31
|
+
declare function sitemap(options: Options): Plugin;
|
|
13
32
|
|
|
14
|
-
export { type Options, sitemap };
|
|
33
|
+
export { type ChangeFreq, type Options, type SitemapEntry, sitemap };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,66 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
1
5
|
// src/utils.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
6
|
+
var SPACER = " ";
|
|
7
|
+
var DSPACER = SPACER + SPACER;
|
|
8
|
+
var xmlHeader = `<?xml version="1.0" encoding="UTF-8"?>`;
|
|
9
|
+
var xmlSchema = (content) => {
|
|
10
|
+
return `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
11
|
+
${content}
|
|
4
12
|
</urlset>`;
|
|
13
|
+
};
|
|
14
|
+
var escapeXml = (value) => {
|
|
15
|
+
return String(value).replace(/[&<>"']/g, (ch) => {
|
|
16
|
+
switch (ch) {
|
|
17
|
+
case "&":
|
|
18
|
+
return "&";
|
|
19
|
+
case "<":
|
|
20
|
+
return "<";
|
|
21
|
+
case ">":
|
|
22
|
+
return ">";
|
|
23
|
+
case '"':
|
|
24
|
+
return """;
|
|
25
|
+
case "'":
|
|
26
|
+
return "'";
|
|
27
|
+
default:
|
|
28
|
+
return ch;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
var generateSitemap = (entries) => {
|
|
33
|
+
const urls = entries.map((entry) => {
|
|
34
|
+
let sitemapEntry = `${DSPACER}<loc>${escapeXml(entry.loc)}</loc>`;
|
|
35
|
+
if (entry.lastmod) {
|
|
36
|
+
sitemapEntry += `
|
|
37
|
+
${DSPACER}<lastmod>${escapeXml(entry.lastmod)}</lastmod>`;
|
|
38
|
+
}
|
|
39
|
+
if (entry.changefreq) {
|
|
40
|
+
sitemapEntry += `
|
|
41
|
+
${DSPACER}<changefreq>${escapeXml(entry.changefreq)}</changefreq>`;
|
|
42
|
+
}
|
|
43
|
+
if (entry.priority !== void 0) {
|
|
44
|
+
sitemapEntry += `
|
|
45
|
+
${DSPACER}<priority>${escapeXml(entry.priority)}</priority>`;
|
|
46
|
+
}
|
|
47
|
+
return `${SPACER}<url>
|
|
48
|
+
${sitemapEntry}
|
|
49
|
+
${SPACER}</url>`;
|
|
50
|
+
}).join("\n");
|
|
51
|
+
return `${xmlHeader}
|
|
52
|
+
${xmlSchema(urls)}`;
|
|
53
|
+
};
|
|
54
|
+
var buildSitemapEntries = (options) => {
|
|
55
|
+
const host = options.hostname.replace(/\/$/, "");
|
|
56
|
+
const lastmod = (/* @__PURE__ */ new Date()).toISOString();
|
|
57
|
+
return options.routes.map((route) => {
|
|
58
|
+
return {
|
|
59
|
+
loc: `${host}/${route.replace(/^\/+/, "")}`,
|
|
60
|
+
lastmod
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
};
|
|
5
64
|
var logColor = (color, text, bold = false) => {
|
|
6
65
|
const colorCode = {
|
|
7
66
|
red: bold ? "\x1B[1;31m" : "\x1B[31m",
|
|
@@ -19,11 +78,15 @@ var LOGGER_FAILURE = logColor("red", "\u2717", true);
|
|
|
19
78
|
var BASE_PATH = "/";
|
|
20
79
|
var FILE_NAME = "sitemap.xml";
|
|
21
80
|
var SITEMAP_PATH = `${BASE_PATH}${FILE_NAME}`;
|
|
22
|
-
function sitemap(options
|
|
81
|
+
function sitemap(options) {
|
|
23
82
|
let config;
|
|
24
83
|
let success = false;
|
|
25
|
-
const sitemapContent = SITEMAP_CONTENT;
|
|
26
84
|
const enabled = options.enabled ?? true;
|
|
85
|
+
const host = options.hostname ?? void 0;
|
|
86
|
+
const routes = options.routes ?? ["/"];
|
|
87
|
+
if (!host) {
|
|
88
|
+
throw new Error("Sitemap hostname is not set and required to build the sitemap.");
|
|
89
|
+
}
|
|
27
90
|
return {
|
|
28
91
|
name: "vite-plugin-sitemap-ts",
|
|
29
92
|
apply: () => enabled,
|
|
@@ -32,27 +95,30 @@ function sitemap(options = {}) {
|
|
|
32
95
|
},
|
|
33
96
|
configureServer(server) {
|
|
34
97
|
server.middlewares.use(SITEMAP_PATH, (_req, res) => {
|
|
98
|
+
const entries = buildSitemapEntries({ hostname: host, routes });
|
|
99
|
+
const content = generateSitemap(entries);
|
|
35
100
|
res.setHeader("Content-Type", "text/xml; charset=utf-8");
|
|
36
|
-
res.end(
|
|
101
|
+
res.end(content);
|
|
37
102
|
});
|
|
38
103
|
config.logger.info(
|
|
39
104
|
`${LOGGER_CLEAR}${LOGGER_SUCCESS} ${LOGGER_PREFIX} Exposed new route: ${logColor("green", SITEMAP_PATH)}`
|
|
40
105
|
);
|
|
41
106
|
},
|
|
42
|
-
|
|
43
|
-
if (this.environment
|
|
44
|
-
|
|
107
|
+
closeBundle() {
|
|
108
|
+
if (this.environment) {
|
|
109
|
+
if (this.environment.name !== "client" || this.environment.mode === "dev") {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
45
112
|
}
|
|
46
|
-
config.
|
|
47
|
-
|
|
48
|
-
- ${LOGGER_CLEAR}${LOGGER_PREFIX} Writing sitemap.xml at ${
|
|
49
|
-
);
|
|
113
|
+
const outDir = config.build.outDir.replace("server", "client");
|
|
114
|
+
config.logger.info(`
|
|
115
|
+
- ${LOGGER_CLEAR}${LOGGER_PREFIX} Writing sitemap.xml at ${outDir}${SITEMAP_PATH}`);
|
|
50
116
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
117
|
+
const entries = buildSitemapEntries({ hostname: host, routes });
|
|
118
|
+
const content = generateSitemap(entries);
|
|
119
|
+
const outDirPath = path.resolve(config.root, outDir);
|
|
120
|
+
const filePath = path.join(outDirPath, FILE_NAME);
|
|
121
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
56
122
|
success = true;
|
|
57
123
|
} catch (_err) {
|
|
58
124
|
success = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-sitemap-ts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Vite plugin to generate sitemap.xml. Works in dev mode.",
|
|
5
5
|
"author": "Cornelius Weidmann <cornelius@kyco.io> (https://kyco.io)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vite": ">=2"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@biomejs/biome": "^2.4.
|
|
66
|
+
"@biomejs/biome": "^2.4.7",
|
|
67
67
|
"@semantic-release/changelog": "^6.0.3",
|
|
68
68
|
"@semantic-release/git": "^10.0.1",
|
|
69
69
|
"@semantic-release/github": "^12.0.6",
|