vaderjs 1.4.4 → 1.4.5

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.
Files changed (3) hide show
  1. package/index.ts +100 -61
  2. package/main.js +90 -20
  3. package/package.json +1 -1
package/index.ts CHANGED
@@ -1,18 +1,43 @@
1
+ //@ts-nocheck
1
2
  let isClassComponent = function(element) {
2
3
  return element.toString().startsWith("class");
3
4
  };
4
5
 
6
+ const memoizes = new Map();
7
+ //@ts-ignore
8
+
5
9
  declare global {
6
10
  interface Window {
7
11
  onbeforeunload: any;
8
12
  localStorage: any;
9
13
  sessionStorage: any;
14
+ state: any;
10
15
  }
11
16
  const genKey: any;
12
17
  let isServer: boolean;
18
+ /**
19
+ * @description - The params object is used to store the query parameters of the current URL
20
+ * @example
21
+ * // URL: https://example.com?name=John
22
+ * console.log(params.name) // John
23
+ * @example
24
+ * // URL: https://example.com/:name/:age
25
+ * // GO: https://example.com/John/20
26
+ * console.log(params.name) // John
27
+ * console.log(params.age) // 20
28
+ */
29
+ let params: { [key: string]: string };
13
30
  }
14
31
  //@ts-ignore
15
32
  globalThis.isServer = typeof window === "undefined";
33
+ //@ts-ignore
34
+ globalThis.params = {
35
+ [Symbol.iterator]: function* () {
36
+ for (const key in this) {
37
+ yield [key, this[key]];
38
+ }
39
+ },
40
+ };
16
41
 
17
42
 
18
43
  /**
@@ -41,6 +66,17 @@ export const useEffect = (callback:any, dependencies: any[]) => {
41
66
  }
42
67
  }
43
68
 
69
+ function memoizeComponent(Component: any) {
70
+ let key = Component.toString();
71
+ if (memoizes.has(key)) {
72
+ return memoizes.get(key);
73
+ }
74
+ let instance = new Component();
75
+ memoizes.set(key, instance);
76
+ return instance;
77
+
78
+ }
79
+
44
80
  /**
45
81
  * @description - Create a new element
46
82
  * @param element
@@ -63,20 +99,16 @@ export const e = (element: any, props: any, ...children: any[]) => {
63
99
  * @param initialState
64
100
  * @returns {state, (newState: any, Element: string) => void, key}
65
101
  */
66
- export const useState = (key, initialState) => {
67
- const instance = new Component;
68
- return [instance.state[key],
69
- /**
70
- * @description - Set the state of the component
71
- * @param newState
72
- * @param Element
73
- */
74
- (newState: any, Element: string) => {
75
- instance.setState({ [key]: newState }, Element);
76
- }, key];
102
+ export const useState = <T>(initialState: T) => {
103
+ const setState = (newState: T, Element: string) => {
104
+ initialState = newState;
105
+ }
106
+ return [initialState, setState];
107
+ }
108
+ //@ts-ignore
109
+ if(!isServer){
110
+ window.state = {};
77
111
  }
78
- //@ts-ignore
79
- let state = {};
80
112
  export class Component {
81
113
  props: any;
82
114
  state: any;
@@ -88,21 +120,24 @@ export class Component {
88
120
  constructor() {
89
121
  this.key = Math.random().toString(36).substring(7);
90
122
  this.props = {};
91
- //@ts-ignore
92
- state[this.key] = {};
93
- this.state = state[this.key];
123
+ //@ts-ignore
124
+ if(!isServer){
125
+ window.state[this.key] = {};
126
+ this.state = window.state[this.key];
127
+ }else{
128
+ this.state = {};
129
+ }
94
130
  this.effect = [];
95
131
  this.Mounted = false;
96
132
  this.element = null;
97
133
  }
98
134
  setState(newState: any, Element: string) {
99
- state[this.key] = { ...this.state, ...newState };
100
- console.log(state[this.key]);
135
+ globalThis.window.state[this.key] = { ...this.state, ...newState };
101
136
  this.forceUpdate(Element);
102
137
  }
103
138
 
104
139
  useEffect(callback: any, dependencies: any[]) {
105
- if (dependencies.length === 0 && this.Mounted && this.effect.length === 0) {
140
+ if (dependencies.length === 0 && this.Mounted && this.effect.length === 0) {
106
141
  callback();
107
142
  this.effect.push(callback);
108
143
  }else{
@@ -114,34 +149,26 @@ export class Component {
114
149
  }
115
150
  }
116
151
  }
117
- useState(key: string, initialState: any) {
118
- if (!this.state[key]) {
119
- console.log(`State ${key} does not exist`)
120
- this.state[key] = initialState;
121
- }
152
+ useState <T> (key: string, defaultValue: T) {
153
+ let value = sessionStorage.getItem("state_" + key) || defaultValue;
154
+ typeof value === "string" ? value = JSON.parse(value) : value;
122
155
 
123
- window.onbeforeunload = () => {
124
- sessionStorage.setItem("state", JSON.stringify({}));
156
+ window.onbeforeunload = function() {
157
+ sessionStorage.removeItem("state_" + key);
158
+ }
159
+ const setValue = (newValue: T ,element: string) => {
160
+ value = newValue;
161
+ sessionStorage.setItem("state_" + key, JSON.stringify(value));
162
+ this.state[key] = value;
163
+ this.forceUpdate(element)
125
164
  }
126
- /**
127
- *
128
- * @param {*} newState
129
- * @param {*} Element - The element affected by the state change
130
- */
131
- const setState = (newState, Element) => {
132
- this.prevState = { ...this.state };
133
- this.state[key] = newState;
134
- state[this.key] = { ...this.state };
135
- this.forceUpdate(Element);
136
- };
137
- const returnKey = key;
138
- return [this.state[key], setState, returnKey];
165
+ return [value, setValue];
139
166
  }
167
+
168
+
140
169
 
141
170
  useFetch(url, options) {
142
- const { key } = options;
143
-
144
- console.log(key);
171
+ const { key } = options;
145
172
  if (!key) {
146
173
  throw new Error(`You must supply a key for the affected element in the options object`);
147
174
  }
@@ -151,23 +178,23 @@ export class Component {
151
178
  const dataKey = "_data" + url;
152
179
 
153
180
  // Initialize loading to false if loadingKey doesn't exist in state
154
- const loading = state[this.key][loadingKey] !== undefined ? state[this.key][loadingKey] : true;
155
- const error = state[this.key][errorKey] || null;
156
- const data = state[this.key][dataKey] || null;
181
+ let [loading, setLoading] = this.useState(loadingKey, false);
182
+ let [error, setError] = this.useState(errorKey, null);
183
+ let [data, setData] = this.useState(dataKey, null);
157
184
 
158
185
  if (loading && !error && !data) {
159
- state[this.key][loadingKey] = true;
186
+ this.state[this.key][loadingKey] = true;
160
187
 
161
188
  fetch(url, options)
162
189
  .then((res) => res.json())
163
190
  .then((data) => {
164
- state[this.key][dataKey] = data;
165
- state[this.key][loadingKey] = false;
191
+ //@ts-ignore
192
+ setLoading(false, options.key);
193
+ setData(data, options.key);
166
194
  this.forceUpdate(key);
167
195
  })
168
196
  .catch((err) => {
169
- state[this.key][errorKey] = err;
170
- state[this.key][loadingKey] = false;
197
+ setError(err, options.key);
171
198
  this.forceUpdate(key);
172
199
  });
173
200
  }
@@ -179,7 +206,7 @@ export class Component {
179
206
  forceUpdate(key) {
180
207
  //@ts-ignore
181
208
  let el = Array.from(document.querySelectorAll("*")).filter((el2: any) =>{ return el2.key === key})[0];
182
- let newl = this.parseToElement(this.render());
209
+ let newl = this.parseToElement(this.render());
183
210
  if(newl.key !== key){
184
211
  //@ts-ignore
185
212
  newl = Array.from(newl.children).filter((el2) => el2.key === key)[0];
@@ -239,8 +266,7 @@ export class Component {
239
266
  continue;
240
267
  }
241
268
  //@ts-ignore
242
- if (key.startsWith("on")) {
243
- console.log(key.substring(2).toLowerCase());
269
+ if (key.startsWith("on")) {
244
270
  el.addEventListener(key.substring(2).toLowerCase(), attributes[key]);
245
271
  continue;
246
272
  }
@@ -281,8 +307,21 @@ export class Component {
281
307
  render() {
282
308
  return "";
283
309
  }
310
+
311
+
284
312
  }
285
313
 
314
+ function memoizeClassComponent(Component: any) {
315
+ let key = Component.toString();
316
+ if (memoizes.has(key)) {
317
+ return memoizes.get(key);
318
+ }
319
+ let instance = new Component();
320
+ memoizes.set(key, instance);
321
+ return instance;
322
+
323
+ }
324
+
286
325
  export function render(element: any, container) {
287
326
  if (isClassComponent(element)) {
288
327
  const instance = new element();
@@ -292,14 +331,14 @@ export function render(element: any, container) {
292
331
  container.innerHTML = "";
293
332
  container.replaceWith(el);
294
333
  } else {
295
- const newInstance = new Component;
296
- element = element.bind(newInstance);
297
- newInstance.render = element;
298
- newInstance.Mounted = true;
299
- let el = newInstance.toElement();
300
- newInstance.element = el;
301
- container.innerHTML = "";
302
- container.replaceWith(el);
334
+ // memoizeComponent(element);
335
+ let memoizedInstance = memoizeClassComponent(Component);
336
+ memoizedInstance.Mounted = true;
337
+ memoizedInstance.render = element.bind(memoizedInstance);
338
+ let el = memoizedInstance.toElement();
339
+ container.innerHTML = "";
340
+ container.replaceWith(el);
341
+
303
342
  }
304
343
  }
305
344
 
package/main.js CHANGED
@@ -24,7 +24,7 @@ if(!mode){
24
24
 
25
25
  let start = Date.now()
26
26
  console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
27
- let { port, host, } = require(process.cwd() + '/config').default
27
+ let { port, host, host_provider } = require(process.cwd() + '/config').default
28
28
 
29
29
  if (!fs.existsSync(process.cwd() + '/jsconfig.json')) {
30
30
  let json = {
@@ -96,21 +96,32 @@ const handleReplacements = (code, file) => {
96
96
  }
97
97
 
98
98
 
99
- async function generateApp() {
99
+ async function generateApp() {
100
+ // remove files from dist
101
+ fs.rmdirSync(process.cwd() + '/dist', { recursive: true })
100
102
  return new Promise(async (resolve, reject) => {
101
103
  let routes = new Bun.FileSystemRouter({
102
104
  dir: process.cwd() + '/app',
103
105
  style: 'nextjs'
104
106
  })
105
- globalThis.routes = routes.routes
107
+ routes.reload()
108
+ globalThis.routes = routes.routes
106
109
  Object.keys(routes.routes).forEach(async (route) => {
107
110
  let r = routes.routes[route]
108
111
  let code = await Bun.file(r).text()
109
112
  code = handleReplacements(code)
110
113
  r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
111
- r = r.replace('.jsx', '.js')
112
- fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
113
- fs.writeFileSync(process.cwd() + '/dist/' + r, code)
114
+ r = r.replace('.jsx', '.js')
115
+ fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
116
+ fs.writeFileSync(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r), `
117
+ let route = window.location.pathname.split('/').filter(v => v !== '')
118
+ let params = {
119
+ ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}) .map(p => {
120
+ return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p) + 1}]`
121
+ }).join(',') : ""}
122
+ }
123
+ \n${code}
124
+ `)
114
125
  fs.mkdirSync(process.cwd() + '/dev', { recursive: true })
115
126
  fs.writeFileSync(path.join(process.cwd() + '/dev/bundler.js'), `
116
127
  import { Component, e, useState, useEffect, useFetch, useAsyncState } from 'vaderjs'
@@ -134,14 +145,16 @@ async function generateApp() {
134
145
  getElementById: (id) => {},
135
146
  }
136
147
  await Bun.build({
137
- entrypoints: [process.cwd() + '/dist/' + process.env.ENTRYPOINT],
138
- minify:true,
139
- root: process.cwd() + '/dist',
140
- outdir: process.cwd() + '/dist',
141
- })
148
+ entrypoints: [process.env.ENTRYPOINT],
149
+ minify:true,
150
+ root: process.cwd() + '/dist/',
151
+ outdir: process.cwd() + '/dist/',
152
+ format: 'esm',
153
+ ...(process.env.DEV ? { sourcemap: 'inline' } : {})
154
+ })
142
155
  let isClass = function(element) {
143
156
  return element.toString().startsWith('class');
144
- };
157
+ };
145
158
  const generatePage = async (data = {path: process.env.INPUT, route: process.env.OUT}) => {
146
159
  const { path, route } = data
147
160
  if(path.includes('root.js')) return
@@ -168,10 +181,10 @@ async function generateApp() {
168
181
  let headHtml = ''
169
182
  if(head){
170
183
  headHtml = document(head())
171
- }
184
+ }
172
185
  Bun.write(process.cwd() + '/dist/' + route + '/index.html', \`<!DOCTYPE html><head>\${headHtml}</head>\${h}
173
186
  <script type="module">
174
- import c from '\${route === '/' ? './index.js' : route + '/index.js'}'
187
+ import c from '\${process.env.filePath}'
175
188
  import {render} from '/src/vader/index.js'
176
189
  render(c, document.body.firstChild)
177
190
  </script>
@@ -183,15 +196,20 @@ async function generateApp() {
183
196
  fs.mkdirSync(process.cwd() + '/dist/src/vader', { recursive: true })
184
197
  fs.writeFileSync(process.cwd() + '/dist/src/vader/index.js', await new Bun.Transpiler({
185
198
  loader: 'ts',
186
- }).transformSync(await Bun.file(require.resolve('vaderjs')).text()))
199
+ minify: true,
200
+ }).transformSync(await Bun.file(require.resolve('vaderjs')).text()))
201
+
187
202
  const spawn = Bun.spawn({
188
203
  cmd: ['bun', 'run', './dev/bundler.js'],
189
204
  cwd: process.cwd(),
190
205
  stdout: 'inherit',
191
206
  env: {
192
- ENTRYPOINT: r,
207
+ ENTRYPOINT: path.join(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r)),
193
208
  ROOT: process.cwd() + '/app/',
194
- OUT: route,
209
+ OUT: path.dirname(r),
210
+ file: process.cwd() + '/dist/' + path.dirname(r) + '/index.js',
211
+ DEV: mode === 'development',
212
+ filePath: r,
195
213
  INPUT: `../app/${r.replace('.js', '.jsx')}`,
196
214
  },
197
215
  onExit({exitCode: code}) {
@@ -205,6 +223,44 @@ async function generateApp() {
205
223
  })
206
224
 
207
225
  })
226
+
227
+ switch(host_provider){
228
+ case 'vercel':
229
+
230
+ let vercelData = {
231
+ rewrites: []
232
+ }
233
+
234
+ for(let route in routes.routes){
235
+ let {filePath, kind, name, params, pathname,query} = routes.match(route)
236
+ let exists = vercelData.rewrites.find(v => v.source === `/${route}`)
237
+ let paramString = ''
238
+ if(pathname === '/'){
239
+ continue
240
+ }
241
+ if(params){
242
+ paramString = Object.keys(params).map(p => `:${p}`).join('/')
243
+ }
244
+ // replace double slashes
245
+ paramString = paramString.replace(/\/\//g, '/')
246
+ let base = path.dirname(route)
247
+ if(base.includes('[')){
248
+ base = base.split('[')[0].split('/').filter(v => v !== '').join('/')
249
+ }else{
250
+ base = base.split('/').filter(v => v !== '').join('/')
251
+ }
252
+
253
+ if(!exists){
254
+ vercelData.rewrites.push({
255
+ source: `/${base}/${paramString}`,
256
+ destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
257
+ })
258
+ }
259
+ }
260
+ fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
261
+
262
+ break;
263
+ }
208
264
 
209
265
  })
210
266
 
@@ -245,6 +301,8 @@ if(mode === 'development'){
245
301
  watcher.on('change', async (event, filename) => {
246
302
  try {
247
303
  await generateApp()
304
+
305
+ handleFiles()
248
306
  clients.forEach(c => {
249
307
  c.send('reload')
250
308
  })
@@ -289,14 +347,26 @@ if(mode === 'development'){
289
347
  }
290
348
  })
291
349
  }
292
- return new Response(fs.readFileSync(process.cwd() + '/dist/' + url.pathname + '/index.html') + `
350
+ let router = new Bun.FileSystemRouter({
351
+ dir: process.cwd() + '/app',
352
+ style: 'nextjs'
353
+ })
354
+ router.reload()
355
+ let route = router.match(url.pathname)
356
+ if(!route){
357
+ return new Response('Not found', { status: 404 })
358
+ }
359
+ let p = route.pathname;
360
+ let base = path.dirname(route.filePath)
361
+ base = base.replace(path.join(process.cwd() + '/app'), '')
362
+ base = base.replace(/\\/g, '/').replace('/app', '/dist')
363
+ return new Response(await Bun.file(path.join(base, 'index.html')).text() + `
293
364
  <script>
294
365
  let ws = new WebSocket('ws://localhost:${server.port}')
295
366
  ws.onmessage = (e) => {
296
367
  if(e.data === 'reload'){
297
368
  window.location.reload()
298
- }
299
- console.log(e.data)
369
+ }
300
370
  }
301
371
  </script>
302
372
  `, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "main":"./index.js",
6
6
  "bin": {