vite-plugin-unit 0.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Henry Hale (https://github.com/henryhale)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # vite-plugin-unit
2
+
3
+ [![npm](https://img.shields.io/npm/v/vite-plugin-unit.svg?style=for-the-badge)](https://www.npmjs.com/package/vite-plugin-unit)
4
+
5
+ A vite plugin for handling unit.js projects
6
+
7
+ ## installation
8
+
9
+ ```sh
10
+ npm i -D vite-plugin-unit
11
+ ```
12
+
13
+ ## usage
14
+
15
+ ```js
16
+ import unit from "vite-plugin-unit";
17
+ import { defineConfig } from "vite";
18
+
19
+ export default defineConfig({
20
+ plugins: [
21
+ unit({/* options */})
22
+ ]
23
+ });
24
+ ```
25
+
26
+ ## configuration
27
+
28
+ ```ts
29
+ type PluginOptions = {
30
+ pages: string;
31
+ template: string;
32
+ slot: string;
33
+ };
34
+ ```
35
+
36
+ - `options.template`: _string_ - The HTML file in which compiles .unit files will be mounted
37
+ - `options.pages`: _string_ - The folder under `src` folder containing the pages or routes
38
+ - `options.slot`: _string_ - The slot identifier in the template to be replaced by compiled .unit files
39
+
40
+ ## default options
41
+
42
+ ```js
43
+ const defaultOptions = {
44
+ pages: "pages/",
45
+ template: "template.html",
46
+ slot: "#slot#"
47
+ };
48
+ ```
49
+
50
+ ## License
51
+
52
+ Released under the [MIT License](./LICENSE.md)
53
+
54
+ Copyright © 2024-present, [Henry Hale](https://github.com/henryhale)
@@ -0,0 +1,13 @@
1
+ /**
2
+ * vite-plugin-unit
3
+ * @author Henry Hale
4
+ * @license MIT
5
+ * @url https://github.com/unit-js/vite-plugin-unit
6
+ */
7
+ import type { Plugin } from "vite";
8
+ export type PluginOptions = {
9
+ pages: string;
10
+ template: string;
11
+ slot: string;
12
+ };
13
+ export default function plugin(options: Partial<PluginOptions>): Plugin[];
package/dist/index.js ADDED
@@ -0,0 +1,218 @@
1
+ /**
2
+ * vite-plugin-unit
3
+ * @author Henry Hale
4
+ * @license MIT
5
+ * @url https://github.com/unit-js/vite-plugin-unit
6
+ */
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { dirname, extname, join } from "node:path";
9
+ import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
10
+ import { log } from "node:console";
11
+ const defaultOptions = {
12
+ pages: "pages/",
13
+ template: "template.html",
14
+ slot: "#slot#"
15
+ };
16
+ export default function plugin(options) {
17
+ const opt = Object.assign({}, defaultOptions, options);
18
+ // unit file extension
19
+ const ext = ".unit";
20
+ // source code folder
21
+ const srcDir = "src/";
22
+ // intermediate output folder for unit.js
23
+ const outputDir = "./.unit/";
24
+ // regexp to match single html tag
25
+ const htmlRegex = /<(.+?) ([/]?|.+?)>/g;
26
+ // mapping file path to thier contents
27
+ const pathToCode = new Map();
28
+ // function that compiles .unit files
29
+ function compile(file = "", code = "") {
30
+ let filePath = null;
31
+ let content = null;
32
+ const nameToPath = new Map();
33
+ // remove all import statements while saving the import names & content
34
+ return (code
35
+ .replace(/import (.+?) from "(.+?)"(.+?)/g, (_, importName, importPath) => {
36
+ filePath = join(dirname(file), importPath);
37
+ nameToPath.set(importName, filePath);
38
+ if (!pathToCode.has(filePath)) {
39
+ content = compile(filePath, readFileSync(filePath, "utf-8"));
40
+ pathToCode.set(filePath, content);
41
+ }
42
+ return "";
43
+ })
44
+ // replace every html tag matching an import name
45
+ .replace(htmlRegex, (match, tag, attr = "") => {
46
+ const path = nameToPath.get(tag);
47
+ if (path) {
48
+ if (attr.endsWith("/"))
49
+ attr = attr.slice(0, -1);
50
+ return pathToCode.get(path).replace(/<(.+?)>/, (m) => m.slice(0, -1) + " " + attr + ">");
51
+ }
52
+ return match;
53
+ })
54
+ .trim());
55
+ }
56
+ return [
57
+ {
58
+ /**
59
+ * Unit.js - Server plugin
60
+ */
61
+ name: "vite-plugin-unit-serve",
62
+ /**
63
+ * use this plugin in development mode
64
+ */
65
+ apply: "serve",
66
+ /**
67
+ * partial config
68
+ */
69
+ config() {
70
+ return {
71
+ root: srcDir
72
+ };
73
+ },
74
+ /**
75
+ * intercept vite server requests and compile .unit files on demand
76
+ */
77
+ configureServer({ middlewares, config }) {
78
+ /**
79
+ * register a middleware to intercept the server's requests
80
+ */
81
+ middlewares.use(async (req, res, next) => {
82
+ /**
83
+ * function to send compiled .unit file as html
84
+ */
85
+ async function respond(file) {
86
+ res.statusCode = 200;
87
+ res.setHeader("Content-Type", "text/html");
88
+ const contents = await readFile(join(config.root, opt.template), { encoding: "utf-8" });
89
+ const compiled = compile(file, await readFile(file, { encoding: "utf-8" }));
90
+ res.end(contents.replace(opt.slot, compiled));
91
+ }
92
+ // folder containing pages
93
+ const srcDir = join(config.root, opt.pages);
94
+ // generate actual file path
95
+ let filePath = join(srcDir, req.url + (req.url?.endsWith("/") ? "index.html" : ""));
96
+ // check if the requested html file does not exist
97
+ if (filePath.endsWith(".html") && !existsSync(filePath)) {
98
+ filePath = filePath.replace(".html", ext);
99
+ if (existsSync(filePath)) {
100
+ // print request to the console
101
+ log(req.method?.toUpperCase(), req.url, filePath);
102
+ // send requested file
103
+ return await respond(filePath);
104
+ }
105
+ }
106
+ // try checking if the requested asset exists in the `src` folder
107
+ if (filePath.lastIndexOf(".") > -1) {
108
+ filePath = join(config.root, req.url);
109
+ if (existsSync(filePath)) {
110
+ // direct the file path relative to the `src` folder
111
+ req.url = filePath;
112
+ }
113
+ }
114
+ return next();
115
+ });
116
+ }
117
+ },
118
+ {
119
+ /**
120
+ * Unit.js - Build plugin
121
+ */
122
+ name: "vite-plugin-unit-build",
123
+ /**
124
+ * only apply this plugin on `vite build` command
125
+ */
126
+ apply: "build",
127
+ /**
128
+ * modify vite config in favor of this plugin
129
+ */
130
+ config() {
131
+ return {
132
+ base: "./",
133
+ root: outputDir
134
+ };
135
+ },
136
+ /**
137
+ * function invoked when the build process begins
138
+ */
139
+ async buildStart(options) {
140
+ const output = join(__dirname, outputDir);
141
+ /**
142
+ * Create unit.js compiled output directory
143
+ */
144
+ if (existsSync(output)) {
145
+ rm(output, { recursive: true, force: true });
146
+ }
147
+ await mkdir(outputDir);
148
+ /**
149
+ * Copy entire `src/` to `.unit/`
150
+ */
151
+ await cp("./src/", outputDir, { recursive: true });
152
+ /**
153
+ * Grab the template file
154
+ */
155
+ const templateFile = join(outputDir, opt.template);
156
+ const template = await readFile(templateFile, { encoding: "utf-8" });
157
+ /**
158
+ * Capture the pages
159
+ */
160
+ const srcDir = join(outputDir, "./pages/");
161
+ const srcFiles = await readdir(srcDir, { recursive: true });
162
+ const pages = srcFiles.filter((file) => extname(file) === ext);
163
+ log("pages: ", pages);
164
+ /**
165
+ * Function that generate .html file from compiled .unit file
166
+ */
167
+ async function generateBuild(page) {
168
+ const filePath = join(srcDir, page);
169
+ if (Array.isArray(options.input)) {
170
+ options.input.push(join(outputDir, page.replace(ext, ".html")));
171
+ }
172
+ else {
173
+ // ...
174
+ }
175
+ const fileContent = await readFile(filePath, { encoding: "utf-8" });
176
+ const compiledPage = compile(filePath, fileContent);
177
+ const result = template.replace(opt.template, compiledPage);
178
+ log("build: ", page);
179
+ return await writeFile(join(outputDir, page.replace(ext, ".html")), result);
180
+ }
181
+ /**
182
+ * Clear the input files
183
+ */
184
+ if (options.input.length) {
185
+ options.input.length = 0;
186
+ }
187
+ else {
188
+ options.input = [];
189
+ }
190
+ /**
191
+ * Generate builds, add input files for rollup to resolve dependencies
192
+ */
193
+ await Promise.all(pages.map((page) => generateBuild(page)));
194
+ },
195
+ /**
196
+ * function invoked when the output bundle is complete
197
+ */
198
+ async closeBundle() {
199
+ /**
200
+ * Remove the dist folder if exists
201
+ */
202
+ const distFolder = join(__dirname, "dist");
203
+ if (existsSync(distFolder)) {
204
+ await rm(distFolder, { recursive: true, force: true });
205
+ }
206
+ /**
207
+ * Copy the entire unit dist folder to the root of the project
208
+ */
209
+ await cp(outputDir + "dist", distFolder, { recursive: true });
210
+ // await new Promise((res) => setTimeout(res, 5000));
211
+ /**
212
+ * Delete the entire unit output folder
213
+ */
214
+ await rm(outputDir, { recursive: true, force: true });
215
+ }
216
+ }
217
+ ];
218
+ }
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "vite-plugin-unit",
3
+ "version": "0.0.1",
4
+ "description": "A vite plugin for handling unit.js projects",
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
+ "alpine",
21
+ "ui",
22
+ "browser"
23
+ ],
24
+ "author": {
25
+ "name": "Henry Hale",
26
+ "url": "https://github.com/henryhale"
27
+ },
28
+ "license": "MIT",
29
+ "bugs": {
30
+ "url": "https://github.com/henryhale/vite-plugin-unit/issues"
31
+ },
32
+ "homepage": "https://github.com/henryhale/vite-plugin-unit#readme",
33
+ "type": "module",
34
+ "scripts": {
35
+ "build": "tsc -b",
36
+ "dev": "tsc -w",
37
+ "lint": "eslint --cache --ext .ts source/ && prettier -c source/",
38
+ "lint:fix": "eslint --cache --ext .ts source/ --fix && prettier -c -w source/",
39
+ "prepack": "pnpm build",
40
+ "prepare": "husky install",
41
+ "release": "release-it",
42
+ "test": "echo \"Error: no test specified\""
43
+ },
44
+ "engines": {
45
+ "node": ">=18",
46
+ "pnpm": ">=8"
47
+ },
48
+ "lint-staged": {
49
+ "*.ts": "pnpm lint:fix"
50
+ },
51
+ "prettier": {
52
+ "printWidth": 120,
53
+ "tabWidth": 4,
54
+ "semi": true,
55
+ "singleQuote": false,
56
+ "trailingComma": "none"
57
+ },
58
+ "devDependencies": {
59
+ "@release-it/conventional-changelog": "^8.0.1",
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
+ }
72
+ }