vaderjs 1.3.7 → 1.4.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 +252 -154
- package/binaries/generator.js +201 -0
- package/binaries/readme.md +4 -0
- package/binaries/watcher.js +70 -0
- package/client/index.js +426 -0
- package/logo.png +0 -0
- package/package.json +28 -12
- package/runtime/router.js +1 -261
- package/runtime/vader.js +1 -0
- package/vader.js +690 -0
- package/runtime/static/index.html +0 -21
- package/vader +0 -0
package/vader.js
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Glob } from "bun";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import * as Bun from "bun";
|
|
5
|
+
import WebSocket from 'ws'
|
|
6
|
+
let config = await import(process.cwd() + '/vader.config.js').then((m) => m ? m.default : {}).catch((e) => {
|
|
7
|
+
console.error(e)
|
|
8
|
+
return {}
|
|
9
|
+
})
|
|
10
|
+
/**@description - Used to store hmr websocket clients */
|
|
11
|
+
globalThis.clients = []
|
|
12
|
+
/**@description - Used to keep track of routes */
|
|
13
|
+
globalThis.routes = []
|
|
14
|
+
/**
|
|
15
|
+
* @description - Used to keep track of the mode
|
|
16
|
+
*/
|
|
17
|
+
globalThis.mode = 'dev'
|
|
18
|
+
/**@usedby @transForm */
|
|
19
|
+
globalThis.isBuilding = false
|
|
20
|
+
globalThis.hasGenerated = []
|
|
21
|
+
/**
|
|
22
|
+
* @description - Used to keep track of the bundle size
|
|
23
|
+
*/
|
|
24
|
+
let bundleSize = 0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if(globalThis.mode === 'dev'){
|
|
28
|
+
Bun.spawn({
|
|
29
|
+
cwd: process.cwd() + '/node_modules/vaderjs/binaries/',
|
|
30
|
+
env: {
|
|
31
|
+
PWD: process.cwd(),
|
|
32
|
+
onExit: (code) => {
|
|
33
|
+
globalThis.isBuilding = false
|
|
34
|
+
globalThis.oneAndDone = true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
cmd: ['node', 'generator.js'],
|
|
38
|
+
})
|
|
39
|
+
globalThis.generatorWs = new WebSocket(`ws://localhost:${3436}`)
|
|
40
|
+
globalThis.generatorWs.on('message', (message) => {
|
|
41
|
+
let data = JSON.parse(message.toString())
|
|
42
|
+
switch(true){
|
|
43
|
+
case data.type === 'done':
|
|
44
|
+
let file = data.file
|
|
45
|
+
globalThis.hasGenerated.push(file)
|
|
46
|
+
console.log('Generated', file)
|
|
47
|
+
break;
|
|
48
|
+
case data.type === 'error':
|
|
49
|
+
console.error(data.message)
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
globalThis.generatorWs.on('connection', (ws) => {
|
|
54
|
+
console.log('Connected to generator...')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if(!globalThis.generatorWs.readyState === 1){
|
|
58
|
+
console.log('Generator is not ready...')
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @description - variables used to generate arrays of paths recursively
|
|
64
|
+
*/
|
|
65
|
+
const glob = new Glob("/pages/**/**/*.{,tsx,js,jsx}", {absolute: true});
|
|
66
|
+
const vaderGlob = new Glob("/node_modules/vaderjs/runtime/**/**/*.{,tsx,js}", {absolute: true});
|
|
67
|
+
const srcGlob = new Glob("/src/**/**/*.{jsx,ts,tsx,js}", {absolute: true});
|
|
68
|
+
const publicGlob = new Glob("/public/**/**/*.{css,js,html,jpg,png,gif,svg,ico,video,webm,mp4,jpeg}", {absolute: true});
|
|
69
|
+
const distPages = new Glob("/dist/pages/**/**/*.{tsx,js,jsx}", {absolute: true})
|
|
70
|
+
const distSrc = new Glob("/dist/src/**/**/*.{tsx,js,jsx}", {absolute: true})
|
|
71
|
+
const distPublic = new Glob("/dist/public/**/**/*.{css,js,html,jpg,png,gif,svg,ico,video,webm,mp4,jpeg}", {absolute: true});
|
|
72
|
+
|
|
73
|
+
const router = new Bun.FileSystemRouter({
|
|
74
|
+
style: "nextjs",
|
|
75
|
+
dir: process.cwd() + '/pages',
|
|
76
|
+
origin: process.env.ORIGIN || "http://localhost:3000",
|
|
77
|
+
assetPrefix: "_next/static/"
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* @function handleReplaceMents
|
|
81
|
+
* @description - replaces data to be compatible with Vader.js
|
|
82
|
+
* @param {*} data
|
|
83
|
+
* @returns
|
|
84
|
+
*/
|
|
85
|
+
function handleReplaceMents(data){
|
|
86
|
+
data.split('\n').forEach((line, index)=>{
|
|
87
|
+
switch(true){
|
|
88
|
+
|
|
89
|
+
case line.includes('useReducer') && !line.includes('import'):
|
|
90
|
+
line = line.replaceAll(/\s+/g, " ");
|
|
91
|
+
|
|
92
|
+
let varTypereducer = line.split("=")[0].trim().split("[")[0].trim();
|
|
93
|
+
let keyreducer = line.split("=")[0].trim().split("[")[1].trim().split(",")[0].trim();
|
|
94
|
+
let setKeyreducer = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
|
|
95
|
+
let reducer = line.split("=")[1].split("useReducer(")[1];
|
|
96
|
+
|
|
97
|
+
let newStatereducer = `${varTypereducer} [${keyreducer}, ${setKeyreducer}] = this.useReducer('${keyreducer}', ${line.includes('=>') ? reducer + '=>{' : reducer}`;
|
|
98
|
+
|
|
99
|
+
data = data.replace(line, newStatereducer);
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
case line.includes('useState') && !line.includes('import'):
|
|
103
|
+
let varType = line.split("[")[0]
|
|
104
|
+
if (!line.split("=")[0].split(",")[1]) {
|
|
105
|
+
throw new Error('You forgot to value selector (useState) ' + ' at ' + `${file}:${string.split(line)[0].split('\n').length}`)
|
|
106
|
+
}
|
|
107
|
+
let key = line.split("=")[0].split(",")[0].trim().split('[')[1];
|
|
108
|
+
|
|
109
|
+
if (!line.split("=")[0].split(",")[1]) {
|
|
110
|
+
throw new Error('You forgot to add a setter (useState) ' + ' at ' + `${file}:${string.split(line)[0].split('\n').length}`)
|
|
111
|
+
}
|
|
112
|
+
let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
|
|
113
|
+
key = key.replace("[", "").replace(",", "");
|
|
114
|
+
let valuestate = line.split("=")[1].split("useState(")[1];
|
|
115
|
+
|
|
116
|
+
let regex = /useState\((.*)\)/gs;
|
|
117
|
+
valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
|
|
118
|
+
let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}`;
|
|
119
|
+
data = data.replace(line, newState);
|
|
120
|
+
break;
|
|
121
|
+
|
|
122
|
+
case line.includes("useRef") && !line.includes("import"):
|
|
123
|
+
line = line.trim();
|
|
124
|
+
let typeref = line.split(" ")[0]
|
|
125
|
+
|
|
126
|
+
let keyref = line.split(typeref)[1].split("=")[0].trim().replace("[", "").replace(",", "");
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
let valueref = line.split("=")[1].split("useRef(")[1];
|
|
130
|
+
|
|
131
|
+
let newStateref = `${typeref} ${keyref} = this.useRef('${keyref}', ${valueref}`;
|
|
132
|
+
data = data.replace(line, newStateref);
|
|
133
|
+
case line.includes('.jsx') && line.includes('import') || line.includes('.tsx') && line.includes('import'):
|
|
134
|
+
let old = line
|
|
135
|
+
line = line.replace('.jsx', '.js')
|
|
136
|
+
line = line.replace('.tsx', '.js')
|
|
137
|
+
data = data.replace(old, line)
|
|
138
|
+
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
data = data.replaceAll('jsxDEV', 'Vader.createElement')
|
|
144
|
+
data = data.replaceAll('jsx', 'Vader.createElement')
|
|
145
|
+
data = data.replaceAll('vaderjs/client', '/vader.js')
|
|
146
|
+
data = data.replaceAll('.tsx', '.js')
|
|
147
|
+
let reactImportMatch = data.match(/import React/g);
|
|
148
|
+
if(reactImportMatch){
|
|
149
|
+
let fullmatch = data.match(/import React from "react"/g);
|
|
150
|
+
if(fullmatch){
|
|
151
|
+
data = data.replaceAll('import React from "react"', '');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
data = data.replaceAll('.ts', '.js')
|
|
155
|
+
|
|
156
|
+
// check if Vader is imported
|
|
157
|
+
let vaderImport = data.match(/import Vader/g);
|
|
158
|
+
if(!vaderImport){
|
|
159
|
+
data = `import Vader from "/vader.js";\n` + data;
|
|
160
|
+
}
|
|
161
|
+
return data;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @function ContentType
|
|
167
|
+
* @description - returns the content type based on the file extension
|
|
168
|
+
* @param {*} url
|
|
169
|
+
* @returns
|
|
170
|
+
*/
|
|
171
|
+
const ContentType = (url)=>{
|
|
172
|
+
switch(url.split('.').pop()){
|
|
173
|
+
case 'css':
|
|
174
|
+
return 'text/css';
|
|
175
|
+
case 'js':
|
|
176
|
+
return 'text/javascript';
|
|
177
|
+
case 'json':
|
|
178
|
+
return 'application/json';
|
|
179
|
+
case 'html':
|
|
180
|
+
return 'text/html';
|
|
181
|
+
case 'jpg':
|
|
182
|
+
return 'image/jpg';
|
|
183
|
+
case 'png':
|
|
184
|
+
return 'image/png';
|
|
185
|
+
case 'gif':
|
|
186
|
+
return 'image/gif';
|
|
187
|
+
case 'svg':
|
|
188
|
+
return 'image/svg+xml';
|
|
189
|
+
case 'ico':
|
|
190
|
+
return 'image/x-icon';
|
|
191
|
+
default:
|
|
192
|
+
return 'text/html';
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @function Server
|
|
200
|
+
* @description - Creates a hmr development server
|
|
201
|
+
* @param {Number} port
|
|
202
|
+
*/
|
|
203
|
+
function Server(port){
|
|
204
|
+
Bun.serve({
|
|
205
|
+
port: port,
|
|
206
|
+
fetch(req, res){
|
|
207
|
+
const url = new URL(req.url);
|
|
208
|
+
const success = res.upgrade(req);
|
|
209
|
+
if(success){
|
|
210
|
+
return new Response('Connected', {
|
|
211
|
+
headers: {
|
|
212
|
+
"Content-Type": "text/html"
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
if(req.url.includes('.')){
|
|
217
|
+
return new Response(fs.readFileSync(process.cwd() + '/dist/' + url.pathname, 'utf8'), {
|
|
218
|
+
headers: {
|
|
219
|
+
"Content-Type": ContentType(req.url)
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
let matchedRoute = router.match(url.pathname);
|
|
224
|
+
if(matchedRoute){
|
|
225
|
+
let {filePath, kind, name, params, pathname, query,} = matchedRoute
|
|
226
|
+
let folder = url.pathname.split('/')[1]
|
|
227
|
+
let jsFile = filePath.split('pages/').pop().split('.').shift() + '.js'
|
|
228
|
+
let pageContent = fs.readFileSync(process.cwd() + '/dist/pages/' + folder + '/index.html', 'utf8')
|
|
229
|
+
globalThis.mode === 'dev' ? pageContent += `
|
|
230
|
+
<script type="module">
|
|
231
|
+
let ws = new WebSocket('ws://localhost:${port}');
|
|
232
|
+
ws.onmessage = async (e) => {
|
|
233
|
+
if(e.data === 'reload'){
|
|
234
|
+
window.location.reload()
|
|
235
|
+
console.log('Reloading...')
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
</script>
|
|
239
|
+
` : void 0
|
|
240
|
+
return new Response( pageContent, {
|
|
241
|
+
headers: {
|
|
242
|
+
"Content-Type": "text/html",
|
|
243
|
+
"X-Powered-By": "Vader.js v1.3.3"
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return new Response('Not Found', {
|
|
249
|
+
status: 404,
|
|
250
|
+
headers: {
|
|
251
|
+
"Content-Type": "text/html"
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
},
|
|
255
|
+
websocket: {
|
|
256
|
+
open(ws){
|
|
257
|
+
clients.push(ws)
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* @function write
|
|
264
|
+
* @description - Writes data to a file
|
|
265
|
+
* @returns {void} 0
|
|
266
|
+
* @param {string} file
|
|
267
|
+
* @param {any} data
|
|
268
|
+
* @returns
|
|
269
|
+
*/
|
|
270
|
+
const write = (file, data) => {
|
|
271
|
+
try {
|
|
272
|
+
if(!fs.existsSync('./dist')){
|
|
273
|
+
fs.mkdirSync('./dist')
|
|
274
|
+
}
|
|
275
|
+
Bun.write(file, data);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error(error)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* @function read
|
|
283
|
+
* @param {path} file
|
|
284
|
+
* @returns {Promise<string>}
|
|
285
|
+
*/
|
|
286
|
+
const read = async (file) => {
|
|
287
|
+
return await Bun.file(file).text();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @function generateProviderRoutes
|
|
292
|
+
* @description - Generates routes for hosting provders ie: vercel, cloudflare
|
|
293
|
+
* @returns {void} 0
|
|
294
|
+
*/
|
|
295
|
+
async function generateProviderRoutes(){
|
|
296
|
+
if(!config?.host?.provider){
|
|
297
|
+
console.warn('No provider found in vader.config.js ignoring route generation...')
|
|
298
|
+
return void 0;
|
|
299
|
+
}
|
|
300
|
+
let providerType = [{
|
|
301
|
+
provider: 'vercel',
|
|
302
|
+
file: 'vercel.json',
|
|
303
|
+
out: process.cwd() + '/vercel.json',
|
|
304
|
+
obj: {
|
|
305
|
+
rewrites:[]
|
|
306
|
+
}
|
|
307
|
+
},{
|
|
308
|
+
provider: 'cloudflare',
|
|
309
|
+
file:'_redirects',
|
|
310
|
+
out: 'dist/_redirects'
|
|
311
|
+
}]
|
|
312
|
+
|
|
313
|
+
let provider = providerType.find((p) => p.provider === config.host.provider)
|
|
314
|
+
if(provider){
|
|
315
|
+
let prev = null
|
|
316
|
+
|
|
317
|
+
switch(provider.provider){
|
|
318
|
+
case 'vercel':
|
|
319
|
+
prev = await read(provider.out);
|
|
320
|
+
if(!prev.includes('rewrites')){
|
|
321
|
+
prev = []
|
|
322
|
+
} else{
|
|
323
|
+
prev = JSON.parse(prev).rewrites
|
|
324
|
+
}
|
|
325
|
+
routes.forEach((r) => {
|
|
326
|
+
if(r.path === '/'
|
|
327
|
+
|| prev.find((p) => p.source === '/'+ r.path + '/index.html')
|
|
328
|
+
){
|
|
329
|
+
return void 0;
|
|
330
|
+
}
|
|
331
|
+
prev.push({
|
|
332
|
+
source: '/'+ r.path,
|
|
333
|
+
destination: '/'+ r.path + '/index.html'
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
if(r.params.length > 0){
|
|
337
|
+
r.params.forEach((param)=>{
|
|
338
|
+
if(!param.paramData){
|
|
339
|
+
return void 0;
|
|
340
|
+
}
|
|
341
|
+
let parampath= Object.keys(param.paramData).map((p)=>`:${p}`).join('/')
|
|
342
|
+
prev.push({
|
|
343
|
+
source: '/'+ r.path + '/' + parampath ,
|
|
344
|
+
destination: '/'+ r.path + '/index.html'
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
fs.writeFileSync(provider.out, JSON.stringify({rewrites: prev}, null, 2))
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
})
|
|
353
|
+
provider.obj.rewrites = prev
|
|
354
|
+
write(provider.out, JSON.stringify(provider.obj, null, 2))
|
|
355
|
+
break;
|
|
356
|
+
case 'cloudflare':
|
|
357
|
+
console.warn('Cloudflare is not supported yet refer to their documentation for more information:https://developers.cloudflare.com/pages/configuration/redirects/')
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
return void 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @function transform
|
|
370
|
+
* @description - Transforms the jsx files to js files based on file paths
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
async function transForm(){
|
|
374
|
+
globalThis.isBuilding = true
|
|
375
|
+
router.reload()
|
|
376
|
+
for await (var file of glob.scan('.')) {
|
|
377
|
+
file = file.replace(/\\/g, '/');
|
|
378
|
+
let isBasePath = file.split('pages/')?.[1]?.split('/').length === 1;
|
|
379
|
+
let folder = file.split('pages/')?.[1]?.split('/').slice(0, -1).join('/') || null;
|
|
380
|
+
let route = isBasePath ? router.match('/') : router.match('/' + folder)
|
|
381
|
+
if(route){
|
|
382
|
+
let {filePath, kind, name, params, pathname, query,} = route
|
|
383
|
+
let data = await read(filePath);
|
|
384
|
+
try{
|
|
385
|
+
data = new Bun.Transpiler({loader: "tsx", target:"browser", }).transformSync(data);
|
|
386
|
+
}catch(e){
|
|
387
|
+
console.error(e)
|
|
388
|
+
}
|
|
389
|
+
let out = `./dist/pages/${isBasePath ? 'index.js' : folder + '/index.js'}`;
|
|
390
|
+
isBasePath ? folder = '/': null;
|
|
391
|
+
data = handleReplaceMents(data);
|
|
392
|
+
globalThis.routes.push({path: folder, file: out, isParam: kind === 'dynamic' ? true : false, params, query, pathname})
|
|
393
|
+
write(out, data);
|
|
394
|
+
bundleSize += data.length
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
for await (var file of srcGlob.scan('.')) {
|
|
402
|
+
if(!fs.existsSync(process.cwd() +'/dist/src/')){
|
|
403
|
+
fs.mkdirSync(process.cwd() +'/dist/src/')
|
|
404
|
+
}
|
|
405
|
+
file = file.replace(/\\/g, '/');
|
|
406
|
+
switch(file.split('.').pop()){
|
|
407
|
+
case 'ts':
|
|
408
|
+
let transpiler = new Bun.Transpiler({loader: "ts", target:"browser", });
|
|
409
|
+
let data = await read(file);
|
|
410
|
+
try {
|
|
411
|
+
data = transpiler.transformSync(data);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
console.error(error)
|
|
414
|
+
}
|
|
415
|
+
file = file.replace('.ts', '.js')
|
|
416
|
+
let path = process.cwd() +'/dist/src/' + file.split('src/').pop()
|
|
417
|
+
write(path, data);
|
|
418
|
+
bundleSize += data.length
|
|
419
|
+
|
|
420
|
+
break;
|
|
421
|
+
|
|
422
|
+
case 'tsx':
|
|
423
|
+
let transpilerx = new Bun.Transpiler({loader: "tsx", target:"browser", });
|
|
424
|
+
let datax = await read(file);
|
|
425
|
+
try {
|
|
426
|
+
datax = transpilerx.transformSync(datax);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error(error)
|
|
429
|
+
}
|
|
430
|
+
datax = handleReplaceMents(datax);
|
|
431
|
+
file = file.replace('.tsx', '.js')
|
|
432
|
+
let pathx = process.cwd() +'/dist/src/' + file.split('src/').pop()
|
|
433
|
+
write(pathx, datax);
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
break;
|
|
437
|
+
case 'jsx':
|
|
438
|
+
let transpilerjx = new Bun.Transpiler({loader: "jsx", target:"browser", });
|
|
439
|
+
let datajx = await read(file);
|
|
440
|
+
try {
|
|
441
|
+
datajx = transpilerjx.transformSync(datajx);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error(error)
|
|
444
|
+
}
|
|
445
|
+
datajx = handleReplaceMents(datajx);
|
|
446
|
+
file = file.replace('.jsx', '.js')
|
|
447
|
+
let pathjx = process.cwd() +'/dist/src/' + file.split('src/').pop()
|
|
448
|
+
write(pathjx, datajx);
|
|
449
|
+
bundleSize += datajx.length
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
for await (var file of publicGlob.scan('.')) {
|
|
456
|
+
let data = await read(file);
|
|
457
|
+
file = file.replace(/\\/g, '/');
|
|
458
|
+
write(process.cwd() +'/dist/public/' + file.split('public/').pop(), data);
|
|
459
|
+
bundleSize += fs.statSync(process.cwd() +'/dist/public/' + file.split('public/').pop()).size
|
|
460
|
+
}
|
|
461
|
+
for await (var file of vaderGlob.scan('.')) {
|
|
462
|
+
let data = await read(file);
|
|
463
|
+
file = file.replace(/\\/g, '/');
|
|
464
|
+
write(process.cwd() +'/dist/' + file.split('node_modules/vaderjs/runtime/').pop(), data);
|
|
465
|
+
bundleSize += fs.statSync(process.cwd() +'/dist/' + file.split('node_modules/vaderjs/runtime/').pop()).size
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// clean dist folder
|
|
469
|
+
for await( var file of distPages.scan('.')){
|
|
470
|
+
file = file.replace(/\\/g, '/');
|
|
471
|
+
let path = process.cwd() +'/pages/' + file.split('dist/pages/').pop()
|
|
472
|
+
path = path.replace('.js', config?.files?.mimeType || '.jsx')
|
|
473
|
+
|
|
474
|
+
if(!fs.existsSync(path)){
|
|
475
|
+
fs.unlinkSync(file)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
for await( var file of distSrc.scan('.')){
|
|
481
|
+
file = file.replace(/\\/g, '/');
|
|
482
|
+
let path = process.cwd() +'/src/' + file.split('dist/src/').pop()
|
|
483
|
+
// if the file is a js file see if theirs a matching ts file
|
|
484
|
+
if(file.split('.').pop() === 'js'){
|
|
485
|
+
let tsFile = path.replace('.js', '.ts')
|
|
486
|
+
// if the ts file exists then the js file is valid else if not the js file exists then remove
|
|
487
|
+
switch(true){
|
|
488
|
+
case !fs.existsSync(tsFile):
|
|
489
|
+
// check if a tsx or jsx file exists
|
|
490
|
+
let tsxFile = path.replace('.js', '.tsx')
|
|
491
|
+
let jsxFile = path.replace('.js', '.jsx')
|
|
492
|
+
let tsfile = path.replace('.js', '.ts')
|
|
493
|
+
switch(true){
|
|
494
|
+
case fs.existsSync(tsxFile):
|
|
495
|
+
break;
|
|
496
|
+
case fs.existsSync(jsxFile):
|
|
497
|
+
break;
|
|
498
|
+
case fs.existsSync(tsfile):
|
|
499
|
+
break
|
|
500
|
+
default:
|
|
501
|
+
fs.unlinkSync(file)
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
505
|
+
case fs.existsSync(tsFile):
|
|
506
|
+
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
for await( var file of distPublic.scan('.')){
|
|
513
|
+
file = file.replace(/\\/g, '/');
|
|
514
|
+
let path = process.cwd() +'/public/' + file.split('dist/public/').pop()
|
|
515
|
+
if(!fs.existsSync(path)){
|
|
516
|
+
fs.unlinkSync(file)
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* @function organizeRoutes
|
|
524
|
+
* @description - Organizes routes that have param paths
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
const organizeRoutes = () => {
|
|
528
|
+
// if path starts with the same path and is dynamic then they are the same route and push params to the same route
|
|
529
|
+
let newRoutes = []
|
|
530
|
+
routes.forEach((route) => {
|
|
531
|
+
let exists = routes.find((r) => r.path.startsWith(route.path) && r.isParam === true)
|
|
532
|
+
if(exists){
|
|
533
|
+
let b4Params = route.params
|
|
534
|
+
route.params = []
|
|
535
|
+
route.params.push(b4Params)
|
|
536
|
+
route.params.push( {
|
|
537
|
+
jsFile: '/pages/' + exists.path + '/index.js',
|
|
538
|
+
folder: '/pages/' + exists.path,
|
|
539
|
+
paramData:exists.params
|
|
540
|
+
}
|
|
541
|
+
)
|
|
542
|
+
route.query = exists.query
|
|
543
|
+
newRoutes.push(route)
|
|
544
|
+
}
|
|
545
|
+
else if(!exists && !route.isParam){
|
|
546
|
+
newRoutes.push(route)
|
|
547
|
+
|
|
548
|
+
}
|
|
549
|
+
//remove param route that matched
|
|
550
|
+
routes = routes.filter((r) => exists ? r.path !== exists.path : true)
|
|
551
|
+
|
|
552
|
+
})
|
|
553
|
+
globalThis.routes = newRoutes
|
|
554
|
+
}
|
|
555
|
+
organizeRoutes()
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
if(globalThis.mode === 'dev' && !globalThis.oneAndDone || globalThis.mode === 'build'){
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @description - create an html file for each route
|
|
562
|
+
*/
|
|
563
|
+
routes.forEach((r)=>{
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
globalThis.generatorWs.send(JSON.stringify({
|
|
567
|
+
type:'generate',
|
|
568
|
+
PWD: process.cwd(),
|
|
569
|
+
output: process.cwd() + '/dist/pages/' + r.path + '/index.html',
|
|
570
|
+
file: '/pages/' + r.path + '/index.js',
|
|
571
|
+
folder:'/pages/' + r.path,
|
|
572
|
+
params: JSON.stringify(r.params),
|
|
573
|
+
}))
|
|
574
|
+
|
|
575
|
+
})
|
|
576
|
+
let i = setInterval(() => {
|
|
577
|
+
if(hasGenerated.length === routes.length){
|
|
578
|
+
globalThis.generatorWs.send(JSON.stringify({
|
|
579
|
+
type:'done'
|
|
580
|
+
}))
|
|
581
|
+
globalThis.oneAndDone = true
|
|
582
|
+
clearInterval(i)
|
|
583
|
+
}
|
|
584
|
+
}, 1000)
|
|
585
|
+
}
|
|
586
|
+
generateProviderRoutes( )
|
|
587
|
+
globalThis.isBuilding = false
|
|
588
|
+
console.log(`Finished building ${Math.round(bundleSize / 1000)}kb`)
|
|
589
|
+
bundleSize = 0
|
|
590
|
+
return void 0;
|
|
591
|
+
|
|
592
|
+
}
|
|
593
|
+
let port = 3000
|
|
594
|
+
switch (true) {
|
|
595
|
+
case process.argv.includes('dev') && !process.argv.includes('build') && !process.argv.includes('start'):
|
|
596
|
+
|
|
597
|
+
port = process.env.PORT || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
|
|
598
|
+
globalThis.oneAndDone = false
|
|
599
|
+
console.log(`
|
|
600
|
+
Vader.js v${fs.readFileSync(process.cwd() + '/node_modules/vaderjs/package.json', 'utf8').split('"version": "')[1].split('"')[0]}
|
|
601
|
+
- Watching for changes in ./pages
|
|
602
|
+
- Watching for changes in ./src
|
|
603
|
+
- Watching for changes in ./public
|
|
604
|
+
- Serving on port ${port}
|
|
605
|
+
`)
|
|
606
|
+
globalThis.mode = 'dev'
|
|
607
|
+
Server(port)
|
|
608
|
+
transForm()
|
|
609
|
+
Bun.spawn({
|
|
610
|
+
cwd: process.cwd() + '/node_modules/vaderjs/binaries/',
|
|
611
|
+
env:{
|
|
612
|
+
FOLDERS: 'pages,src,public',
|
|
613
|
+
PWD: process.cwd(),
|
|
614
|
+
},
|
|
615
|
+
cmd: ['node', 'watcher.js'],
|
|
616
|
+
onExit: (code) => {
|
|
617
|
+
console.log('Exited', code)
|
|
618
|
+
}
|
|
619
|
+
})
|
|
620
|
+
const ws = new WebSocket(`ws://localhost:${3434}`)
|
|
621
|
+
ws.on('open', () => {
|
|
622
|
+
console.log('Watching for changes...')
|
|
623
|
+
})
|
|
624
|
+
ws.on('message', (message) => {
|
|
625
|
+
message = JSON.parse(message.toString())
|
|
626
|
+
switch(true){
|
|
627
|
+
case message.type === 'change' && !globalThis.isBuilding:
|
|
628
|
+
console.log('Rebuilding...')
|
|
629
|
+
globalThis.clients.forEach((client) => {
|
|
630
|
+
client.send('reload')
|
|
631
|
+
})
|
|
632
|
+
transForm()
|
|
633
|
+
break;
|
|
634
|
+
case message.type === 'add' && !globalThis.isBuilding:
|
|
635
|
+
console.log('Rebuilding...')
|
|
636
|
+
globalThis.clients.forEach((client) => {
|
|
637
|
+
client.send('reload')
|
|
638
|
+
})
|
|
639
|
+
transForm()
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
})
|
|
644
|
+
|
|
645
|
+
break;
|
|
646
|
+
case process.argv.includes('build') && !process.argv.includes('dev') && !process.argv.includes('start'):
|
|
647
|
+
globalThis.devMode = false
|
|
648
|
+
globalThis.isProduction = true
|
|
649
|
+
globalThis.routeStates = []
|
|
650
|
+
console.log(`
|
|
651
|
+
Vader.js v1.3.3
|
|
652
|
+
Building to ./dist
|
|
653
|
+
`)
|
|
654
|
+
|
|
655
|
+
globalThis.mode = 'build'
|
|
656
|
+
transForm()
|
|
657
|
+
break;
|
|
658
|
+
case process.argv.includes('start') && !process.argv.includes('dev') && !process.argv.includes('build'):
|
|
659
|
+
port = process.env.PORT || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
|
|
660
|
+
console.log(`
|
|
661
|
+
Vader.js v1.3.3
|
|
662
|
+
Serving ./dist on port ${port}
|
|
663
|
+
url: http://localhost:${port}
|
|
664
|
+
`)
|
|
665
|
+
globalThis.devMode = false
|
|
666
|
+
globalThis.isProduction = true
|
|
667
|
+
|
|
668
|
+
Server(port)
|
|
669
|
+
break;
|
|
670
|
+
default:
|
|
671
|
+
// add color
|
|
672
|
+
console.log(`
|
|
673
|
+
Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
|
|
674
|
+
|
|
675
|
+
Usage: vader <command>
|
|
676
|
+
|
|
677
|
+
Commands:
|
|
678
|
+
|
|
679
|
+
vaderjs dev -p <number> Start the development server
|
|
680
|
+
|
|
681
|
+
vaderjs build Build the project to ./dist
|
|
682
|
+
|
|
683
|
+
vaderjs start -p <number> Production Mode (default 3000 or process.env.PORT)
|
|
684
|
+
|
|
685
|
+
Learn more about vader: https://vader-js.pages.dev/
|
|
686
|
+
|
|
687
|
+
`)
|
|
688
|
+
break;
|
|
689
|
+
|
|
690
|
+
}
|