vite-elysia-forge 0.0.7 → 0.0.9

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
@@ -1,43 +1,40 @@
1
1
  # vite-elysia-forge
2
2
 
3
- <svg width="200" height="120" viewBox="0 0 200 120" xmlns="http://www.w3.org/2000/svg">
4
- <!-- Vite logo representation -->
5
- <defs>
6
- <linearGradient id="viteGradient" x1="0%" y1="0%" x2="100%" y2="100%">
7
- <stop offset="0%" style="stop-color:#646cff;stop-opacity:1" />
8
- <stop offset="100%" style="stop-color:#535bf2;stop-opacity:1" />
9
- </linearGradient>
10
- </defs>
11
-
12
- <!-- Vite symbol -->
13
- <polygon points="50,20 70,60 50,100 30,60" fill="url(#viteGradient)" />
14
-
15
- <!-- Arrow connecting to Elysia -->
16
- <line x1="80" y1="60" x2="120" y2="60" stroke="#646cff" stroke-width="3" marker-end="url(#arrowhead)" />
17
- <defs>
18
- <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
19
- <polygon points="0 0, 10 3, 0 6" fill="#646cff" />
20
- </marker>
21
- </defs>
22
-
23
- <!-- Elysia symbol (simplified) -->
24
- <circle cx="150" cy="30" r="15" fill="#e0db55" />
25
- <circle cx="150" cy="90" r="15" fill="#e0db55" />
26
- <rect x="135" y="50" width="30" height="20" fill="#e0db55" />
27
- </svg>
28
-
29
- Vite middleware plugin that hot-reloads an Elysia API module and forwards `/api` requests to it during local development.
30
-
31
- ## Installation
3
+ <p align="center">
4
+ <img src="https://vitejs.dev/logo.svg" alt="Vite" width="60" height="60" />
5
+ <img src="https://elysiajs.com/assets/elysia.svg" alt="Elysia" width="60" height="60" />
6
+ <img src="https://bun.sh/logo.svg" alt="Bun" width="60" height="60" />
7
+ </p>
8
+
9
+ A [Vite](https://vite.dev/) middleware plugin that hot-reloads an [Elysia](https://elysiajs.com/) API module and forwards `/api` requests to it during local development. Powered by [Bun](https://bun.sh/).
10
+
11
+ ## 1. Installation
32
12
 
33
13
  ```bash
34
- bun install
14
+ bun install vite-elysia-forge
15
+ ```
16
+
17
+ ## 2. Quick Start
18
+
19
+ ### 2.1 Create Your API Handler
20
+
21
+ Place your Elysia handler at `src/server/api.ts` (default path):
22
+
23
+ ```ts
24
+ import { Elysia } from "elysia";
25
+
26
+ export const api = new Elysia({
27
+ prefix: "/api",
28
+ });
29
+
30
+ api.get("/", () => "hello from elysia");
31
+
32
+ export default api;
35
33
  ```
36
34
 
37
- ## Quick Start
35
+ ### 2.2 Configure Vite
38
36
 
39
- 1. Place your Elysia handler at `src/server/api.ts` (default path).
40
- 2. In your Vite config, register the plugin:
37
+ Register the plugin in your Vite config:
41
38
 
42
39
  ```ts
43
40
  import { defineConfig } from "vite";
@@ -46,85 +43,158 @@ import elysiaPlugin from "vite-elysia-forge";
46
43
  export default defineConfig({
47
44
  plugins: [
48
45
  elysiaPlugin({
49
- serverFile: "/server/api.ts",
46
+ serverFile: "./src/server/api.ts",
50
47
  }),
51
48
  ],
52
49
  });
53
50
  ```
54
51
 
55
- 3. Run Vite as usual, and hit `/api/*` routes. The plugin will reload the Elysia module when the file changes.
52
+ ### 2.3 Start Development
56
53
 
57
- ## Starting the App
58
-
59
- To build and start the app:
54
+ Run Vite as usual and access your API at `/api/*` routes. The plugin will automatically reload the Elysia module when files change.
60
55
 
61
56
  ```bash
62
- bun run build
63
- bun start
57
+ bun run dev
64
58
  ```
65
59
 
66
- `bun run build` compiles the plugin for production, and `bun start` runs the built application.
60
+ ## 3. Configuration Options
61
+
62
+ ### 3.1 Plugin Options
67
63
 
68
- ## Configuration
64
+ ```ts
65
+ elysiaPlugin({
66
+ // Path to your Elysia API module (relative to project root)
67
+ serverFile?: string; // default: "/server/api.ts"
68
+ })
69
+ ```
69
70
 
70
- | Option | Type | Default | Description |
71
- | ------------ | ------ | ------------ | ------------------------------------------------------- |
72
- | `serverURL` | string | `"/server/"` | URL prefix to your API module (leading slash required). |
73
- | `serverFile` | string | `"api.ts"` | Filename of the Elysia module to load and hot-reload. |
71
+ ## 4. API Module Requirements
74
72
 
75
- ## Expectations for the API module
73
+ Your API module must export an Elysia instance with a `handle(request: Request) => Promise<Response>` method.
76
74
 
77
- Your API module should export `api` with a `handle(request: Request) => Promise<Response>` signature.
75
+ ### 4.1 Basic Example
78
76
 
79
77
  ```ts
78
+ import { Elysia } from "elysia";
79
+
80
80
  export const api = new Elysia({
81
81
  prefix: "/api",
82
82
  });
83
83
 
84
84
  api.get("/", () => "hello from elysia");
85
+ api.get("/users", () => ["user1", "user2"]);
85
86
 
86
87
  export default api;
87
88
  ```
88
89
 
89
- ## Production Usage
90
+ ## 5. Integration with @elysiajs/openapi
90
91
 
91
- When building for production, you need to build both the Vite frontend and the Elysia backend. This package provides a CLI to handle this for you.
92
+ To use the [@elysiajs/openapi plugin](https://elysiajs.com/patterns/openapi), add the following to your `tsconfig.json`:
92
93
 
93
- 1. Update your `package.json` build script:
94
+ ```json
95
+ {
96
+ "compilerOptions": {
97
+ "types": ["bun-types"],
98
+ "typeRoots": ["node_modules"]
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### 5.1 Example with `fromTypes`
104
+
105
+ It is recommended to pre-generate the declaration file (`.d.ts`) to provide type declaration to the generator.
106
+
107
+ ```ts
108
+ import { Elysia, t } from "elysia";
109
+ import { openapi, fromTypes } from "@elysiajs/openapi";
110
+
111
+ const app = new Elysia().use(
112
+ openapi({
113
+ references: fromTypes("server/api"),
114
+ })
115
+ );
116
+ ```
117
+
118
+ ## 6. Production Deployment
119
+
120
+ ### 6.1 Build Configuration
121
+
122
+ Update your `package.json` scripts:
94
123
 
95
124
  ```json
96
125
  {
97
126
  "scripts": {
127
+ "dev": "vite",
98
128
  "build": "vite-elysia-forge build",
99
129
  "start": "bun dist/server.js"
100
130
  }
101
131
  }
102
132
  ```
103
133
 
104
- 2. Run the build:
134
+ If your API is located elsewhere, specify the path:
135
+
136
+ ```bash
137
+ vite-elysia-forge build src/my-api.ts
138
+ ```
139
+
140
+ ### 6.2 Building for Production
141
+
142
+ Run the build command:
105
143
 
106
144
  ```bash
107
145
  bun run build
108
146
  ```
109
147
 
110
- This will:
148
+ This command performs the following steps:
149
+
150
+ 1. Runs `vite build` to compile your frontend to `dist/`
151
+ 2. Automatically generates a temporary entry file that imports your API from `src/server/api.ts`
152
+ 3. Bundles the server into a single file at `dist/server.js`
111
153
 
112
- 1. Run `vite build` to compile your frontend to `dist/`.
113
- 2. Automatically generate a temporary entry file that imports your API from `src/server/api.ts` (default).
114
- 3. Bundle the server into a single file at `dist/server.js`.
154
+ ### 6.3 Starting the Production Server
115
155
 
116
- If your API is located elsewhere, you can specify the path:
156
+ Start the server with:
117
157
 
118
158
  ```bash
119
- vite-elysia-forge build src/my-api.ts
159
+ bun start
120
160
  ```
121
161
 
122
- 3. Start the server:
162
+ ## 7. Troubleshooting
163
+
164
+ ### 7.1 "Bun is not defined" Error
165
+
166
+ If you encounter this error, ensure you are running Vite with the Bun runtime:
123
167
 
124
168
  ```bash
125
- bun start
169
+ bunx --bun vite
170
+ ```
171
+
172
+ Or update your `dev` script in `package.json`:
173
+
174
+ ```json
175
+ "scripts": {
176
+ "dev": "bunx --bun vite"
177
+ }
126
178
  ```
127
179
 
128
- ## Authors
180
+ **Benefits:**
181
+
182
+ - **Access to Bun APIs:** You can use `Bun.file`, `Bun.env`, `bun:sqlite`, and other native Bun features directly in your server code.
183
+ - **Performance:** Vite often starts faster and uses less memory when running under Bun.
184
+
185
+ **Caveats:**
186
+
187
+ - **Node.js Compatibility:** While Bun has excellent Node.js compatibility, some Vite plugins that rely on obscure Node.js internals might behave unexpectedly.
188
+ - **Performance:** Running Vite under Bun is generally faster, but you might encounter edge cases where optimization differs from Node.js.
189
+
190
+ ### 7.2 Hot Reload Not Working
191
+
192
+ Check that your file changes are within the dependency graph of your API module. The plugin uses Vite's dependency tracking to determine when to reload.
193
+
194
+ ## 8. Authors
129
195
 
130
196
  - Chijioke Udokporo ([@chijiokeudokporo](https://github.com/chijioke-udokporo))
197
+
198
+ ## 9. License
199
+
200
+ MIT
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var path=require('path');function M({serverFile:g="/server/api.ts"}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=path.resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=M;
1
+ 'use strict';var path=require('path');function E({serverFile:g="/server/api.ts"}={}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=path.resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=E;
2
2
  module.exports=P;
package/dist/index.d.cts CHANGED
@@ -20,6 +20,6 @@ interface ConfigOptions {
20
20
  * @param options - Configuration options for the plugin.
21
21
  * @returns A Vite plugin instance.
22
22
  */
23
- declare function elysiaPlugin({ serverFile }: ConfigOptions): Plugin;
23
+ declare function elysiaPlugin({ serverFile }?: ConfigOptions): Plugin;
24
24
 
25
25
  export { type ConfigOptions, elysiaPlugin as default };
package/dist/index.d.ts CHANGED
@@ -20,6 +20,6 @@ interface ConfigOptions {
20
20
  * @param options - Configuration options for the plugin.
21
21
  * @returns A Vite plugin instance.
22
22
  */
23
- declare function elysiaPlugin({ serverFile }: ConfigOptions): Plugin;
23
+ declare function elysiaPlugin({ serverFile }?: ConfigOptions): Plugin;
24
24
 
25
25
  export { type ConfigOptions, elysiaPlugin as default };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {resolve}from'path';function M({serverFile:g="/server/api.ts"}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=M;
1
+ import {resolve}from'path';function E({serverFile:g="/server/api.ts"}={}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=E;
2
2
  export{P as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-elysia-forge",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "A Vite plugin to seamlessly integrate ElysiaJS for full-stack development with Bun runtime.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -13,7 +13,7 @@
13
13
  "author": "chijioke-udokporo",
14
14
  "private": false,
15
15
  "scripts": {
16
- "build": "bun run test && tsup",
16
+ "build": "rm -rf dist &&bun run test && tsup",
17
17
  "test": "bun test"
18
18
  },
19
19
  "dependencies": {},