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.
- package/bundler/index.js +97 -0
- package/config/index.ts +1 -1
- package/index.ts +66 -62
- package/main.js +184 -236
- package/package.json +4 -1
package/bundler/index.js
ADDED
|
@@ -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
|
|
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
|
|
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 = (
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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 -
|
|
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
|
|
114
|
+
const setState = (newState: T) => {
|
|
109
115
|
initialState = newState;
|
|
110
116
|
}
|
|
111
117
|
return [initialState, setState];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
|
213
|
-
setData(data
|
|
214
|
-
this.forceUpdate(key);
|
|
214
|
+
setLoading(false);
|
|
215
|
+
setData(data);
|
|
216
|
+
this.forceUpdate(this.key);
|
|
215
217
|
})
|
|
216
218
|
.catch((err) => {
|
|
217
|
-
setError(err
|
|
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
|
-
|
|
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' :
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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 >
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
231
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
212
|
+
|
|
213
|
+
fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
264
216
|
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
})
|
|
217
|
+
})
|
|
269
218
|
|
|
270
219
|
}
|
|
271
220
|
|
|
272
221
|
await generateApp()
|
|
273
|
-
function handleFiles(){
|
|
274
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
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':
|
|
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.
|
|
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
|
}
|