vaderjs 1.3.7-alpha-3 → 1.4.0-169o234

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 CHANGED
@@ -1,167 +1,253 @@
1
- <p align="center">
2
- <a href="https://vader-js.pages.dev">
3
- <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="/icon.jpeg">
5
- <img src="logo.png" height="128">
6
- </picture>
7
- <h1 align="center">Vader.js</h1>
8
- </a>
9
- </p>
10
-
11
- # VaderJS: A Powerful Reactive Framework for SPAs inspired by react.js!
12
-
13
- [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/vaderjs.svg?style=flat)](https://www.npmjs.com/package/vaderjs)
14
-
15
-
16
-
17
- ## Get Started
18
-
19
- 1. Install Bun.js
20
-
21
- Need more help? [Bun guide](https://bun.sh/docs/installation)
22
-
23
- ```sh
24
- curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
25
- ```
26
-
27
- > Skip if you are not using windows!
28
- [How to open folder in wsl](https://code.visualstudio.com/docs/remote/wsl)
29
-
30
- 1. Open a WSL terminal window (using the start menu item or by typing wsl from a command prompt / PowerShell).
31
-
32
- 2. Navigate to a folder you'd like to open in VS Code (including, but not limited to, Windows filesystem mounts like /mnt/c)
33
-
34
- 3. Type code . in the terminal. When doing this for the first time, you should see VS Code fetching components needed to run in WSL. This should only take a short while, and is only needed once.
35
-
36
- Open folder in vsc - open terminal and type wsl then type `code .` and continue to the next step
37
-
38
- 2. Installing vaderjs
39
-
40
- ```bash
41
- npm i vaderjs
42
- ```
43
-
44
- 3. Create Proper Folders
45
-
46
- Create a pages folder - which allows you to have nextjs page like routing via buns file based router
47
-
48
- ```bash
49
- /pages/index.jsx = /
50
- /pages/home/[page].jsx = /home/:page
51
- /pages/path/index.jsx = /path/file
52
- ```
53
- Keyword folders - all files are passed from these folders to the `dist` folder
54
-
55
- ```bash
56
-
57
- pages - used for jsx route files
58
- src - used for your jsx components / javascript files
59
- public - used for anything
60
-
61
- ```
62
-
63
-
64
-
65
- 4. And your done - Run `bun run vader --build` and the compiled output is visible inside of the `/dist/` folder!
66
-
67
- ## Key Features & Examples
68
-
69
- ### File based routing
70
- vader's compiler automatically handles routing so you wont need to!
71
- below is valid paths for parsing per [Buns fileSystem Routing Api](https://bun.sh/docs/api/file-system-router)
72
-
73
- ```bash
74
- /pages/index.jsx = /
75
- /pages/home/[page].jsx = /home/:page
76
- /pages/path/index.jsx = /path/file
77
-
78
-
79
- ```
80
- You can grab the request object from `this.request` and response object from `this.response!`
81
-
82
-
83
- ### Simplified Component Creation
84
-
85
- ```jsx
86
- // pages/home.jsx
87
- let {Component, useState} = await import('./vader.js') // always use ./vader.js as files reference vaders main file
88
- let Mycomponent = await require('./pages/mycomponent')
89
- class Home extends Vader {
90
- constructor() {
91
- super();
92
- this.key = '2'
93
- }
94
- render() {
95
- return <>
96
- <div key={this.key}>
97
- <p>Hello World</p>
98
- </div>
99
- <Mycomponent ..props />
100
- </>
101
- }
102
- }
103
-
104
- return {default:Home}
105
- ```
106
-
107
-
108
-
109
- ### State Management
110
-
111
- ```jsx
112
- let {Component, useState} = await import('./vader.js')
113
-
114
- class MyApp extends Component{
115
- contructor(){
116
- super()
117
- this.key = 'static key for state changes'
118
- }
119
-
120
- render(){
121
- let [count, setCount] = useState(0)
122
- function increment(){
123
- setCount(count()+ 1)
124
- }
125
- return <>
126
- <p>Count is ${count}</p>
127
- <button onclick={()=>increment()}>Increment</button>
128
- </>
129
-
130
- }
131
- }
132
-
133
- return {default:MyApp}
134
- ```
135
-
136
-
137
- ### Function Binding
138
-
139
- Vaderjs allows you to bind functions directly to html elements just like react
140
-
141
- ```javascript
142
- // vader uses params[0] as the event target object and other parameters resolve after
143
-
144
- function click(event, otherparams){
145
- console.log(event.target, otherparams)
146
- }
147
-
148
- return <>
149
- <button onclick={()=>click()}>Click Me</button>
150
- </>
151
- ```
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
- ## License
162
-
163
- VaderJS is released under the MIT License. See the [LICENSE](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) file for details.
164
-
165
- ## Join the Community
166
-
167
- Connect with the VaderJS community on [GitHub](https://github.com/Postr-Inc/Vader.js). Contribute, share feedback, and improve VaderJS for SPA development.
1
+
2
+ <p align="center">
3
+ <a href="https://vader-js.pages.dev">
4
+ <picture>
5
+ <source media="(prefers-color-scheme: dark)" srcset="/icon.jpeg">
6
+ <img src="./logo.png" height="128">
7
+ </picture>
8
+ <h1 align="center">Vader.js</h1>
9
+ </a>
10
+ </p>
11
+
12
+ # VaderJS: A Powerful Reactive Framework for SPAs inspired by react.js!
13
+
14
+ [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/vaderjs.svg?style=flat)](https://www.npmjs.com/package/vaderjs)
15
+
16
+
17
+ > Do not use any alpha versions as these where changed multiple times any version under latest is considered lts and are deemed to be stable
18
+ ## Get Started
19
+
20
+ 1. Installing Bun.js - (Required)
21
+ > Warning - do not use wsl version of bun with vader on windows it will not work due to path resolution use the experimental version :}
22
+
23
+ ([Install Bun](https://bun.sh/docs/installation))
24
+
25
+ 2. Install vaderjs
26
+
27
+ ```bash
28
+ bun add vaderjs@latest or npx vaderjs@latest
29
+ ```
30
+
31
+ 4. Create Proper Folders
32
+
33
+ Create a pages folder - which allows you to have nextjs page like routing via buns file based router
34
+
35
+ Tip: Each folder can be deep nested up to 4 levels!
36
+
37
+ ```bash
38
+ /pages/index.jsx = /
39
+ /pages/home/[page].jsx = /home/:page
40
+ /pages/path/index.jsx = /path/
41
+ /pages/test/[...]/index.jsx = /path/test/*
42
+ /pages/route/[param1]/[param2].jsx = /path/route/:param1/:param2
43
+ ```
44
+ Keyword folders - all files are passed from these folders to the `dist` folder
45
+
46
+ ```bash
47
+
48
+ pages - used for jsx route files
49
+ src - used for your jsx components / javascript files
50
+ public - used for anything
51
+
52
+ ```
53
+
54
+
55
+
56
+ 5. And your done - Run `npx vaderjs` and the compiled output is visible inside of the `/dist/` folder!
57
+
58
+
59
+ ## Key Features & Examples
60
+
61
+ ### File based routing
62
+ vader's compiler automatically handles routing so you wont need to! - it uses a similar page routing to nextjs
63
+
64
+ ```bash
65
+ /pages/index.jsx = /
66
+ /pages/home/[page].jsx = /home/:page
67
+ /pages/path/index.jsx = /path/
68
+ /pages/path/[...].jsx = /path/*
69
+
70
+ ```
71
+ For pages that have [params] you can derive it using this.request
72
+
73
+
74
+ # Usage
75
+
76
+
77
+ ```jsx
78
+ // pages/home.jsx
79
+ import {Component, useState, useRef} = from 'vaderjs/client'
80
+ import Mycomponent from './src/mycomponent.jsx'
81
+
82
+
83
+ export default function(req, res){
84
+ let counterRef = useRef(null)
85
+ let [count, setCount] = useState(0)
86
+
87
+ return <>
88
+ <h1>{count}</h1>
89
+ <button onClick={(event)=>{setCount(++count)}}>
90
+ </>
91
+ }
92
+
93
+
94
+
95
+ ```
96
+
97
+ # ServerSide Site Generation (SSG)
98
+
99
+ Vader compiles all code to a static index.html page so your visitors will never have to wait for the page to load, it then rehydrates the page reapplying functionality!
100
+
101
+ you can always opt out of ssg using:
102
+
103
+ ```js
104
+ export const $prerender = false;
105
+ ```
106
+ We can define some metadata to be used at compile
107
+
108
+ ```jsx
109
+ // src/layout.tsx
110
+ export function Layout({title, keywords, description, children}){
111
+ return (
112
+ <Html lang="en-us">
113
+ <Head>
114
+ <title>{title}</title>
115
+ <meta charset="utf-8" />
116
+ <meta name="description" content={description} />
117
+ <meta name="robots" content="index, follow" />
118
+ <meta name="author" content="Malik Whitten" />
119
+ <meta name="keywords" content={keywords} />
120
+ <meta name="url" content="https://malikwhitten.com" />
121
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
122
+ <link rel="icon" href={logo} />
123
+ <script src="/src/theme.js" eager> </script>
124
+ <link rel="stylesheet" href="/public/css/styles.css" />
125
+ </Head>
126
+
127
+ {children}
128
+ </Html>
129
+ )
130
+ }
131
+
132
+ // pages/index.jsx
133
+
134
+ //$= is a ternary operator used for spread like nesting
135
+
136
+ export default function (req, res){
137
+ return (
138
+ <Layout {...{title:'home', description:'home page', keywords:'vader.js', logo:''}}>
139
+ <h1> Hello World</h1>
140
+ </Layout>
141
+ )
142
+ }
143
+
144
+ ```
145
+ Vader will take the metadata and place it inside of the compiled html file.
146
+
147
+ ### Styling
148
+
149
+ Vaderjs has two types of in javascript styling - css modules and inline jsx styling
150
+ ```jsx
151
+
152
+ // inline
153
+ <button style={{color:'red'}}>Button</button>
154
+
155
+ // css module
156
+
157
+ //public/app.module.css
158
+ `
159
+ .container{
160
+ color:red;
161
+ font-size:20px
162
+ }
163
+ `
164
+
165
+ // import file
166
+ import style from 'public/app.module.css' // this gets replaced with the compiled css output
167
+
168
+ <button style={{...style.container}}>Button </button>
169
+
170
+ ```
171
+ ### State Management
172
+ Vaderjs uses partial hydration & full reflection
173
+
174
+ You can pass a reference to the dom target like an id for the element u want to change - or you can just swap the value and the entire component will rerender
175
+
176
+ ```jsx
177
+ import {Component, useState, useRef. Mounted} = from 'vaderjs/client'
178
+
179
+ export default class MyApp extends Component{
180
+ contructor(){
181
+ super()
182
+ this.key = 'static key for state changes'
183
+ }
184
+
185
+ render(){
186
+ let [count, setCount] = useState(0)
187
+ let ref = useRef('')
188
+
189
+ Mounted(()=>{
190
+ console.log(ref.current) // p tag
191
+ }, this)
192
+ return <>
193
+ <p ref={ref}>Count is {count}</p>
194
+ {/**
195
+ pass anything used from the toplevel render to the lowerlevel function params to be able to invoke!
196
+ **/}
197
+ <button onclick={()=>{
198
+ setCount(++count)
199
+ }}>Increment</button>
200
+ </>
201
+
202
+ }
203
+ }
204
+ ```
205
+
206
+
207
+ ### Function Binding
208
+
209
+ Vaderjs allows you to bind functions directly to html elements just like react
210
+ there are two ways - top level invokes like below
211
+
212
+ ```javascript
213
+ // vader uses params[0] as the event target object and other parameters resolve after
214
+
215
+ function click(event, otherparams){
216
+ console.log(event.target, otherparams)
217
+ }
218
+
219
+ const hello = function(event, otherparams){
220
+
221
+ }
222
+
223
+ return <>
224
+ <button onclick={()=>click()}>Click Me</button>
225
+ </>
226
+ ```
227
+
228
+ Low level invokes are considered top level and can access - any value above the scope !!
229
+
230
+ ```jsx
231
+ let car = {
232
+ model: 'tesla',
233
+ price: 'toomiuch'
234
+ }
235
+ return <>
236
+ <button onclick={(event)=>{
237
+ console.log(car.model)
238
+ }}>Log</button>
239
+ ```
240
+
241
+
242
+
243
+
244
+
245
+
246
+ ## License
247
+
248
+ VaderJS is released under the MIT License. See the [LICENSE](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) file for details.
249
+
250
+ ## Join the Community
251
+
252
+ Connect with the VaderJS community on [GitHub](https://github.com/Postr-Inc/Vader.js). Contribute, share feedback, and improve VaderJS for SPA development.
253
+
@@ -0,0 +1,202 @@
1
+ import http from "http";
2
+ import fs from "fs";
3
+ import dotenv from "dotenv";
4
+ dotenv.config();
5
+ import puppeteer from "puppeteer";
6
+ import { WebSocketServer } from "ws";
7
+ const wss = new WebSocketServer({ port: 3436 });
8
+ globalThis.wss = wss;
9
+ process.cwd = () => {
10
+ return process.env.PWD;
11
+ }
12
+ globalThis.routeDocuments = {};
13
+ function httpServer(){
14
+ let server = http.createServer((req, res) => {
15
+ if (!req.url.includes(".")) {
16
+ let folder = req.url.split("?")[1].split("=")[1];
17
+
18
+ let content = globalThis.routeDocuments[folder]
19
+ globalThis.wss.clients.forEach((client) => {
20
+ client.send(JSON.stringify({ type: "server", content }));
21
+ });
22
+
23
+
24
+ res.writeHead(200, { "Content-Type": "text/html" });
25
+
26
+ res.end(content);
27
+ } else {
28
+ const filePath = process.cwd() + "/dist/" + req.url;
29
+
30
+ fs.readFile(filePath, (err, data) => {
31
+ if (err) {
32
+ res.writeHead(404, {
33
+ "Content-Type": filePath.includes("js")
34
+ ? "text/javascript"
35
+ : "text/html",
36
+ });
37
+ res.end("File not found");
38
+ } else {
39
+ res.writeHead(200, {
40
+ "Content-Type": filePath.includes("js")
41
+ ? "text/javascript"
42
+ : "text/html",
43
+ });
44
+ res.end(data);
45
+ }
46
+ });
47
+ }
48
+ });
49
+
50
+ globalThis.server = server;
51
+ server.listen(8700, async () => {
52
+
53
+
54
+ });
55
+ }
56
+ httpServer()
57
+ if(!globalThis.browser){
58
+ const browser = await puppeteer.launch({
59
+ headless: "new",
60
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
61
+ executablePath: process.platform === "win32" ? process.env.CHROME_PATH : '/usr/bin/chromium-browser',
62
+ });
63
+ globalThis.browser = browser;
64
+ }
65
+ wss.on("connection", async function connection(ws) {
66
+ ws.send(JSON.stringify({ type: "connected" }));
67
+
68
+ ws.on("message", async function incoming(message) {
69
+
70
+ let data = JSON.parse(message.toString());
71
+ if (data.type === "generate") { ;
72
+ globalThis.wss.clients.forEach((client) => {
73
+ client.send(JSON.stringify({ message: "Generating" }));
74
+ });
75
+ let PWD = data.PWD;
76
+ process.cwd = () => {
77
+ return PWD;
78
+ };
79
+ let params = JSON.parse(data.params);
80
+ let output = data.output;
81
+ let file = data.file;
82
+
83
+ let folder = data.folder;
84
+ const page = await browser.newPage();
85
+ let baseFolder = folder
86
+ .split("/")
87
+ .filter((f) => f !== "pages")
88
+ .join("/");
89
+ baseFolder = baseFolder.replace("//", "/");
90
+ globalThis.routeDocuments[folder] = `<!DOCTYPE html>
91
+
92
+ <html lang="en">
93
+ <head>
94
+ <meta charset="UTF-8">
95
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
96
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
97
+ <title>Document</title>
98
+ <script id="server">
99
+ window.$SERVER = true
100
+ </script>
101
+ </head>
102
+ <body>
103
+ <div id="app"></div>
104
+ <script type="module" id="router" >
105
+ window.files = window.files || []
106
+ import Router from '/router.js'
107
+ import c from '${file}'
108
+ const rt = new Router
109
+ let module = await import('${file}')
110
+ if(Object.keys(module).includes('$prerender') && !module.$prerender){
111
+ document.head.setAttribute('prerender', 'false')
112
+ }
113
+ rt.get($SERVER ? '/' : '${baseFolder}', c)
114
+ window.files.push('${file}')
115
+
116
+ ${
117
+ Array.isArray(params)
118
+ ? params
119
+ .map((param) => {
120
+ if (!param.jsFile) return "";
121
+ let ranName = Math.random()
122
+ .toString(36)
123
+ .substring(7)
124
+ .replace(".", "");
125
+ let pd = Object.keys(param.paramData)[0];
126
+ let baseFolder = folder
127
+ .split("/")
128
+ .filter((f) => f !== "pages")
129
+ .join("/");
130
+
131
+ return `
132
+ import c${ranName} from '${param.jsFile}'
133
+ rt.get('${baseFolder}/:${pd}', c${ranName})
134
+ window.files.push('${param.jsFile}')
135
+ `;
136
+ })
137
+ .join("")
138
+ : ""
139
+ }
140
+ window.rt = rt
141
+ rt.listen()
142
+ </script>
143
+ </body>
144
+ </html>
145
+
146
+ `;
147
+
148
+ server.on("error", (err) => {
149
+ globalThis.wss.clients.forEach((client) => {
150
+ client.send(JSON.stringify({ type: "error", error: err }));
151
+ });
152
+ });
153
+
154
+ page.on("error", (err) => {
155
+ globalThis.wss.clients.forEach((client) => {
156
+ client.send(JSON.stringify({ type: "error", error: err }));
157
+ });
158
+ });
159
+ page.on("pageerror", (err) => {
160
+ globalThis.wss.clients.forEach((client) => {
161
+ client.send(JSON.stringify({ type: "error", error: err }));
162
+ });
163
+ });
164
+ await page.goto(`http://localhost:8700/?folder=${folder}`, {
165
+ waitUntil: "networkidle2",
166
+ });
167
+ await page.evaluate(() => {
168
+ let server = document.getElementById("server");
169
+ server.innerHTML = "window.$SERVER = false";
170
+ let shouldPrerender = document.head.getAttribute("prerender");
171
+ if (shouldPrerender === "false") {
172
+ document.querySelector("#app").innerHTML = "";
173
+ }
174
+ });
175
+ let html = await page.content();
176
+ if (!fs.existsSync("./dist")) {
177
+ fs.mkdirSync("./dist");
178
+ }
179
+ if (!fs.existsSync("./dist/pages")) {
180
+ fs.mkdirSync("./dist/pages");
181
+ }
182
+
183
+ if (!fs.existsSync(folder)) {
184
+ fs.mkdirSync(folder);
185
+ }
186
+ globalThis.wss.clients.forEach((client) => {
187
+ client.send(JSON.stringify({ type: "done", file }));
188
+ });
189
+ fs.writeFileSync(output, html);
190
+ page.close();
191
+
192
+
193
+ }else if(data.type === 'done'){
194
+
195
+ globalThis.browser.close()
196
+ globalThis.server.close()
197
+
198
+ }
199
+ });
200
+ });
201
+
202
+