vite-plugin-unit 0.0.5 → 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 +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +68 -16
- package/package.json +58 -70
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vite-plugin-unit
|
|
3
|
-
* @description A vite plugin to enable you build websites in units
|
|
3
|
+
* @description A vite plugin to enable you build websites in units.
|
|
4
4
|
* @author Henry Hale
|
|
5
5
|
* @license MIT
|
|
6
6
|
* @url https://github.com/henryhale/vite-plugin-unit
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vite-plugin-unit
|
|
3
|
-
* @description A vite plugin to enable you build websites in units
|
|
3
|
+
* @description A vite plugin to enable you build websites in units.
|
|
4
4
|
* @author Henry Hale
|
|
5
5
|
* @license MIT
|
|
6
6
|
* @url https://github.com/henryhale/vite-plugin-unit
|
|
7
7
|
*/
|
|
8
|
+
import { log } from "node:console";
|
|
8
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
9
11
|
import { dirname, extname, join, resolve } from "node:path";
|
|
10
|
-
import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
11
|
-
import { log } from "node:console";
|
|
12
12
|
const defaultOptions = {
|
|
13
13
|
pages: "pages/",
|
|
14
14
|
template: "template.html",
|
|
15
|
-
slot: "
|
|
15
|
+
slot: "<slot></slot>"
|
|
16
16
|
};
|
|
17
17
|
export default function plugin(options = {}) {
|
|
18
18
|
const opt = Object.assign({}, defaultOptions, options);
|
|
@@ -23,9 +23,17 @@ export default function plugin(options = {}) {
|
|
|
23
23
|
// source code folder
|
|
24
24
|
const srcDir = "src/";
|
|
25
25
|
// intermediate output folder for unit.js
|
|
26
|
-
const outputDir = "
|
|
27
|
-
// regexp to match single html tag
|
|
26
|
+
const outputDir = ".unit/";
|
|
27
|
+
// regexp to match single html tag with attributes
|
|
28
28
|
const htmlRegex = /<(.+?) ([/]?|.+?)>/g;
|
|
29
|
+
// import statements
|
|
30
|
+
const importRegex = /import (.+?) from "(.+?)"(.+?)/g;
|
|
31
|
+
// html tag regexp
|
|
32
|
+
const tagRegex = /<(.+?)>/;
|
|
33
|
+
// regexp to match attributes in html tag
|
|
34
|
+
const attrRegex = /(\w+(?:-\w+)*)\s*=\s*["']([^"']+)["']/g;
|
|
35
|
+
// regexp to match placeholders like {text}
|
|
36
|
+
const valueRegex = /{(\w*)}/g;
|
|
29
37
|
// mapping file path to thier contents
|
|
30
38
|
const pathToCode = new Map();
|
|
31
39
|
// function that compiles .unit files
|
|
@@ -33,9 +41,19 @@ export default function plugin(options = {}) {
|
|
|
33
41
|
let filePath = null;
|
|
34
42
|
let content = null;
|
|
35
43
|
const nameToPath = new Map();
|
|
44
|
+
// create a key-value object from attributes of an html tag
|
|
45
|
+
function mapAttributes(attr = "") {
|
|
46
|
+
const map = {};
|
|
47
|
+
let match = attrRegex.exec(attr);
|
|
48
|
+
while (match !== null) {
|
|
49
|
+
map[match[1]] = match[2];
|
|
50
|
+
match = attrRegex.exec(attr);
|
|
51
|
+
}
|
|
52
|
+
return map;
|
|
53
|
+
}
|
|
36
54
|
// remove all import statements while saving the import names & content
|
|
37
55
|
return (code
|
|
38
|
-
.replace(
|
|
56
|
+
.replace(importRegex, (_, importName, importPath) => {
|
|
39
57
|
filePath = join(dirname(file), importPath);
|
|
40
58
|
nameToPath.set(importName, filePath);
|
|
41
59
|
if (!pathToCode.has(filePath)) {
|
|
@@ -45,12 +63,29 @@ export default function plugin(options = {}) {
|
|
|
45
63
|
return "";
|
|
46
64
|
})
|
|
47
65
|
// replace every html tag matching an import name
|
|
48
|
-
.replace(htmlRegex, (match, tag, attr
|
|
66
|
+
.replace(htmlRegex, (match, tag, attr) => {
|
|
49
67
|
const path = nameToPath.get(tag);
|
|
50
68
|
if (path) {
|
|
69
|
+
// get rid of trailing forward slash
|
|
51
70
|
if (attr.endsWith("/"))
|
|
52
71
|
attr = attr.slice(0, -1);
|
|
53
|
-
|
|
72
|
+
const map = mapAttributes(attr);
|
|
73
|
+
return (pathToCode
|
|
74
|
+
.get(path)
|
|
75
|
+
?.replace(valueRegex, (m, key) => {
|
|
76
|
+
const value = map[key];
|
|
77
|
+
if (value) {
|
|
78
|
+
delete map[key];
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
return m;
|
|
82
|
+
})
|
|
83
|
+
.replace(tagRegex, (m) => {
|
|
84
|
+
const others = Object.entries(map).reduce((r, [k, v]) => {
|
|
85
|
+
return `${r + k}=${/'/.test(v) ? `"${v}"` : `'${v}'`}`;
|
|
86
|
+
}, "");
|
|
87
|
+
return `${m.slice(0, -1)} ${others}>`;
|
|
88
|
+
}) ?? "");
|
|
54
89
|
}
|
|
55
90
|
return match;
|
|
56
91
|
})
|
|
@@ -88,15 +123,23 @@ export default function plugin(options = {}) {
|
|
|
88
123
|
async function respond(file) {
|
|
89
124
|
res.statusCode = 200;
|
|
90
125
|
res.setHeader("Content-Type", "text/html");
|
|
91
|
-
const contents = await readFile(join(config.root, opt.template), {
|
|
126
|
+
const contents = await readFile(join(config.root, opt.template), {
|
|
127
|
+
encoding: "utf-8"
|
|
128
|
+
});
|
|
92
129
|
pathToCode.clear();
|
|
93
130
|
const compiled = compile(file, await readFile(file, { encoding: "utf-8" }));
|
|
94
131
|
res.end(contents.replace(opt.slot, compiled));
|
|
95
132
|
}
|
|
96
133
|
// folder containing pages
|
|
97
134
|
const srcDir = join(config.root, opt.pages);
|
|
135
|
+
// strip the base path from the request URL
|
|
136
|
+
let url = req.url || "";
|
|
137
|
+
const base = config.base || "/";
|
|
138
|
+
if (base !== "/" && url.startsWith(base)) {
|
|
139
|
+
url = "/" + url.slice(base.length);
|
|
140
|
+
}
|
|
98
141
|
// generate actual file path
|
|
99
|
-
let filePath = join(srcDir,
|
|
142
|
+
let filePath = join(srcDir, url + (url?.endsWith("/") ? "index.html" : ""));
|
|
100
143
|
// check if the requested html file does not exist
|
|
101
144
|
if (filePath.endsWith(".html") && !existsSync(filePath)) {
|
|
102
145
|
filePath = filePath.replace(".html", ext);
|
|
@@ -109,7 +152,7 @@ export default function plugin(options = {}) {
|
|
|
109
152
|
}
|
|
110
153
|
// try checking if the requested asset exists in the `src` folder
|
|
111
154
|
if (filePath.lastIndexOf(".") > -1) {
|
|
112
|
-
filePath = join(config.root,
|
|
155
|
+
filePath = join(config.root, url || "");
|
|
113
156
|
if (existsSync(filePath)) {
|
|
114
157
|
// direct the file path relative to the `src` folder
|
|
115
158
|
req.url = filePath;
|
|
@@ -157,7 +200,9 @@ export default function plugin(options = {}) {
|
|
|
157
200
|
* Grab the template file
|
|
158
201
|
*/
|
|
159
202
|
const templateFile = join(outputDir, opt.template);
|
|
160
|
-
const template = await readFile(templateFile, {
|
|
203
|
+
const template = await readFile(templateFile, {
|
|
204
|
+
encoding: "utf-8"
|
|
205
|
+
});
|
|
161
206
|
/**
|
|
162
207
|
* Capture the pages
|
|
163
208
|
*/
|
|
@@ -176,11 +221,18 @@ export default function plugin(options = {}) {
|
|
|
176
221
|
else {
|
|
177
222
|
// ...
|
|
178
223
|
}
|
|
179
|
-
const fileContent = await readFile(filePath, {
|
|
224
|
+
const fileContent = await readFile(filePath, {
|
|
225
|
+
encoding: "utf-8"
|
|
226
|
+
});
|
|
180
227
|
const compiledPage = compile(filePath, fileContent);
|
|
181
228
|
const result = template.replace(opt.slot, compiledPage);
|
|
182
229
|
log("build: ", page);
|
|
183
|
-
|
|
230
|
+
const fullPath = join(outputDir, page.replace(ext, ".html"));
|
|
231
|
+
const dirPath = dirname(fullPath);
|
|
232
|
+
if (!existsSync(dirPath)) {
|
|
233
|
+
await mkdir(dirPath, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
return await writeFile(fullPath, result);
|
|
184
236
|
}
|
|
185
237
|
/**
|
|
186
238
|
* Clear the input files
|
|
@@ -210,7 +262,7 @@ export default function plugin(options = {}) {
|
|
|
210
262
|
/**
|
|
211
263
|
* Copy the entire unit dist folder to the root of the project
|
|
212
264
|
*/
|
|
213
|
-
await cp(outputDir
|
|
265
|
+
await cp(`${outputDir}dist`, distFolder, { recursive: true });
|
|
214
266
|
// await new Promise((res) => setTimeout(res, 5000));
|
|
215
267
|
/**
|
|
216
268
|
* Delete the entire unit output folder
|
package/package.json
CHANGED
|
@@ -1,72 +1,60 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"@types/node": "^20.10.6",
|
|
61
|
-
"@typescript-eslint/eslint-plugin": "^6.16.0",
|
|
62
|
-
"@typescript-eslint/parser": "^6.16.0",
|
|
63
|
-
"eslint": "^8.56.0",
|
|
64
|
-
"eslint-plugin-prettier": "^5.1.2",
|
|
65
|
-
"husky": "^8.0.3",
|
|
66
|
-
"lint-staged": "^15.2.0",
|
|
67
|
-
"prettier": "^3.1.1",
|
|
68
|
-
"release-it": "^17.0.1",
|
|
69
|
-
"typescript": "^5.3.3",
|
|
70
|
-
"vite": "^5.0.11"
|
|
71
|
-
}
|
|
2
|
+
"name": "vite-plugin-unit",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A vite plugin to enable you build websites in units.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"./dist/",
|
|
10
|
+
"./LICENSE.md",
|
|
11
|
+
"./README.md",
|
|
12
|
+
"./package.json"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/henryhale/vite-plugin-unit.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"vite",
|
|
20
|
+
"static",
|
|
21
|
+
"site",
|
|
22
|
+
"static site generator",
|
|
23
|
+
"ui",
|
|
24
|
+
"website",
|
|
25
|
+
"browser"
|
|
26
|
+
],
|
|
27
|
+
"author": {
|
|
28
|
+
"name": "Henry Hale",
|
|
29
|
+
"url": "https://github.com/henryhale"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/henryhale/vite-plugin-unit/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/henryhale/vite-plugin-unit#readme",
|
|
36
|
+
"type": "module",
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -b",
|
|
39
|
+
"dev": "tsc -w",
|
|
40
|
+
"lint": "biome check",
|
|
41
|
+
"lint:fix": "biome check --fix",
|
|
42
|
+
"prepack": "pnpm build",
|
|
43
|
+
"prepare": "husky || true",
|
|
44
|
+
"release": "release-it",
|
|
45
|
+
"test": "echo \"Error: no test specified\""
|
|
46
|
+
},
|
|
47
|
+
"lint-staged": {
|
|
48
|
+
"*.ts": "pnpm lint:fix"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@biomejs/biome": "^2.4.10",
|
|
52
|
+
"@release-it/conventional-changelog": "^10.0.6",
|
|
53
|
+
"@types/node": "^25.5.2",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"lint-staged": "^16.4.0",
|
|
56
|
+
"release-it": "^19.2.4",
|
|
57
|
+
"typescript": "^6.0.2",
|
|
58
|
+
"vite": "^8.0.3"
|
|
59
|
+
}
|
|
72
60
|
}
|