vaderjs 1.4.7 → 1.4.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.
@@ -0,0 +1,97 @@
1
+ import {
2
+ Component,
3
+ e,
4
+ useState,
5
+ useEffect,
6
+ useFetch,
7
+ useAsyncState,
8
+ Fragment,
9
+ } from "vaderjs";
10
+ import { document } from "vaderjs/document";
11
+ import fs from "fs";
12
+ import ansiColors from "ansi-colors";
13
+ let path2 = require("path");
14
+ globalThis.Fragment = Fragment;
15
+ globalThis.window = {
16
+ location: {
17
+ hash: "",
18
+ host: "",
19
+ },
20
+ };
21
+ globalThis.Component = Component;
22
+ globalThis.e = e;
23
+ globalThis.useFetch = useFetch;
24
+ globalThis.useEffect = useEffect;
25
+ globalThis.useAsyncState = useAsyncState;
26
+ globalThis.useState = useState;
27
+ globalThis.genKey = () => {
28
+ return crypto.randomUUID();
29
+ };
30
+ globalThis.document = {
31
+ createElement: (tag) => { },
32
+ getElementById: (id) => { },
33
+ querySelector: (query) => { },
34
+ };
35
+ await Bun.build({
36
+ entrypoints: [process.env.ENTRYPOINT],
37
+ minify: true,
38
+ root: process.cwd() + "/dist/",
39
+ outdir: process.cwd() + "/dist/",
40
+ format: "esm",
41
+ ...(process.env.DEV ? { sourcemap: "inline" } : {}),
42
+ });
43
+ let isClass = function (element) {
44
+ return element.toString().startsWith("class");
45
+ };
46
+ const generatePage = async (
47
+ data = { path: process.env.INPUT, route: process.env.OUT }
48
+ ) => {
49
+ const { path, route } = data;
50
+ if (path.includes("root.js")) return;
51
+ let html = await import(path).then((m) => m.default);
52
+ let { head } = await import(path).then((m) => m);
53
+ let isFunction = false;
54
+ globalThis.isServer = true;
55
+ if (isClass(html)) {
56
+ html = new html();
57
+ html.Mounted = true;
58
+ html = html.render();
59
+ } else {
60
+ isFunction = true;
61
+ let instance = new Component();
62
+ html = html.bind(instance);
63
+ instance.render = html;
64
+ html = instance.render();
65
+ }
66
+
67
+ let h = document(html);
68
+ if (!fs.existsSync(process.cwd() + "/dist" + path2.dirname(route))) {
69
+ fs.mkdirSync(process.cwd() + "/dist" + path2.dirname(route), {
70
+ recursive: true,
71
+ });
72
+ }
73
+ let headHtml = "";
74
+ if (head) {
75
+ headHtml = document(head());
76
+ }
77
+ Bun.write(
78
+ process.cwd() + "/dist/" + route + "/index.html",
79
+ `<!DOCTYPE html><head>${headHtml}</head>${h}
80
+ <script type="module">
81
+ import c from '${process.env.filePath}'
82
+ import {render} from '/src/vader/index.js'
83
+ render(c, document.body.firstChild)
84
+ </script>
85
+ `
86
+ );
87
+
88
+ console.log(
89
+ ansiColors.blue(
90
+ `${process.env.filePath.replace(".js", ".jsx")} - ${parseInt(
91
+ process.env.size
92
+ ).toFixed(2)}kb`
93
+ )
94
+ );
95
+ process.exit(0);
96
+ };
97
+ generatePage({ path: process.env.INPUT, route: process.env.OUT });
package/config/index.ts CHANGED
@@ -3,7 +3,7 @@ type Config = {
3
3
  host?: string,
4
4
  plugins?: any[],
5
5
  generateTypes?: boolean,
6
- host_provider?: 'vercel' | 'netlify' | 'aws' | 'gcp' | 'azure' | 'heroku' | 'custom' | 'none',
6
+ host_provider?: 'vercel' | 'netlify' | 'aws' | 'gcp' | 'azure' | 'heroku' | 'custom' | 'apache' | 'none',
7
7
  host_provider_options?: {
8
8
  [key: string]: any
9
9
  },
package/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  //@ts-nocheck
2
2
  let isClassComponent = function(element) {
3
3
  return element.toString().startsWith("class");
4
- };
4
+ };
5
5
 
6
6
  const memoizes = new Map();
7
7
  //@ts-ignore
@@ -19,7 +19,7 @@ declare global {
19
19
  */
20
20
  let isServer: boolean;
21
21
  /**
22
- * @description - The params object is used to store the query parameters of the current URL
22
+ * @description - The params object is used to store the parameters of the current URL
23
23
  * @example
24
24
  * // URL: https://example.com?name=John
25
25
  * console.log(params.name) // John
@@ -56,12 +56,11 @@ export const useFetch = (url: string, options: any) => {
56
56
  };
57
57
 
58
58
  /**
59
- * @description A custom hook that allows you to use state in a functional component
60
- * @param key
59
+ * @description - Handle asyncronous promises and return the data or error;
61
60
  * @param promise
62
61
  * @returns
63
62
  */
64
- export const useAsyncState = (key: string, promise: Promise<any>) => {
63
+ export const useAsyncState = (promise: Promise<any>) => {
65
64
  return [null, () => {}];
66
65
  }
67
66
  export const useEffect = (callback:any, dependencies: any[]) => {
@@ -69,19 +68,18 @@ export const useEffect = (callback:any, dependencies: any[]) => {
69
68
  if (dependencies.length === 0) {
70
69
  callback();
71
70
  }
72
- }
71
+ }
73
72
 
74
- function memoizeComponent(Component: any) {
75
- let key = Component.toString();
76
- if (memoizes.has(key)) {
77
- return memoizes.get(key);
73
+ export const Fragment = (props: any, children: any) => {
74
+ return {
75
+ type: "div",
76
+ props: props || {},
77
+ children: children || [],
78
78
  }
79
- let instance = new Component();
80
- memoizes.set(key, instance);
81
- return instance;
82
-
83
79
  }
84
80
 
81
+ globalThis.Fragment = Fragment;
82
+
85
83
  /**
86
84
  * @description - Create a new element
87
85
  * @param element
@@ -90,30 +88,52 @@ function memoizeComponent(Component: any) {
90
88
  * @returns
91
89
  */
92
90
  export const e = (element: any, props: any, ...children: any[]) => {
93
- if(typeof element === "function"){
94
- let instance = new Component();
95
- instance.render = element;
96
- return instance.render()
97
- }
98
- return { type: element, props: props || {}, children: children || [] };
91
+ let instance;
92
+ switch (true){
93
+ case isClassComponent(element):
94
+ instance = new element();
95
+ instance.props = props;
96
+ instance.children = children;
97
+ return instance.render();
98
+ case typeof element === "function":
99
+ instance = new Component();
100
+ instance.render = element;
101
+ return instance.render();
102
+ default:
103
+ return { type: element, props: props || {}, children: children || [] };
104
+ }
99
105
  };
100
106
 
101
107
  /**
102
- * @description - Create a new element
108
+ * @description - Manage state and forceupdate specific affected elements
103
109
  * @param key
104
110
  * @param initialState
105
111
  * @returns {state, (newState: any, Element: string) => void, key}
106
112
  */
107
113
  export const useState = <T>(initialState: T) => {
108
- const setState = (newState: T, Element: string) => {
114
+ const setState = (newState: T) => {
109
115
  initialState = newState;
110
116
  }
111
117
  return [initialState, setState];
112
- }
113
- //@ts-ignore
114
- if(!isServer){
115
- window.state = {};
116
- }
118
+ }
119
+
120
+ /**
121
+ * @description - Create a new component
122
+ * @param element
123
+ * @param props
124
+ * @param children
125
+ * @returns
126
+ * @example
127
+ * const App = (props) => {
128
+ * return (
129
+ * <div>
130
+ * <h1>Hello, {props.name}</h1>
131
+ * </div>
132
+ * )
133
+ * }
134
+ *
135
+ * render(<App name="John" />, document.getElementById("root"));
136
+ */
117
137
  export class Component {
118
138
  props: any;
119
139
  state: any;
@@ -125,23 +145,12 @@ export class Component {
125
145
  constructor() {
126
146
  this.key = Math.random().toString(36).substring(7);
127
147
  this.props = {};
128
- //@ts-ignore
129
- if(!isServer){
130
- window.state[this.key] = {};
131
- this.state = window.state[this.key];
132
- }else{
133
- this.state = {};
134
- }
148
+ this.state = {};
135
149
  this.effect = [];
136
150
  this.Mounted = false;
137
- this.element = null;
138
-
139
-
140
- }
141
- setState(newState: any, Element: string) {
142
- globalThis.window.state[this.key] = { ...this.state, ...newState };
143
- this.forceUpdate(Element);
151
+ this.element = null;
144
152
  }
153
+
145
154
 
146
155
  useEffect(callback: any, dependencies: any[]) {
147
156
  if (dependencies.length === 0 && this.Mounted && this.effect.length === 0) {
@@ -182,22 +191,15 @@ export class Component {
182
191
  this.forceUpdate(this.key)
183
192
  };
184
193
 
185
- return [value, setValue];
194
+ return [value as T, setValue];
186
195
  }
187
196
 
188
197
 
189
198
 
190
- useFetch(url, options) {
191
- const { key } = options;
192
- if (!key) {
193
- throw new Error(`You must supply a key for the affected element in the options object`);
194
- }
195
-
199
+ useFetch(url: string, options: any) {
196
200
  const loadingKey = "loading_" + url;
197
201
  const errorKey = "error" + url;
198
- const dataKey = "_data" + url;
199
-
200
- // Initialize loading to false if loadingKey doesn't exist in state
202
+ const dataKey = "_data" + url;
201
203
  let [loading, setLoading] = this.useState(loadingKey, false);
202
204
  let [error, setError] = this.useState(errorKey, null);
203
205
  let [data, setData] = this.useState(dataKey, null);
@@ -209,13 +211,13 @@ export class Component {
209
211
  .then((res) => res.json())
210
212
  .then((data) => {
211
213
  //@ts-ignore
212
- setLoading(false, options.key);
213
- setData(data, options.key);
214
- this.forceUpdate(key);
214
+ setLoading(false);
215
+ setData(data);
216
+ this.forceUpdate(this.key);
215
217
  })
216
218
  .catch((err) => {
217
- setError(err, options.key);
218
- this.forceUpdate(key);
219
+ setError(err);
220
+ this.forceUpdate(this.key);
219
221
  });
220
222
  }
221
223
 
@@ -347,8 +349,12 @@ function memoizeClassComponent(Component: any) {
347
349
  return instance;
348
350
 
349
351
  }
350
-
351
- export function render(element: any, container) {
352
+ /**
353
+ * @description - Render jsx Componenet to the DOM
354
+ * @param element
355
+ * @param container
356
+ */
357
+ export function render(element: any, container: HTMLElement) {
352
358
  if (isClassComponent(element)) {
353
359
  const instance = new element();
354
360
  instance.Mounted = true;
@@ -356,8 +362,7 @@ export function render(element: any, container) {
356
362
  instance.element = el;
357
363
  container.innerHTML = "";
358
364
  container.replaceWith(el);
359
- } else {
360
- // memoizeComponent(element);
365
+ } else {
361
366
  let memoizedInstance = memoizeClassComponent(Component);
362
367
  memoizedInstance.Mounted = true;
363
368
  memoizedInstance.render = element.bind(memoizedInstance);
@@ -366,5 +371,4 @@ export function render(element: any, container) {
366
371
  container.replaceWith(el);
367
372
 
368
373
  }
369
- }
370
-
374
+ }
package/main.js CHANGED
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
+ import ansiColors from 'ansi-colors'
3
4
  import { Glob } from 'bun'
4
5
  const args = Bun.argv.slice(2)
5
6
  import fs from 'fs'
6
- import path from 'path'
7
-
7
+ import path from 'path'
8
8
  if (!fs.existsSync(process.cwd() + '/app')) {
9
9
  console.error(`App directory not found in ${process.cwd()}/app`)
10
10
  process.exit(1)
11
11
  }
12
12
  if (!fs.existsSync(process.cwd() + '/public')) {
13
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){
14
+ }
15
+ const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : null
16
+ if (!mode) {
17
17
  console.log(`
18
18
  Usage:
19
19
  bun vaderjs dev - Start development server output in dist/
@@ -22,15 +22,26 @@ if(!mode){
22
22
  process.exit(1)
23
23
  }
24
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
+
25
33
  let start = Date.now()
26
- console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
34
+ console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
27
35
  let { port, host, host_provider } = require(process.cwd() + '/config').default
28
-
36
+ if (host_provider === 'apache' && mode === 'development') {
37
+ console.warn('Note: SSR will not work with Apache')
38
+ }
29
39
  if (!fs.existsSync(process.cwd() + '/jsconfig.json')) {
30
40
  let json = {
31
41
  "compilerOptions": {
32
42
  "jsx": "react",
33
43
  "jsxFactory": "e",
44
+ "jsxFragmentFactory": "Fragment",
34
45
  }
35
46
  }
36
47
  await Bun.write(process.cwd() + '/jsconfig.json', JSON.stringify(json, null, 4))
@@ -43,27 +54,27 @@ const handleReplacements = (code, file) => {
43
54
  let newLines = []
44
55
  for (let line of lines) {
45
56
  let hasImport = line.includes('import')
46
- if(hasImport && line.includes('.jsx')){
57
+ if (hasImport && line.includes('.jsx')) {
47
58
  line = line.replace('.jsx', '.js')
48
59
  }
49
- if(hasImport && line.includes('.css')){
50
- try {
60
+ if (hasImport && line.includes('.css')) {
61
+ try {
51
62
  let url = path.join('/' + line.split("'")[1])
52
63
  let css = fs.readFileSync(process.cwd() + url, 'utf-8')
53
64
  line = '';
54
- if(!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
65
+ if (!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
55
66
  bindes.push(`<link rel="stylesheet" href="${url}">`)
56
- }
67
+ }
57
68
  fs.mkdirSync(process.cwd() + '/dist' + path.dirname(url), { recursive: true })
58
69
  fs.writeFileSync(process.cwd() + '/dist' + url, css)
59
- } catch (error) {
70
+ } catch (error) {
60
71
  console.error(error)
61
- }
62
- }
72
+ }
73
+ }
63
74
  if (line.toLowerCase().includes('genkey()')) {
64
75
  line = line.toLowerCase().replace('genkey()', `this.key = "${crypto.randomUUID()}"`)
65
76
  }
66
- if(!hasImport && line.includes('useFetch')){
77
+ if (!hasImport && line.includes('useFetch')) {
67
78
  line = line.replace('useFetch', 'this.useFetch')
68
79
  }
69
80
  if (!hasImport && line.includes('useState')) {
@@ -72,7 +83,7 @@ const handleReplacements = (code, file) => {
72
83
  b4 = line.replace('useState(', `this.useState('${key}',`)
73
84
  line = b4
74
85
  }
75
- if(!hasImport && line.includes('useAsyncState')){
86
+ if (!hasImport && line.includes('useAsyncState')) {
76
87
  let key = line.split(',')[0].split('[')[1].replace(' ', '')
77
88
  let b4 = line
78
89
  b4 = line.replace('useAsyncState(', `this.useAsyncState('${key}',`)
@@ -88,241 +99,180 @@ const handleReplacements = (code, file) => {
88
99
  let key = line.split(' ')[1].split('=')[0]
89
100
  b4 = line.replace('useRef(', `this.useRef('${key}',`)
90
101
  line = b4
91
- }
102
+ }
92
103
  newLines.push(line)
93
104
  }
94
105
  let c = newLines.join('\n')
95
106
  return c
96
- }
97
-
107
+ }
98
108
 
99
- async function generateApp() {
100
- // remove files from dist
101
- if(mode === 'development'){
102
- fs.rmdirSync(process.cwd() + '/dist', { recursive: true })
103
- }else{
104
- fs.mkdirSync(process.cwd() + '/dist', { recursive: true })
105
- }
106
- return new Promise(async (resolve, reject) => {
107
- let routes = new Bun.FileSystemRouter({
108
- dir: process.cwd() + '/app',
109
- style: 'nextjs'
110
- })
111
- routes.reload()
112
- globalThis.routes = routes.routes
113
- Object.keys(routes.routes).forEach(async (route) => {
114
- let r = routes.routes[route]
115
- let code = await Bun.file(r).text()
116
- code = handleReplacements(code)
117
- r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
118
- r = r.replace('.jsx', '.js')
119
- fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
120
- fs.writeFileSync(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r), `
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), `
121
136
  let route = window.location.pathname.split('/').filter(v => v !== '')
122
137
  let params = {
123
- ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}) .map(p => {
138
+ ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}).map(p => {
124
139
  return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p) + 1}]`
125
140
  }).join(',') : ""}
126
141
  }
127
142
  \n${code}
128
143
  `)
129
- fs.mkdirSync(process.cwd() + '/dev', { recursive: true })
130
- fs.writeFileSync(path.join(process.cwd() + '/dev/bundler.js'), `
131
- import { Component, e, useState, useEffect, useFetch, useAsyncState } from 'vaderjs'
132
- import { document } from 'vaderjs/document'
133
- import fs from 'fs'
134
- let path2 = require('path')
135
- globalThis.window = {
136
- location: {
137
- hash: '',
138
- host: '',
139
- }
140
- }
141
- globalThis.Component = Component
142
- globalThis.e = e
143
- globalThis.useState = useState
144
- globalThis.genKey = () => {
145
- return crypto.randomUUID()
146
- };
147
- globalThis.document = {
148
- createElement: (tag) => {},
149
- getElementById: (id) => {},
150
- }
151
- await Bun.build({
152
- entrypoints: [process.env.ENTRYPOINT],
153
- minify:true,
154
- root: process.cwd() + '/dist/',
155
- outdir: process.cwd() + '/dist/',
156
- format: 'esm',
157
- ...(process.env.DEV ? { sourcemap: 'inline' } : {})
158
- })
159
- let isClass = function(element) {
160
- return element.toString().startsWith('class');
161
- };
162
- const generatePage = async (data = {path: process.env.INPUT, route: process.env.OUT}) => {
163
- const { path, route } = data
164
- if(path.includes('root.js')) return
165
- let html = await import(path).then(m => m.default)
166
- let { head } = await import(path).then(m => m)
167
- let isFunction = false
168
- globalThis.isServer = true
169
- if(isClass(html)){
170
- html = new html()
171
- html.Mounted = true
172
- html = html.render()
173
- }else{
174
- isFunction = true
175
- let instance = new Component()
176
- html = html.bind(instance)
177
- instance.render = html
178
- html = instance.render()
179
- }
180
-
181
- let h = document(html)
182
- if(!fs.existsSync(process.cwd() + '/dist' + path2.dirname(route))){
183
- fs.mkdirSync(process.cwd() + '/dist' + path2.dirname(route), { recursive: true })
184
- }
185
- let headHtml = ''
186
- if(head){
187
- headHtml = document(head())
188
- }
189
- Bun.write(process.cwd() + '/dist/' + route + '/index.html', \`<!DOCTYPE html><head>\${headHtml}</head>\${h}
190
- <script type="module">
191
- import c from '\${process.env.filePath}'
192
- import {render} from '/src/vader/index.js'
193
- render(c, document.body.firstChild)
194
- </script>
195
- \`)
196
- }
197
- generatePage({path: process.env.INPUT, route: process.env.OUT})
198
- `)
199
-
200
- fs.mkdirSync(process.cwd() + '/dist/src/vader', { recursive: true })
201
- fs.writeFileSync(process.cwd() + '/dist/src/vader/index.js', await new Bun.Transpiler({
202
- loader: 'ts',
203
- }).transformSync(await Bun.file(require.resolve('vaderjs')).text()))
204
-
205
- const spawn = Bun.spawn({
206
- cmd: ['bun', 'run', './dev/bundler.js'],
207
- cwd: process.cwd(),
208
- stdout: 'inherit',
209
- env: {
210
- ENTRYPOINT: path.join(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r)),
211
- ROOT: process.cwd() + '/app/',
212
- OUT: path.dirname(r),
213
- file: process.cwd() + '/dist/' + path.dirname(r) + '/index.js',
214
- DEV: mode === 'development',
215
- filePath: r,
216
- INPUT: `../app/${r.replace('.js', '.jsx')}`,
217
- },
218
- onExit({exitCode: code}) {
219
- if (code === 0) {
220
- console.log('Build complete')
221
- resolve()
222
- } else {
223
- reject()
224
- }
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')
225
147
  }
226
- })
227
-
228
- })
229
148
 
230
- switch(host_provider){
231
- case 'vercel':
232
-
233
- let vercelData = {
234
- rewrites: []
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`)
235
151
  }
236
-
237
- for(let route in routes.routes){
238
- let {filePath, kind, name, params, pathname,query} = routes.match(route)
239
- let exists = vercelData.rewrites.find(v => v.source === `/${route}`)
240
- let paramString = ''
241
- if(pathname === '/'){
242
- continue
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
+ }
243
176
  }
244
- if(params){
245
- paramString = Object.keys(params).map(p => `:${p}`).join('/')
246
- }
247
- // replace double slashes
248
- paramString = paramString.replace(/\/\//g, '/')
249
- let base = path.dirname(route)
250
- if(base.includes('[')){
251
- base = base.split('[')[0].split('/').filter(v => v !== '').join('/')
252
- }else{
253
- base = base.split('/').filter(v => v !== '').join('/')
177
+ })
178
+
179
+ })
180
+
181
+ switch (host_provider) {
182
+ case 'vercel':
183
+
184
+ let vercelData = {
185
+ rewrites: []
254
186
  }
255
-
256
- if(!exists){
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
+
257
207
  vercelData.rewrites.push({
258
208
  source: `/${base}/${paramString}`,
259
209
  destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
260
210
  })
261
211
  }
262
- }
263
- fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
212
+
213
+ fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
214
+ break;
215
+ }
264
216
 
265
- break;
266
- }
267
-
268
- })
217
+ })
269
218
 
270
219
  }
271
220
 
272
221
  await generateApp()
273
- function handleFiles(){
274
- return new Promise(async (resolve, reject) => {
275
- try {
276
- let glob = new Glob('public/**/*')
277
- for await (var i of glob.scan()){
278
- let file = i
279
- fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
280
- if(fs.existsSync(path.join(process.cwd() + '/dist', file))){
281
- fs.rmSync(path.join(process.cwd() + '/dist', file))
282
- }
283
- fs.copyFileSync(file, path.join(process.cwd() + '/dist', file))
284
- }
285
- resolve()
286
- } catch (error) {
287
- reject(error)
288
- }
289
- })
290
- }
291
- await handleFiles()
292
- let isBuilding = false;
293
- let timeout = null
294
- if(mode === 'development'){
295
- const watcher = fs.watch(path.join(process.cwd() + '/app'), { recursive: true })
296
- const publicWatcher = fs.watch(path.join(process.cwd() + '/public'), { recursive: true })
297
- publicWatcher.on('change', async (event, filename) => {
298
- try {
299
- await handleFiles()
300
- clients.forEach(c => {
301
- c.send('reload')
302
- })
303
- } catch (error) {
304
- console.error(error)
305
- }
306
- })
307
- watcher.on('change', async (event, filename) => {
222
+ function handleFiles() {
223
+ return new Promise(async (resolve, reject) => {
308
224
  try {
309
- await generateApp()
310
- handleFiles()
311
- clients.forEach(c => {
312
- c.send('reload')
313
- })
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()
314
235
  } catch (error) {
315
- console.error(error)
236
+ reject(error)
316
237
  }
317
-
318
- })
319
- watcher.on('error', (err) => {
320
- console.error(err)
321
238
  })
322
239
  }
240
+ await handleFiles()
323
241
  globalThis.clients = []
324
242
 
325
- if(mode === 'development'){
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
+
326
276
  let server = Bun.serve({
327
277
  port: port || 8080,
328
278
  websocket: {
@@ -335,34 +285,34 @@ if(mode === 'development'){
335
285
  c.send(message)
336
286
  })
337
287
  },
338
-
288
+
339
289
  },
340
290
  async fetch(req, res) {
341
- if(res.upgrade(req)){
291
+ if (res.upgrade(req)) {
342
292
  return new Response('Upgraded', { status: 101 })
343
293
  }
344
-
345
- let url = new URL(req.url)
346
- if(url.pathname.includes('.')){
347
- let file = await Bun.file(path.join(process.cwd() + '/dist' + url.pathname))
348
- if(!await file.exists()) return new Response('Not found', { status: 404 })
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 })
349
299
  return new Response(await file.text(), {
350
300
  headers: {
351
- 'Content-Type': file.type
301
+ 'Content-Type': file.type
352
302
  }
353
303
  })
354
- }
304
+ }
355
305
  let router = new Bun.FileSystemRouter({
356
306
  dir: process.cwd() + '/app',
357
307
  style: 'nextjs'
358
308
  })
359
- router.reload()
309
+ router.reload()
360
310
  let route = router.match(url.pathname)
361
- if(!route){
311
+ if (!route) {
362
312
  return new Response('Not found', { status: 404 })
363
- }
364
- let p = route.pathname;
365
- let base = path.dirname(route.filePath)
313
+ }
314
+ let p = route.pathname;
315
+ let base = path.dirname(route.filePath)
366
316
  base = base.replace(path.join(process.cwd() + '/app'), '')
367
317
  base = base.replace(/\\/g, '/').replace('/app', '/dist')
368
318
  return new Response(await Bun.file(path.join(base, 'index.html')).text() + `
@@ -378,12 +328,10 @@ if(mode === 'development'){
378
328
  headers: {
379
329
  'Content-Type': 'text/html'
380
330
  }
381
- })
331
+ })
382
332
  }
383
333
  })
384
-
385
- console.log(`Server running on http://localhost:${server.port}`)
386
- }else{
334
+ } else {
387
335
  console.log(`Build complete in ${Date.now() - start}ms at ${new Date().toLocaleTimeString()}`)
388
336
  process.exit(0)
389
337
  }
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "1.4.7",
3
+ "version": "1.4.9",
4
4
  "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "main":"./index.js",
6
6
  "bin": {
7
7
  "vaderjs": "./main.js"
8
+ },
9
+ "dependencies": {
10
+ "ansi-colors":"latest"
8
11
  }
9
12
  }