cajoa 0.9.0 → 0.10.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 CHANGED
@@ -30,22 +30,24 @@ Or add Cajoa to an existing project:
30
30
  npm install cajoa
31
31
  ```
32
32
 
33
- ### Manual JSX setup
33
+ ### Manual setup
34
34
 
35
- In your `tsconfig.json`:
35
+ Add the plugin to `vite.config.ts`:
36
+
37
+ ```ts
38
+ import { defineConfig } from "vite";
39
+ import { cajoa } from "cajoa/vite";
40
+
41
+ export default defineConfig({ plugins: [cajoa()] });
42
+ ```
43
+
44
+ And set the JSX types in `tsconfig.json`:
36
45
 
37
46
  ```json
38
- {
39
- "compilerOptions": {
40
- "jsx": "react-jsx",
41
- "jsxImportSource": "cajoa"
42
- }
43
- }
47
+ { "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "cajoa" } }
44
48
  ```
45
49
 
46
- With Vite, also set it in `vite.config.ts`
47
- (`oxc: { jsx: { runtime: "automatic", importSource: "cajoa" } }` on newer Vite,
48
- or `esbuild: { jsx: "automatic", jsxImportSource: "cajoa" }` on older ones).
50
+ The plugin also sets Vite's JSX transform for you. Without the plugin, set `oxc: { jsx: { runtime: "automatic", importSource: "cajoa" } }` (Vite 8) or `esbuild: { jsx: "automatic", jsxImportSource: "cajoa" }` (older Vite) yourself.
49
51
 
50
52
  ## Quick start
51
53
 
@@ -65,16 +67,33 @@ function Counter() {
65
67
  render(Counter, document.getElementById("app")!);
66
68
  ```
67
69
 
68
- ## Two rules to remember
70
+ ## Reactive JSX
71
+
72
+ With the Vite plugin, write plain JSX. Calls to signals are reactive wherever they appear in a DOM element, and `Show` children are created lazily:
73
+
74
+ ```tsx
75
+ <p>Double: {count() * 2}</p>
76
+ <p class={count() % 2 ? "odd" : "even"} style={{ color: color() }}>…</p>
77
+
78
+ <Show when={count() > 3} fallback={<p>Keep clicking</p>}>
79
+ <p>More than 3!</p>
80
+ </Show>
81
+
82
+ <For each={todos()}>{(todo) => <li>{todo.text}</li>}</For>
83
+ ```
84
+
85
+ The plugin rewrites your JSX at build time. When an expression contains a function call, it wraps it in a function (`{count() * 2}` becomes `{() => (count() * 2)}`) for:
86
+
87
+ - children and attributes of DOM elements (but not `ref`, `key` and `on*` props)
88
+ - children of your own components
89
+ - `when` and `each` of `Show` and `For`, and the `fallback` and children of `Show`
90
+
91
+ It does **not** change the props of your own components. They receive plain values. To pass a live value, pass the signal itself (`<Greeting name={name} />`) or a function.
69
92
 
70
- Cajoa has no compiler yet, so JSX expressions run exactly once. That gives two rules:
93
+ Without the plugin, two rules apply:
71
94
 
72
- 1. **Pass the signal, don't call it.**
73
- `{count}` is reactive. `{count()}` is read once and never updates.
74
- For computed values, pass a function: `{() => count() * 2}`.
75
- 2. **`Show` children are a function.**
76
- `<Show when={on}>{() => <p>Hello</p>}</Show>`
77
- Otherwise the element is created even when it is hidden.
95
+ 1. **Pass the signal, don't call it.** `{count}` is reactive, `{count()}` is read once. For computed values, pass a function: `{() => count() * 2}`.
96
+ 2. **`Show` children are a function:** `<Show when={on}>{() => <p>Hello</p>}</Show>`.
78
97
 
79
98
  ## Lists and conditions
80
99
 
@@ -255,6 +274,7 @@ Routes are matched in order, so put `path="*"` last.
255
274
  - `set` calls are not batched automatically inside event handlers. Wrap them in `batch()`.
256
275
  - Types in the core use a loose `HostNode` type for now.
257
276
  - Inside `<svg>`, the tags `<a>`, `<title>`, `<style>` and `<script>` are created as HTML elements (they share their names with HTML tags).
277
+ - The compiler works on `.tsx` and `.jsx` files in Vite projects. `Show` and `For` are recognised only when imported from `cajoa` or `@cajoa/core`.
258
278
 
259
279
  ## Roadmap
260
280
 
@@ -266,8 +286,8 @@ Routes are matched in order, so put `path="*"` last.
266
286
  - [x] Renderer abstraction, split into packages
267
287
  - [x] Automated releases
268
288
  - [x] Form, style and event handling in the DOM renderer
269
- - [ ] SVG and `ref` support
270
- - [ ] Vite plugin (removes the two rules above)
289
+ - [x] SVG and `ref` support
290
+ - [x] Vite plugin (removes the two rules above)
271
291
  - [ ] Better form and style handling in the DOM renderer
272
292
  - [ ] Native renderers (mobile, desktop)
273
293
  - [ ] SSR
package/dist/vite.cjs ADDED
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
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
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/vite.ts
31
+ var vite_exports = {};
32
+ __export(vite_exports, {
33
+ cajoa: () => cajoa
34
+ });
35
+ module.exports = __toCommonJS(vite_exports);
36
+ var import_vite = require("vite");
37
+
38
+ // src/compiler.ts
39
+ var import_parser = require("@babel/parser");
40
+ var import_magic_string = __toESM(require("magic-string"), 1);
41
+ var CORE_MODULES = /* @__PURE__ */ new Set(["cajoa", "@cajoa/core"]);
42
+ var SKIP_KEYS = /* @__PURE__ */ new Set([
43
+ "loc",
44
+ "extra",
45
+ "leadingComments",
46
+ "trailingComments",
47
+ "innerComments"
48
+ ]);
49
+ var CALL_TYPES = /* @__PURE__ */ new Set([
50
+ "CallExpression",
51
+ "OptionalCallExpression",
52
+ "TaggedTemplateExpression"
53
+ ]);
54
+ var STOP_TYPES = /* @__PURE__ */ new Set([
55
+ "ArrowFunctionExpression",
56
+ "FunctionExpression",
57
+ "FunctionDeclaration",
58
+ "ObjectMethod",
59
+ "ClassMethod",
60
+ "ClassPrivateMethod",
61
+ "JSXElement",
62
+ "JSXFragment"
63
+ ]);
64
+ var PASS_THROUGH = /* @__PURE__ */ new Set([
65
+ "ArrowFunctionExpression",
66
+ "FunctionExpression",
67
+ "Identifier",
68
+ "MemberExpression",
69
+ "OptionalMemberExpression"
70
+ ]);
71
+ function isNode(value) {
72
+ return typeof value === "object" && value !== null && typeof value.type === "string";
73
+ }
74
+ function childNodes(node) {
75
+ const out = [];
76
+ for (const key of Object.keys(node)) {
77
+ if (SKIP_KEYS.has(key)) continue;
78
+ const value = node[key];
79
+ if (Array.isArray(value)) {
80
+ for (const item of value) if (isNode(item)) out.push(item);
81
+ } else if (isNode(value)) {
82
+ out.push(value);
83
+ }
84
+ }
85
+ return out;
86
+ }
87
+ function containsCall(node) {
88
+ if (CALL_TYPES.has(node.type)) return true;
89
+ if (STOP_TYPES.has(node.type)) return false;
90
+ return childNodes(node).some(containsCall);
91
+ }
92
+ function exprOf(node) {
93
+ if (!node || node.type !== "JSXExpressionContainer") return null;
94
+ return node.expression.type === "JSXEmptyExpression" ? null : node.expression;
95
+ }
96
+ function collectControls(program) {
97
+ const controls = /* @__PURE__ */ new Map();
98
+ for (const node of program.body) {
99
+ if (node.type !== "ImportDeclaration" || !CORE_MODULES.has(node.source.value))
100
+ continue;
101
+ for (const spec of node.specifiers) {
102
+ if (spec.type !== "ImportSpecifier") continue;
103
+ const imported = spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value;
104
+ if (imported === "Show" || imported === "For")
105
+ controls.set(spec.local.name, imported);
106
+ }
107
+ }
108
+ return controls;
109
+ }
110
+ function transformJsx(code, id) {
111
+ const file = id.split("?")[0];
112
+ if (!/\.[jt]sx$/.test(file) || /[\\/]node_modules[\\/]/.test(file))
113
+ return null;
114
+ if (!code.includes("<")) return null;
115
+ let ast;
116
+ try {
117
+ ast = (0, import_parser.parse)(code, {
118
+ sourceType: "module",
119
+ plugins: file.endsWith(".tsx") ? ["jsx", "typescript"] : ["jsx"]
120
+ });
121
+ } catch {
122
+ return null;
123
+ }
124
+ const controls = collectControls(ast.program);
125
+ const s = new import_magic_string.default(code);
126
+ let changed = false;
127
+ const wrap = (expr) => {
128
+ s.prependRight(expr.start, "() => (");
129
+ s.appendLeft(expr.end, ")");
130
+ changed = true;
131
+ };
132
+ const wrapChildren = (parent) => {
133
+ for (const kid of parent.children) {
134
+ const expr = exprOf(kid);
135
+ if (expr && containsCall(expr)) wrap(expr);
136
+ }
137
+ };
138
+ const wrapShowChildren = (el) => {
139
+ const kids = el.children.filter(
140
+ (k) => !(k.type === "JSXText" && k.value.trim() === "") && !(k.type === "JSXExpressionContainer" && k.expression.type === "JSXEmptyExpression")
141
+ );
142
+ if (kids.length === 0) return;
143
+ if (kids.length === 1) {
144
+ const only = kids[0];
145
+ if (only.type === "JSXElement" || only.type === "JSXFragment") {
146
+ s.prependRight(only.start, "{() => (");
147
+ s.appendLeft(only.end, ")}");
148
+ changed = true;
149
+ return;
150
+ }
151
+ const expr = exprOf(only);
152
+ if (expr) {
153
+ if (!PASS_THROUGH.has(expr.type)) wrap(expr);
154
+ return;
155
+ }
156
+ }
157
+ s.prependRight(kids[0].start, "{() => (<>");
158
+ s.appendLeft(kids[kids.length - 1].end, "</>)}");
159
+ changed = true;
160
+ wrapChildren(el);
161
+ };
162
+ const handleElement = (el) => {
163
+ const nameNode = el.openingElement.name;
164
+ const name = nameNode.type === "JSXIdentifier" ? nameNode.name : null;
165
+ const isHost = name !== null && /^[a-z]/.test(name);
166
+ const control = name !== null && !isHost ? controls.get(name) : void 0;
167
+ for (const attr of el.openingElement.attributes) {
168
+ if (attr.type !== "JSXAttribute" || attr.name.type !== "JSXIdentifier")
169
+ continue;
170
+ const expr = exprOf(attr.value);
171
+ if (!expr) continue;
172
+ const prop = attr.name.name;
173
+ if (isHost) {
174
+ if (prop === "ref" || prop === "key" || prop.startsWith("on")) continue;
175
+ if (containsCall(expr)) wrap(expr);
176
+ } else if (control === "Show") {
177
+ if (prop === "when" && containsCall(expr)) wrap(expr);
178
+ else if (prop === "fallback" && !PASS_THROUGH.has(expr.type))
179
+ wrap(expr);
180
+ } else if (control === "For") {
181
+ if (prop === "each" && containsCall(expr)) wrap(expr);
182
+ }
183
+ }
184
+ if (control === "Show") wrapShowChildren(el);
185
+ else if (control !== "For") wrapChildren(el);
186
+ };
187
+ const visit = (node) => {
188
+ if (node.type === "JSXElement") handleElement(node);
189
+ else if (node.type === "JSXFragment") wrapChildren(node);
190
+ for (const child of childNodes(node)) visit(child);
191
+ };
192
+ visit(ast.program);
193
+ if (!changed) return null;
194
+ return {
195
+ code: s.toString(),
196
+ map: s.generateMap({ hires: true, source: file, includeContent: true })
197
+ };
198
+ }
199
+
200
+ // src/vite.ts
201
+ function cajoa(options = {}) {
202
+ const importSource = options.importSource ?? "cajoa";
203
+ return {
204
+ name: "cajoa",
205
+ enforce: "pre",
206
+ config() {
207
+ const major = Number.parseInt(import_vite.version, 10);
208
+ return major >= 8 ? { oxc: { jsx: { runtime: "automatic", importSource } } } : { esbuild: { jsx: "automatic", jsxImportSource: importSource } };
209
+ },
210
+ transform(code, id) {
211
+ const result = transformJsx(code, id);
212
+ return result ? { code: result.code, map: result.map } : null;
213
+ }
214
+ };
215
+ }
216
+ // Annotate the CommonJS export names for ESM import in node:
217
+ 0 && (module.exports = {
218
+ cajoa
219
+ });
@@ -0,0 +1,9 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface CajoaPluginOptions {
4
+ importSource?: string;
5
+ }
6
+ declare function cajoa(options?: CajoaPluginOptions): Plugin;
7
+
8
+ export { cajoa };
9
+ export type { CajoaPluginOptions };
package/dist/vite.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface CajoaPluginOptions {
4
+ importSource?: string;
5
+ }
6
+ declare function cajoa(options?: CajoaPluginOptions): Plugin;
7
+
8
+ export { cajoa };
9
+ export type { CajoaPluginOptions };
package/dist/vite.js ADDED
@@ -0,0 +1,184 @@
1
+ // src/vite.ts
2
+ import { version } from "vite";
3
+
4
+ // src/compiler.ts
5
+ import { parse } from "@babel/parser";
6
+ import MagicString from "magic-string";
7
+ var CORE_MODULES = /* @__PURE__ */ new Set(["cajoa", "@cajoa/core"]);
8
+ var SKIP_KEYS = /* @__PURE__ */ new Set([
9
+ "loc",
10
+ "extra",
11
+ "leadingComments",
12
+ "trailingComments",
13
+ "innerComments"
14
+ ]);
15
+ var CALL_TYPES = /* @__PURE__ */ new Set([
16
+ "CallExpression",
17
+ "OptionalCallExpression",
18
+ "TaggedTemplateExpression"
19
+ ]);
20
+ var STOP_TYPES = /* @__PURE__ */ new Set([
21
+ "ArrowFunctionExpression",
22
+ "FunctionExpression",
23
+ "FunctionDeclaration",
24
+ "ObjectMethod",
25
+ "ClassMethod",
26
+ "ClassPrivateMethod",
27
+ "JSXElement",
28
+ "JSXFragment"
29
+ ]);
30
+ var PASS_THROUGH = /* @__PURE__ */ new Set([
31
+ "ArrowFunctionExpression",
32
+ "FunctionExpression",
33
+ "Identifier",
34
+ "MemberExpression",
35
+ "OptionalMemberExpression"
36
+ ]);
37
+ function isNode(value) {
38
+ return typeof value === "object" && value !== null && typeof value.type === "string";
39
+ }
40
+ function childNodes(node) {
41
+ const out = [];
42
+ for (const key of Object.keys(node)) {
43
+ if (SKIP_KEYS.has(key)) continue;
44
+ const value = node[key];
45
+ if (Array.isArray(value)) {
46
+ for (const item of value) if (isNode(item)) out.push(item);
47
+ } else if (isNode(value)) {
48
+ out.push(value);
49
+ }
50
+ }
51
+ return out;
52
+ }
53
+ function containsCall(node) {
54
+ if (CALL_TYPES.has(node.type)) return true;
55
+ if (STOP_TYPES.has(node.type)) return false;
56
+ return childNodes(node).some(containsCall);
57
+ }
58
+ function exprOf(node) {
59
+ if (!node || node.type !== "JSXExpressionContainer") return null;
60
+ return node.expression.type === "JSXEmptyExpression" ? null : node.expression;
61
+ }
62
+ function collectControls(program) {
63
+ const controls = /* @__PURE__ */ new Map();
64
+ for (const node of program.body) {
65
+ if (node.type !== "ImportDeclaration" || !CORE_MODULES.has(node.source.value))
66
+ continue;
67
+ for (const spec of node.specifiers) {
68
+ if (spec.type !== "ImportSpecifier") continue;
69
+ const imported = spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value;
70
+ if (imported === "Show" || imported === "For")
71
+ controls.set(spec.local.name, imported);
72
+ }
73
+ }
74
+ return controls;
75
+ }
76
+ function transformJsx(code, id) {
77
+ const file = id.split("?")[0];
78
+ if (!/\.[jt]sx$/.test(file) || /[\\/]node_modules[\\/]/.test(file))
79
+ return null;
80
+ if (!code.includes("<")) return null;
81
+ let ast;
82
+ try {
83
+ ast = parse(code, {
84
+ sourceType: "module",
85
+ plugins: file.endsWith(".tsx") ? ["jsx", "typescript"] : ["jsx"]
86
+ });
87
+ } catch {
88
+ return null;
89
+ }
90
+ const controls = collectControls(ast.program);
91
+ const s = new MagicString(code);
92
+ let changed = false;
93
+ const wrap = (expr) => {
94
+ s.prependRight(expr.start, "() => (");
95
+ s.appendLeft(expr.end, ")");
96
+ changed = true;
97
+ };
98
+ const wrapChildren = (parent) => {
99
+ for (const kid of parent.children) {
100
+ const expr = exprOf(kid);
101
+ if (expr && containsCall(expr)) wrap(expr);
102
+ }
103
+ };
104
+ const wrapShowChildren = (el) => {
105
+ const kids = el.children.filter(
106
+ (k) => !(k.type === "JSXText" && k.value.trim() === "") && !(k.type === "JSXExpressionContainer" && k.expression.type === "JSXEmptyExpression")
107
+ );
108
+ if (kids.length === 0) return;
109
+ if (kids.length === 1) {
110
+ const only = kids[0];
111
+ if (only.type === "JSXElement" || only.type === "JSXFragment") {
112
+ s.prependRight(only.start, "{() => (");
113
+ s.appendLeft(only.end, ")}");
114
+ changed = true;
115
+ return;
116
+ }
117
+ const expr = exprOf(only);
118
+ if (expr) {
119
+ if (!PASS_THROUGH.has(expr.type)) wrap(expr);
120
+ return;
121
+ }
122
+ }
123
+ s.prependRight(kids[0].start, "{() => (<>");
124
+ s.appendLeft(kids[kids.length - 1].end, "</>)}");
125
+ changed = true;
126
+ wrapChildren(el);
127
+ };
128
+ const handleElement = (el) => {
129
+ const nameNode = el.openingElement.name;
130
+ const name = nameNode.type === "JSXIdentifier" ? nameNode.name : null;
131
+ const isHost = name !== null && /^[a-z]/.test(name);
132
+ const control = name !== null && !isHost ? controls.get(name) : void 0;
133
+ for (const attr of el.openingElement.attributes) {
134
+ if (attr.type !== "JSXAttribute" || attr.name.type !== "JSXIdentifier")
135
+ continue;
136
+ const expr = exprOf(attr.value);
137
+ if (!expr) continue;
138
+ const prop = attr.name.name;
139
+ if (isHost) {
140
+ if (prop === "ref" || prop === "key" || prop.startsWith("on")) continue;
141
+ if (containsCall(expr)) wrap(expr);
142
+ } else if (control === "Show") {
143
+ if (prop === "when" && containsCall(expr)) wrap(expr);
144
+ else if (prop === "fallback" && !PASS_THROUGH.has(expr.type))
145
+ wrap(expr);
146
+ } else if (control === "For") {
147
+ if (prop === "each" && containsCall(expr)) wrap(expr);
148
+ }
149
+ }
150
+ if (control === "Show") wrapShowChildren(el);
151
+ else if (control !== "For") wrapChildren(el);
152
+ };
153
+ const visit = (node) => {
154
+ if (node.type === "JSXElement") handleElement(node);
155
+ else if (node.type === "JSXFragment") wrapChildren(node);
156
+ for (const child of childNodes(node)) visit(child);
157
+ };
158
+ visit(ast.program);
159
+ if (!changed) return null;
160
+ return {
161
+ code: s.toString(),
162
+ map: s.generateMap({ hires: true, source: file, includeContent: true })
163
+ };
164
+ }
165
+
166
+ // src/vite.ts
167
+ function cajoa(options = {}) {
168
+ const importSource = options.importSource ?? "cajoa";
169
+ return {
170
+ name: "cajoa",
171
+ enforce: "pre",
172
+ config() {
173
+ const major = Number.parseInt(version, 10);
174
+ return major >= 8 ? { oxc: { jsx: { runtime: "automatic", importSource } } } : { esbuild: { jsx: "automatic", jsxImportSource: importSource } };
175
+ },
176
+ transform(code, id) {
177
+ const result = transformJsx(code, id);
178
+ return result ? { code: result.code, map: result.map } : null;
179
+ }
180
+ };
181
+ }
182
+ export {
183
+ cajoa
184
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cajoa",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "A small, beginner-friendly frontend framework built on signals and JSX.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -35,6 +35,16 @@
35
35
  "require": {
36
36
  "types": "./dist/index.d.cts",
37
37
  "default": "./dist/index.cjs"
38
+ },
39
+ "./vite": {
40
+ "import": {
41
+ "types": "./dist/vite.d.ts",
42
+ "default": "./dist/vite.js"
43
+ },
44
+ "require": {
45
+ "types": "./dist/vite.d.cts",
46
+ "default": "./dist/vite.cjs"
47
+ }
38
48
  }
39
49
  }
40
50
  },
@@ -45,6 +55,9 @@
45
55
  ],
46
56
  "jsx-dev-runtime": [
47
57
  "./dist/index.d.ts"
58
+ ],
59
+ "vite": [
60
+ "./dist/vite.d.ts"
48
61
  ]
49
62
  }
50
63
  },
@@ -56,11 +69,21 @@
56
69
  ],
57
70
  "sideEffects": true,
58
71
  "dependencies": {
59
- "@cajoa/core": "^0.9.0",
60
- "@cajoa/dom": "^0.9.0"
72
+ "@babel/parser": "^8.0.7",
73
+ "@cajoa/core": "^0.10.0",
74
+ "@cajoa/dom": "^0.10.0",
75
+ "magic-string": "^0.30.21"
76
+ },
77
+ "peerDependencies": {
78
+ "vite": ">=5.0.0"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "vite": {
82
+ "optional": true
83
+ }
61
84
  },
62
85
  "scripts": {
63
- "build": "tsup src/index.ts --format esm,cjs --dts --clean",
86
+ "build": "tsup src/index.ts src/vite.ts --format esm,cjs --dts --clean",
64
87
  "check:package": "publint && attw --pack ."
65
88
  },
66
89
  "repository": {