voicss 0.1.4

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 ADDED
@@ -0,0 +1,66 @@
1
+ <div align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/kh4f/vois/refs/heads/assets/logo-dark.png">
4
+ <img alt="logo" src="https://raw.githubusercontent.com/kh4f/vois/refs/heads/assets/logo-light.png">
5
+ </picture>
6
+ <br>
7
+ A lightweight <b>zero-runtime CSS-in-TS</b> toolkit
8
+ <br><br>
9
+ <p>
10
+ <a href="https://www.npmjs.com/package/vois"><img src="https://img.shields.io/npm/v/vois?style=flat-square&logo=npm&label=npm&labelColor=612838&color=D8C8C2" alt="npm version"/></a>&nbsp;
11
+ <a href="https://github.com/kh4f/vois/issues?q=is%3Aissue+is%3Aopen+label%3Abug"><img src="https://img.shields.io/github/issues/kh4f/vois/bug?style=flat-square&label=%F0%9F%90%9B%20Bugs&labelColor=612838&color=D8C8C2" alt="bugs"></a>&nbsp;
12
+ <a href="https://github.com/kh4f/vois/blob/main/LICENSE"><img src="https://img.shields.io/github/license/kh4f/vois?style=flat-square&label=%F0%9F%9B%A1%EF%B8%8F%20License&labelColor=612838&color=D8C8C2" alt="license"></a>&nbsp;
13
+ </p>
14
+ <p><b>
15
+ <a href="#-overview">Overview</a>&nbsp; โ€ข&nbsp;
16
+ <a href="#-quick-start">Quick Start</a>&nbsp; โ€ข&nbsp;
17
+ <a href="#%EF%B8%8F-usage">Usage</a>
18
+ </b></p>
19
+ <img alt="demo" src="https://raw.githubusercontent.com/kh4f/vois/refs/heads/assets/demo.png">
20
+ </div>
21
+
22
+ ## ๐Ÿ‘€ Overview
23
+ **Vois** is a bundler plugin that extracts `` void `css ...` `` blocks from `.ts(x)` files into native CSS.
24
+
25
+ ### ๐Ÿ”ฅ Features
26
+ - **โšก True zero-runtime:** styles are extracted at build time, no JS in production
27
+ - **๐Ÿ’Ž Native CSS:** write standard CSS with all modern features
28
+ - **๐Ÿ“ฆ Modern bundlers:** first-class support for Next.js and Vite
29
+ - **๐Ÿ”ฅ HMR:** instant style updates during development
30
+ - **๐Ÿงฉ [VS Code extension](https://github.com/kh4f/vois-vscode):** syntax highlighting, autocomplete, validation, and more
31
+ - **๐Ÿงน [ESLint plugin](https://github.com/kh4f/vois-eslint):** CSS linting in template literals
32
+
33
+ ## ๐Ÿ Quick Start
34
+ Scaffold a [demo project](templates) for your platform (Next.js/Vite/tsdown):
35
+ ```bash
36
+ bun create vois
37
+ ```
38
+
39
+ ## ๐Ÿ•น๏ธ Usage
40
+ ### Vite
41
+ ```bash
42
+ bun add -D vois
43
+ ```
44
+ ```ts
45
+ // vite.config.ts
46
+ import type { UserConfig } from 'vite'
47
+ import vois from 'vois/vite'
48
+
49
+ export default {
50
+ plugins: [vois()],
51
+ } satisfies UserConfig
52
+ ```
53
+
54
+ ### Next.js
55
+ ```bash
56
+ bun add -D vois
57
+ ```
58
+ ```ts
59
+ // next.config.ts
60
+ import type { NextConfig } from 'next'
61
+ import { voisTurboRule } from 'vois/next'
62
+
63
+ export default {
64
+ turbopack: { rules: { ...voisTurboRule } },
65
+ } satisfies NextConfig
66
+ ```
@@ -0,0 +1,4 @@
1
+ //#region src/index.d.ts
2
+ declare const extractCss: (s: string) => string;
3
+ //#endregion
4
+ export { extractCss };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ //#region src/index.ts
2
+ const extractCss = (s) => [...s.matchAll(/void `css\s(.*?)`/gs)].map((m) => m[1]).join("");
3
+ //#endregion
4
+ export { extractCss };
@@ -0,0 +1,8 @@
1
+ import { NextConfig } from "next";
2
+ //#region src/next.d.ts
3
+ declare const voisTurboRule: Required<Required<NextConfig>['turbopack']>['rules'];
4
+ declare function export_default(this: {
5
+ resourcePath: string;
6
+ }, source: string): string;
7
+ //#endregion
8
+ export { export_default as default, voisTurboRule };
package/dist/next.mjs ADDED
@@ -0,0 +1,23 @@
1
+ import { extractCss } from "./index.mjs";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { dirname, join, relative, resolve } from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ //#region src/next.ts
6
+ const voisTurboRule = { "*": {
7
+ loaders: ["vois/next"],
8
+ condition: { all: [{ not: "foreign" }, { path: /\.(ts|tsx)$/ }] }
9
+ } };
10
+ function next_default(source) {
11
+ const css = extractCss(source);
12
+ if (!css) return source;
13
+ const fileHash = createHash("md5").update(this.resourcePath).digest("hex");
14
+ const cacheDir = resolve("node_modules", ".vois");
15
+ const cssFilePath = join(cacheDir, `${fileHash}.css`);
16
+ mkdirSync(cacheDir, { recursive: true });
17
+ writeFileSync(cssFilePath, css, "utf8");
18
+ let importPath = relative(dirname(this.resourcePath), cssFilePath).replace(/\\/g, "/");
19
+ if (!importPath.startsWith(".")) importPath = `./${importPath}`;
20
+ return source.replace(/^\w/m, `import '${importPath}';\n$&`);
21
+ }
22
+ //#endregion
23
+ export { next_default as default, voisTurboRule };
@@ -0,0 +1,5 @@
1
+ import { Plugin } from "vite";
2
+ //#region src/vite.d.ts
3
+ declare const _default: () => Plugin;
4
+ //#endregion
5
+ export { _default as default };
package/dist/vite.mjs ADDED
@@ -0,0 +1,47 @@
1
+ import { extractCss } from "./index.mjs";
2
+ import MagicString from "magic-string";
3
+ //#region src/vite.ts
4
+ const CSS_EXTRACTABLE_FILES = /\.(ts|tsx)$/;
5
+ const VIRTUAL_PREFIX = "virtual:vois/";
6
+ const RESOLVED_PREFIX = `\0${VIRTUAL_PREFIX}`;
7
+ const styles = /* @__PURE__ */ new Map();
8
+ var vite_default = () => ({
9
+ name: "vois-vite",
10
+ enforce: "pre",
11
+ resolveId(id) {
12
+ if (id.startsWith(VIRTUAL_PREFIX)) return RESOLVED_PREFIX + normalizePath(id.slice(13));
13
+ },
14
+ load(id) {
15
+ if (id.startsWith(RESOLVED_PREFIX)) {
16
+ const cssId = normalizePath(id.slice(RESOLVED_PREFIX.length));
17
+ return styles.get(cssId);
18
+ }
19
+ },
20
+ transform(code, id) {
21
+ if (!CSS_EXTRACTABLE_FILES.test(id)) return;
22
+ const css = extractCss(code);
23
+ if (!css) return;
24
+ const cssId = normalizePath(id + ".css");
25
+ styles.set(cssId, css);
26
+ const s = new MagicString(code);
27
+ s.prepend(`import '${VIRTUAL_PREFIX}${cssId}';`);
28
+ return {
29
+ code: s.toString(),
30
+ map: s.generateMap({ hires: true })
31
+ };
32
+ },
33
+ async handleHotUpdate({ file, server, modules, read }) {
34
+ if (!CSS_EXTRACTABLE_FILES.test(file)) return;
35
+ const sourceCode = await read();
36
+ const css = extractCss(sourceCode);
37
+ if (!css) return;
38
+ const cssId = normalizePath(file + ".css");
39
+ const virtualId = RESOLVED_PREFIX + cssId;
40
+ const mod = server.moduleGraph.getModuleById(virtualId);
41
+ styles.set(cssId, css);
42
+ if (mod) return [...modules, mod];
43
+ }
44
+ });
45
+ const normalizePath = (p) => p.replace(/\\/g, "/");
46
+ //#endregion
47
+ export { vite_default as default };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "voicss",
3
+ "version": "0.1.4",
4
+ "description": "โšก Ultra-Light Compile-Time CSS-in-TS",
5
+ "author": "kh4f",
6
+ "license": "MIT",
7
+ "repository": "https://github.com/kh4f/voicss",
8
+ "homepage": "https://github.com/kh4f/voicss",
9
+ "bugs": "https://github.com/kh4f/voicss/issues",
10
+ "keywords": ["css-in-ts", "compile-time-css", "zero-runtime-css", "vite-plugin", "next-plugin"],
11
+ "files": ["dist", "README.md"],
12
+ "exports": {
13
+ ".": { "import": "./dist/index.mjs", "types": "./dist/index.d.mts" },
14
+ "./vite": { "import": "./dist/vite.mjs", "types": "./dist/vite.d.mts" },
15
+ "./next": { "default": "./dist/next.mjs", "types": "./dist/next.d.mts" }
16
+ },
17
+ "scripts": {
18
+ "build": "tsdown src/{index,vite,next}.ts",
19
+ "lint": "tsc && eslint",
20
+ "prepack": "cp ../../README.md .",
21
+ "postpack": "rm README.md"
22
+ },
23
+ "dependencies": {
24
+ "magic-string": "^1.2.3"
25
+ },
26
+ "peerDependencies": {
27
+ "next": "^16",
28
+ "vite": "^8"
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "next": { "optional": true },
32
+ "vite": { "optional": true }
33
+ },
34
+ "devDependencies": {
35
+ "next": "^16.3.4",
36
+ "vite": "^8.0.16"
37
+ }
38
+ }