vaderjs 1.5.0 → 1.5.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.
@@ -1,337 +1,378 @@
1
- #!/usr/bin/env bun
2
-
3
- import ansiColors from 'ansi-colors'
4
- import { Glob } from 'bun'
5
- const args = Bun.argv.slice(2)
6
- import fs from 'fs'
7
- import path from 'path'
8
- if (!fs.existsSync(process.cwd() + '/app')) {
9
- console.error(`App directory not found in ${process.cwd()}/app`)
10
- process.exit(1)
11
- }
12
- if (!fs.existsSync(process.cwd() + '/public')) {
13
- fs.mkdirSync(process.cwd() + '/public')
14
- }
15
- const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : null
16
- if (!mode) {
17
- console.log(`
18
- Usage:
19
- bun vaderjs dev - Start development server output in dist/
20
- bun vaderjs prod - Build for production output in dist/
21
- `)
22
- process.exit(1)
23
- }
24
-
25
- console.log(
26
- `VaderJS - v${require(process.cwd() + '/node_modules/vaderjs/package.json').version} 🚀
27
- Mode: ${mode}
28
- SSR: ${require(process.cwd() + '/config').default.ssr ? 'Enabled' : 'Disabled'}
29
- PORT: ${require(process.cwd() + '/config').default.port || 8080}
30
- `
31
- )
32
-
33
- let start = Date.now()
34
- console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
35
- let { port, host, host_provider } = require(process.cwd() + '/config').default
36
- if (host_provider === 'apache' && mode === 'development') {
37
- console.warn('Note: SSR will not work with Apache')
38
- }
39
- if (!fs.existsSync(process.cwd() + '/jsconfig.json')) {
40
- let json = {
41
- "compilerOptions": {
42
- "jsx": "react",
43
- "jsxFactory": "e",
44
- "jsxFragmentFactory": "Fragment",
45
- }
46
- }
47
- await Bun.write(process.cwd() + '/jsconfig.json', JSON.stringify(json, null, 4))
48
- }
49
-
50
- const bindes = []
51
-
52
- const handleReplacements = (code, file) => {
53
- let lines = code.split('\n')
54
- let newLines = []
55
- for (let line of lines) {
56
- let hasImport = line.includes('import')
57
- if (hasImport && line.includes('.jsx')) {
58
- line = line.replace('.jsx', '.js')
59
- }
60
- if (hasImport && line.includes('.css')) {
61
- try {
62
- let url = path.join('/' + line.split("'")[1])
63
- let css = fs.readFileSync(process.cwd() + url, 'utf-8')
64
- line = '';
65
- if (!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
66
- bindes.push(`<link rel="stylesheet" href="${url}">`)
67
- }
68
- fs.mkdirSync(process.cwd() + '/dist' + path.dirname(url), { recursive: true })
69
- fs.writeFileSync(process.cwd() + '/dist' + url, css)
70
- } catch (error) {
71
- console.error(error)
72
- }
73
- }
74
- if (line.toLowerCase().includes('genkey()')) {
75
- line = line.toLowerCase().replace('genkey()', `this.key = "${crypto.randomUUID()}"`)
76
- }
77
- if (!hasImport && line.includes('useFetch')) {
78
- line = line.replace('useFetch', 'this.useFetch')
79
- }
80
- if (!hasImport && line.includes('useState')) {
81
- let key = line.split(',')[0].split('[')[1].replace(' ', '')
82
- let b4 = line
83
- b4 = line.replace('useState(', `this.useState('${key}',`)
84
- line = b4
85
- }
86
- if (!hasImport && line.includes('useAsyncState')) {
87
- let key = line.split(',')[0].split('[')[1].replace(' ', '')
88
- let b4 = line
89
- b4 = line.replace('useAsyncState(', `this.useAsyncState('${key}',`)
90
- line = b4
91
- }
92
- if (!hasImport && line.includes('useEffect')) {
93
- let b4 = line
94
- b4 = line.replace('useEffect(', `this.useEffect(`)
95
- line = b4
96
- }
97
- if (!hasImport && line.includes('useRef')) {
98
- let b4 = line
99
- let key = line.split(' ')[1].split('=')[0]
100
- b4 = line.replace('useRef(', `this.useRef('${key}',`)
101
- line = b4
102
- }
103
- newLines.push(line)
104
- }
105
- let c = newLines.join('\n')
106
- return c
107
- }
108
-
109
-
110
- async function generateApp() {
111
- // remove files from dist
112
- if (mode === 'development') {
113
- fs.rmdirSync(process.cwd() + '/dist', { recursive: true })
114
- } else {
115
- fs.mkdirSync(process.cwd() + '/dist', { recursive: true })
116
- }
117
- return new Promise(async (resolve, reject) => {
118
- let routes = new Bun.FileSystemRouter({
119
- dir: process.cwd() + '/app',
120
- style: 'nextjs'
121
- })
122
- routes.reload()
123
- globalThis.routes = routes.routes
124
- console.log(ansiColors.green(`Processing ${Object.keys(routes.routes).length} routes`))
125
-
126
- Object.keys(routes.routes).forEach(async (route) => {
127
-
128
- let r = routes.routes[route]
129
- let code = await Bun.file(r).text()
130
- code = handleReplacements(code)
131
- let size = code.length / 1024
132
- r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
133
- r = r.replace('.jsx', '.js')
134
- fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
135
- fs.writeFileSync(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r), `
136
- let route = window.location.pathname.split('/').filter(v => v !== '')
137
- let params = {
138
- ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}).map(p => {
139
- return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p) + 1}]`
140
- }).join(',') : ""}
141
- }
142
- \n${code}
143
- `)
144
- fs.mkdirSync(process.cwd() + '/dev', { recursive: true })
145
- if (!fs.existsSync(process.cwd() + '/dev/bundler.js')) {
146
- fs.copyFileSync(require.resolve('vaderjs/bundler/index.js'), process.cwd() + '/dev/bundler.js')
147
- }
148
-
149
- if (!fs.existsSync(process.cwd() + '/dev/readme.md')) {
150
- fs.writeFileSync(process.cwd() + '/dev/readme.md', `# Please do not edit the bundler.js file in the dev directory. This file is automatically generated by the bundler. \n\n`)
151
- }
152
- fs.mkdirSync(process.cwd() + '/dist/src/vader', { recursive: true })
153
- fs.writeFileSync(process.cwd() + '/dist/src/vader/index.js', await new Bun.Transpiler({
154
- loader: 'ts',
155
- }).transformSync(await Bun.file(require.resolve('vaderjs')).text()))
156
- Bun.spawn({
157
- cmd: ['bun', 'run', './dev/bundler.js'],
158
- cwd: process.cwd(),
159
- stdout: 'inherit',
160
- env: {
161
- ENTRYPOINT: path.join(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r)),
162
- ROOT: process.cwd() + '/app/',
163
- OUT: path.dirname(r),
164
- file: process.cwd() + '/dist/' + path.dirname(r) + '/index.js',
165
- DEV: mode === 'development',
166
- size,
167
- filePath: r,
168
- INPUT: `../app/${r.replace('.js', '.jsx')}`,
169
- },
170
- onExit({ exitCode: code }) {
171
- if (code === 0) {
172
- resolve()
173
- } else {
174
- reject()
175
- }
176
- }
177
- })
178
-
179
- })
180
-
181
- switch (host_provider) {
182
- case 'vercel':
183
-
184
- let vercelData = {
185
- rewrites: []
186
- }
187
-
188
- for (let route in routes.routes) {
189
- let { filePath, kind, name, params, pathname, query } = routes.match(route)
190
- let paramString = ''
191
- if (params) {
192
- paramString = Object.keys(params).map(p => `:${p}`).join('/')
193
- }
194
- // replace double slashes
195
- paramString = paramString.replace(/\/\//g, '/')
196
- let base = route.split('/').filter(v => v !== '').join('/')
197
-
198
- if (base.includes('[')) {
199
- base = base.split('[')[0].split('/').filter(v => v !== '').join('/')
200
- }
201
- // remove double slashes
202
- base = base.replace(/\/\//g, '/')
203
- if (base === '/' || base === '') {
204
- continue;
205
- }
206
-
207
- vercelData.rewrites.push({
208
- source: `/${base}/${paramString}`,
209
- destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
210
- })
211
- }
212
-
213
- fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
214
- break;
215
- }
216
-
217
- })
218
-
219
- }
220
-
221
- await generateApp()
222
- function handleFiles() {
223
- return new Promise(async (resolve, reject) => {
224
- try {
225
- let glob = new Glob('public/**/*')
226
- for await (var i of glob.scan()) {
227
- let file = i
228
- fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
229
- if (fs.existsSync(path.join(process.cwd() + '/dist', file))) {
230
- fs.rmSync(path.join(process.cwd() + '/dist', file))
231
- }
232
- fs.copyFileSync(file, path.join(process.cwd() + '/dist', file))
233
- }
234
- resolve()
235
- } catch (error) {
236
- reject(error)
237
- }
238
- })
239
- }
240
- await handleFiles()
241
- globalThis.clients = []
242
-
243
- if (mode === 'development') {
244
- const watcher = fs.watch(path.join(process.cwd() + '/app'), { recursive: true })
245
- const publicWatcher = fs.watch(path.join(process.cwd() + '/public'), { recursive: true })
246
- let isBuilding = false; // Flag to track build status
247
-
248
- // Initialize a variable to hold the timeout ID
249
- let debounceTimeout;
250
-
251
- // Function to handle file changes with debounce
252
- const handleFileChangeDebounced = async () => {
253
- clearTimeout(debounceTimeout);
254
- debounceTimeout = setTimeout(async () => {
255
- if (!isBuilding) { // Check if not already building
256
- isBuilding = true; // Set build flag to true
257
- try {
258
- await generateApp();
259
- await handleFiles();
260
- clients.forEach(c => {
261
- c.send('reload');
262
- });
263
- } catch (error) {
264
- console.error(error);
265
- } finally {
266
- isBuilding = false; // Reset build flag
267
- }
268
- }
269
- }, 500);
270
- };
271
-
272
- // Event listeners with debounced handling
273
- publicWatcher.on('change', handleFileChangeDebounced);
274
- watcher.on('change', handleFileChangeDebounced);
275
-
276
- let server = Bun.serve({
277
- port: port || 8080,
278
- websocket: {
279
- open(ws) {
280
- globalThis.clients.push(ws)
281
- ws.send('Connected')
282
- },
283
- message(ws, message) {
284
- globalThis.clients.forEach(c => {
285
- c.send(message)
286
- })
287
- },
288
-
289
- },
290
- async fetch(req, res) {
291
- if (res.upgrade(req)) {
292
- return new Response('Upgraded', { status: 101 })
293
- }
294
-
295
- let url = new URL(req.url)
296
- if (url.pathname.includes('.')) {
297
- let file = await Bun.file(path.join(process.cwd() + '/dist' + url.pathname))
298
- if (!await file.exists()) return new Response('Not found', { status: 404 })
299
- return new Response(await file.text(), {
300
- headers: {
301
- 'Content-Type': file.type
302
- }
303
- })
304
- }
305
- let router = new Bun.FileSystemRouter({
306
- dir: process.cwd() + '/app',
307
- style: 'nextjs'
308
- })
309
- router.reload()
310
- let route = router.match(url.pathname)
311
- if (!route) {
312
- return new Response('Not found', { status: 404 })
313
- }
314
- let p = route.pathname;
315
- let base = path.dirname(route.filePath)
316
- base = base.replace(path.join(process.cwd() + '/app'), '')
317
- base = base.replace(/\\/g, '/').replace('/app', '/dist')
318
- return new Response(await Bun.file(path.join(base, 'index.html')).text() + `
319
- <script>
320
- let ws = new WebSocket('ws://localhost:${server.port}')
321
- ws.onmessage = (e) => {
322
- if(e.data === 'reload'){
323
- window.location.reload()
324
- }
325
- }
326
- </script>
327
- `, {
328
- headers: {
329
- 'Content-Type': 'text/html'
330
- }
331
- })
332
- }
333
- })
334
- } else {
335
- console.log(`Build complete in ${Date.now() - start}ms at ${new Date().toLocaleTimeString()}`)
336
- process.exit(0)
1
+ #!/usr/bin/env bun
2
+
3
+ import ansiColors from 'ansi-colors'
4
+ import { Glob } from 'bun'
5
+ const args = Bun.argv.slice(2)
6
+ import fs from 'fs'
7
+ import path from 'path'
8
+ if (!fs.existsSync(process.cwd() + '/app')) {
9
+ console.error(`App directory not found in ${process.cwd()}/app`)
10
+ process.exit(1)
11
+ }
12
+ if (!fs.existsSync(process.cwd() + '/public')) {
13
+ fs.mkdirSync(process.cwd() + '/public')
14
+ }
15
+ const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : null
16
+ if (!mode) {
17
+ console.log(`
18
+ Usage:
19
+ bun vaderjs dev - Start development server output in dist/
20
+ bun vaderjs prod - Build for production output in dist/
21
+ `)
22
+ process.exit(1)
23
+ }
24
+
25
+ console.log(
26
+ `VaderJS - v${require(process.cwd() + '/node_modules/vaderjs/package.json').version} 🚀
27
+ Mode: ${mode}
28
+ SSR: ${require(process.cwd() + '/vader.config.ts').default.ssr ? 'Enabled' : 'Disabled'}
29
+ PORT: ${require(process.cwd() + '/vader.config.ts').default.port || 8080}
30
+ `
31
+ )
32
+
33
+ let start = Date.now()
34
+ console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
35
+ let { port, host, host_provider } = require(process.cwd() + '/vader.config.ts').default
36
+ if (host_provider === 'apache' && mode === 'development') {
37
+ console.warn('Note: SSR will not work with Apache')
38
+ }
39
+ if (!fs.existsSync(process.cwd() + '/jsconfig.json')) {
40
+ let json = {
41
+ "compilerOptions": {
42
+ "jsx": "react",
43
+ "jsxFactory": "e",
44
+ "jsxFragmentFactory": "Fragment",
45
+ }
46
+ }
47
+ await Bun.write(process.cwd() + '/jsconfig.json', JSON.stringify(json, null, 4))
48
+ }
49
+
50
+ const bindes = []
51
+
52
+ const handleReplacements = (code, file) => {
53
+ let lines = code.split('\n')
54
+ let newLines = []
55
+ for (let line of lines) {
56
+ let hasImport = line.includes('import')
57
+
58
+ if (hasImport && line.includes('.css')) {
59
+ try {
60
+ let url = path.join('/' + line.split("'")[1])
61
+ let css = fs.readFileSync(process.cwd() + url, 'utf-8')
62
+ line = '';
63
+ if (!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
64
+ bindes.push(`<link rel="stylesheet" href="${url}">`)
65
+ }
66
+ fs.mkdirSync(process.cwd() + '/dist' + path.dirname(url), { recursive: true })
67
+ fs.writeFileSync(process.cwd() + '/dist' + url, css)
68
+ } catch (error) {
69
+ console.error(error)
70
+ }
71
+ }
72
+ if (line.toLowerCase().includes('genkey()')) {
73
+ line = line.toLowerCase().replace('genkey()', `this.key = "${crypto.randomUUID()}"`)
74
+ }
75
+ if (!hasImport && line.includes('useFetch')) {
76
+ line = line.replace('useFetch', 'this.useFetch')
77
+ }
78
+ if (!hasImport && line.includes('useState') && line.includes('[')) {
79
+ let key = line.split(',')[0].split('[')[1].replace(' ', '')
80
+ let b4 = line
81
+ b4 = line.replace('useState(', `this.useState('${key}',`)
82
+ line = b4
83
+ }
84
+ if (!hasImport && line.includes('useAsyncState')) {
85
+ let key = line.split(',')[0].split('[')[1].replace(' ', '')
86
+ let b4 = line
87
+ b4 = line.replace('useAsyncState(', `this.useAsyncState('${key}',`)
88
+ line = b4
89
+ }
90
+ if (!hasImport && line.includes('useEffect')) {
91
+ let b4 = line
92
+ b4 = line.replace('useEffect(', `this.useEffect(`)
93
+ line = b4
94
+ }
95
+ if (!hasImport && line.includes('useRef')) {
96
+ let b4 = line
97
+ let key = line.split(' ')[1].split('=')[0]
98
+ b4 = line.replace('useRef(', `this.useRef('${key}',`)
99
+ line = b4
100
+ }
101
+ newLines.push(line)
102
+ }
103
+ let c = newLines.join('\n')
104
+ return c
105
+ }
106
+
107
+
108
+ async function generateApp() {
109
+ // remove files from dist
110
+ if (mode === 'development') {
111
+ fs.rmdirSync(process.cwd() + '/dist', { recursive: true })
112
+ } else {
113
+ fs.mkdirSync(process.cwd() + '/dist', { recursive: true })
114
+ }
115
+ return new Promise(async (resolve, reject) => {
116
+ let routes = new Bun.FileSystemRouter({
117
+ dir: process.cwd() + '/app',
118
+ style: 'nextjs'
119
+ })
120
+ routes.reload()
121
+ globalThis.routes = routes.routes
122
+ Object.keys(routes.routes).forEach(async (route) => {
123
+
124
+ let r = routes.routes[route]
125
+ let code = await Bun.file(r).text()
126
+ code = handleReplacements(code)
127
+ let size = code.length / 1024
128
+ r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
129
+ r = r.replace('.jsx', '.js')
130
+ fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
131
+ fs.writeFileSync(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r), `
132
+ let route = window.location.pathname.split('/').filter(v => v !== '')
133
+ let params = {
134
+ ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}).map(p => {
135
+ return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p)}]`
136
+ }).join(',') : ""}
137
+ }
138
+ \n${code}
139
+ `)
140
+ fs.mkdirSync(process.cwd() + '/dev', { recursive: true })
141
+ if (!fs.existsSync(process.cwd() + '/dev/bundler.js')) {
142
+ fs.copyFileSync(require.resolve('vaderjs/bundler/index.js'), process.cwd() + '/dev/bundler.js')
143
+ }
144
+
145
+ if (!fs.existsSync(process.cwd() + '/dev/readme.md')) {
146
+ fs.writeFileSync(process.cwd() + '/dev/readme.md', `# Please do not edit the bundler.js file in the dev directory. This file is automatically generated by the bundler. \n\n`)
147
+ }
148
+ fs.mkdirSync(process.cwd() + '/dist/src/vader', { recursive: true })
149
+ fs.writeFileSync(process.cwd() + '/dist/src/vader/index.js', await new Bun.Transpiler({
150
+ loader: 'ts',
151
+ }).transformSync(await Bun.file(require.resolve('vaderjs')).text()))
152
+ Bun.spawn({
153
+ cmd: ['bun', 'run', './dev/bundler.js'],
154
+ cwd: process.cwd(),
155
+ stdout: 'inherit',
156
+ env: {
157
+ ENTRYPOINT: path.join(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r)),
158
+ ROOT: process.cwd() + '/app/',
159
+ OUT: path.dirname(r),
160
+ file: process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r),
161
+ DEV: mode === 'development',
162
+ size,
163
+ filePath: r,
164
+ INPUT: `../app/${r.replace('.js', '.jsx')}`,
165
+ },
166
+ onExit({ exitCode: code }) {
167
+ if (code === 0) {
168
+ console.log(`Built ${r} in ${Date.now() - start}ms`)
169
+ resolve()
170
+ } else {
171
+ reject()
172
+ }
173
+ }
174
+ })
175
+
176
+ })
177
+
178
+ switch (host_provider) {
179
+ case 'vercel':
180
+
181
+ let vercelData = {
182
+ rewrites: []
183
+ }
184
+
185
+ for (let route in routes.routes) {
186
+ let { filePath, kind, name, params, pathname, query } = routes.match(route)
187
+ let r = route
188
+
189
+ if (r.includes('[')) {
190
+ r = r.replaceAll('[', ':').replaceAll(']', '')
191
+ }
192
+ if (r === '/') {
193
+ continue
194
+ }
195
+
196
+ vercelData.rewrites.push({
197
+ source: r,
198
+ destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
199
+ })
200
+ }
201
+
202
+ fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
203
+ break;
204
+ }
205
+
206
+ })
207
+
208
+ }
209
+
210
+ await generateApp()
211
+ function handleFiles() {
212
+ return new Promise(async (resolve, reject) => {
213
+ try {
214
+ let glob = new Glob('public/**/*')
215
+ for await (var i of glob.scan()) {
216
+ let file = i
217
+ fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
218
+ if (fs.existsSync(path.join(process.cwd() + '/dist', file))) {
219
+ fs.rmSync(path.join(process.cwd() + '/dist', file))
220
+ }
221
+ fs.copyFileSync(file, path.join(process.cwd() + '/dist', file))
222
+ }
223
+ let glob2 = new Glob('src/**/*')
224
+ for await (var i of glob2.scan()) {
225
+ var file = i
226
+ fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
227
+ // turn jsx to js
228
+ if (file.includes('.jsx')) {
229
+ let code = await Bun.file(file).text()
230
+ code = handleReplacements(code)
231
+
232
+ file = file.replace('.jsx', '.js')
233
+ fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.jsx', '.js')), code)
234
+ await Bun.spawn({
235
+ cmd: ['bun', 'run', './dev/bundler.js'],
236
+ cwd: process.cwd(),
237
+ stdout: 'inherit',
238
+ env: {
239
+ ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.jsx', '.js')),
240
+ ROOT: process.cwd() + '/app/',
241
+ OUT: path.dirname(file),
242
+ file: process.cwd() + '/dist/' + file.replace('.jsx', '.js'),
243
+ DEV: mode === 'development',
244
+ size: code.length / 1024,
245
+ filePath: file.replace('.jsx', '.js'),
246
+ INPUT: path.join(process.cwd() , file.replace('.js', '.jsx')),
247
+ },
248
+ onExit({ exitCode: code }) {
249
+ if (code === 0) {
250
+ resolve()
251
+ } else {
252
+ reject()
253
+ }
254
+ }
255
+ })
256
+ }
257
+
258
+ }
259
+
260
+ resolve()
261
+ } catch (error) {
262
+ reject(error)
263
+ }
264
+ })
265
+ }
266
+ await handleFiles()
267
+ globalThis.clients = []
268
+
269
+ if (mode === 'development') {
270
+ const watcher = fs.watch(path.join(process.cwd() + '/app'), { recursive: true })
271
+ const publicWatcher = fs.watch(path.join(process.cwd() + '/public'), { recursive: true })
272
+ const srcWatcher = fs.watch(path.join(process.cwd() + '/src'), { recursive: true })
273
+ let isBuilding = false; // Flag to track build status
274
+
275
+ // Initialize a variable to hold the timeout ID
276
+ let debounceTimeout;
277
+
278
+ // Function to handle file changes with debounce
279
+ const handleFileChangeDebounced = async () => {
280
+ clearTimeout(debounceTimeout);
281
+ debounceTimeout = setTimeout(async () => {
282
+ if (!isBuilding) { // Check if not already building
283
+ isBuilding = true; // Set build flag to true
284
+ try {
285
+ await generateApp();
286
+ await handleFiles();
287
+ clients.forEach(c => {
288
+ c.send('reload');
289
+ });
290
+ } catch (error) {
291
+ console.error(error);
292
+ } finally {
293
+ isBuilding = false; // Reset build flag
294
+ }
295
+ }
296
+ }, 500);
297
+ };
298
+
299
+ // Event listeners with debounced handling
300
+ publicWatcher.on('change', handleFileChangeDebounced);
301
+ watcher.on('change', handleFileChangeDebounced);
302
+ srcWatcher.on('change', handleFileChangeDebounced);
303
+ let server = Bun.serve({
304
+ port: port || 8080,
305
+ websocket: {
306
+ open(ws) {
307
+ globalThis.clients.push(ws)
308
+ ws.send('Connected')
309
+ },
310
+ message(ws, message) {
311
+ globalThis.clients.forEach(c => {
312
+ c.send(message)
313
+ })
314
+ },
315
+
316
+ },
317
+ async fetch(req, res) {
318
+ if (res.upgrade(req)) {
319
+ return new Response('Upgraded', { status: 101 })
320
+ }
321
+
322
+ let url = new URL(req.url)
323
+ if (url.pathname.includes('.')) {
324
+ let p = url.pathname.replaceAll("%5B", "[").replaceAll("%5D", "]")
325
+ let file = await Bun.file(path.join(process.cwd() + '/dist' + p))
326
+ if (!await file.exists()) return new Response('Not found', { status: 404 })
327
+ return new Response(await file.text(), {
328
+ headers: {
329
+ 'Content-Type': file.type,
330
+ 'Cache-Control': 'no-cache',
331
+ 'Access-Control-Allow-Origin': '*'
332
+ }
333
+ })
334
+ }
335
+ let router = new Bun.FileSystemRouter({
336
+ dir: process.cwd() + '/app',
337
+ style: 'nextjs'
338
+ })
339
+ router.reload()
340
+ let route = router.match(url.pathname)
341
+ if (!route) {
342
+ return new Response('Not found', { status: 404 })
343
+ }
344
+ let p = route.pathname;
345
+ let base = path.dirname(route.filePath)
346
+ base = base.replace(path.join(process.cwd() + '/app'), '')
347
+ base = base.replace(/\\/g, '/').replace('/app', '/dist')
348
+ base = process.cwd() + "/dist/" + base
349
+ let data = await Bun.file(path.join(base, 'index.html')).text()
350
+ if (mode == "development") {
351
+ return new Response(data + `
352
+ <script>
353
+ let ws = new WebSocket('ws://localhost:${server.port}')
354
+ ws.onmessage = (e) => {
355
+ if(e.data === 'reload'){
356
+ window.location.reload()
357
+ }
358
+ }
359
+ </script>
360
+ `, {
361
+ headers:{
362
+ 'Content-Type': 'text/html'
363
+ }
364
+ })
365
+ } else {
366
+ return new Response(data, {
367
+ headers: {
368
+ 'Content-Type': 'text/html'
369
+ }
370
+ })
371
+ }
372
+
373
+ }
374
+ })
375
+ } else {
376
+ console.log(`Build complete in ${Date.now() - start}ms at ${new Date().toLocaleTimeString()}`)
377
+ process.exit(0)
337
378
  }