@aref-shojaei/router 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +332 -205
- package/example/assets/css/styles.css +45 -45
- package/example/assets/js/app.js +7 -7
- package/example/assets/js/router.min.js +1 -1
- package/example/index.html +26 -26
- package/example/package.json +18 -18
- package/example/server.js +17 -17
- package/index.js +6 -4
- package/package.json +48 -42
- package/src/dto/route.js +13 -13
- package/src/exception.js +5 -5
- package/src/page.js +91 -91
- package/src/route.js +103 -103
- package/src/router.js +207 -207
- package/src/utils/element.js +23 -23
- package/src/utils/selector.js +59 -59
- package/src/view.js +24 -24
- package/tests/unit/element.test.js +32 -32
- package/tests/unit/page.test.js +48 -48
- package/tests/unit/route.test.js +82 -82
- package/tests/unit/router.test.js +55 -55
- package/tests/unit/selector.test.js +42 -42
- package/tests/unit/view.test.js +46 -46
- package/webpack.config.js +23 -0
- package/.babelrc +0 -3
package/README.md
CHANGED
|
@@ -1,205 +1,332 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
Route.add("/", () => "
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
```
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🚀 Router - Lightweight JavaScript SPA Router
|
|
4
|
+
|
|
5
|
+
A lightweight and powerful client-side routing library for building Single Page Applications (SPA) with pure JavaScript.
|
|
6
|
+
|
|
7
|
+
Define routes, manage navigation, handle dynamic parameters, apply middleware, and create seamless page transitions without refreshing the browser.
|
|
8
|
+
|
|
9
|
+
<img src="https://github.com/user-attachments/assets/f1831dc5-f72e-4d7a-806d-b9c01b4be29a" alt="Router SPA Banner" />
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✨ Features
|
|
16
|
+
|
|
17
|
+
* 🚀 Client-side SPA routing
|
|
18
|
+
* 🔗 Browser History API support
|
|
19
|
+
* 📄 Single and grouped routes
|
|
20
|
+
* 🔥 Dynamic route parameters
|
|
21
|
+
* 🛡 Route middleware system
|
|
22
|
+
* 🔀 Route redirection
|
|
23
|
+
* 🏷 Dynamic page titles
|
|
24
|
+
* ⚡ No page refresh navigation
|
|
25
|
+
* 🪶 Lightweight and dependency-free
|
|
26
|
+
* 🧩 Simple and expressive API
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
# 📦 Installation
|
|
31
|
+
|
|
32
|
+
## Using NPM
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @aref-shojaei/router
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Using Yarn
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
yarn add @aref-shojaei/router
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# 🚀 Quick Start
|
|
47
|
+
|
|
48
|
+
Create your `app.js` file:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import { Router, Route } from "@aref-shojaei/router";
|
|
52
|
+
|
|
53
|
+
// Configure browser environment
|
|
54
|
+
Router.configure({
|
|
55
|
+
window,
|
|
56
|
+
document
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Create routes
|
|
60
|
+
Route.add("/", () => "Home Page");
|
|
61
|
+
|
|
62
|
+
Route.group("/auth", () => {
|
|
63
|
+
Route.add("/login", () => "Login Page");
|
|
64
|
+
Route.add("/register", () => "Register Page");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Dynamic routes
|
|
68
|
+
Route.add("/users/{id}", ({ params: { id } }) => {
|
|
69
|
+
return `User #${id}`;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Start the router
|
|
73
|
+
Router.run();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
# 🌐 HTML Integration
|
|
79
|
+
|
|
80
|
+
The router automatically intercepts internal links and updates the page without refreshing the browser.
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<body>
|
|
84
|
+
<nav>
|
|
85
|
+
<a href="/">Home</a>
|
|
86
|
+
<a href="/auth/login">Login</a>
|
|
87
|
+
<a href="/auth/register">Register</a>
|
|
88
|
+
<a href="/users/10">User Profile</a>
|
|
89
|
+
</nav>
|
|
90
|
+
|
|
91
|
+
<div id="root"></div>
|
|
92
|
+
|
|
93
|
+
<script src="app.js"></script>
|
|
94
|
+
</body>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
# 🏗 Router Workflow
|
|
100
|
+
|
|
101
|
+
```txt
|
|
102
|
+
User Click
|
|
103
|
+
|
|
|
104
|
+
|
|
|
105
|
+
Browser Event
|
|
106
|
+
|
|
|
107
|
+
|
|
|
108
|
+
Router Engine
|
|
109
|
+
|
|
|
110
|
+
|
|
|
111
|
+
Route Matching
|
|
112
|
+
|
|
|
113
|
+
|
|
|
114
|
+
Middleware
|
|
115
|
+
|
|
|
116
|
+
|
|
|
117
|
+
Component Rendering
|
|
118
|
+
|
|
|
119
|
+
|
|
|
120
|
+
DOM Update
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
# 📚 Routing Guide
|
|
126
|
+
|
|
127
|
+
## Basic Routes
|
|
128
|
+
|
|
129
|
+
Create simple routes:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
Route.add("/", () => "Welcome Page");
|
|
133
|
+
|
|
134
|
+
Route.add("/about", () => "About Page");
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Route Groups
|
|
140
|
+
|
|
141
|
+
Organize related routes together.
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
Route.group("/auth", () => {
|
|
145
|
+
Route.add("/login", () => "Login Page");
|
|
146
|
+
Route.add("/register", () => "Register Page");
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Generated routes:
|
|
151
|
+
|
|
152
|
+
```txt
|
|
153
|
+
/auth/login
|
|
154
|
+
/auth/register
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Dynamic Routes
|
|
160
|
+
|
|
161
|
+
Capture values directly from the URL.
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
Route.add("/users/{id}", ({ params: { id } }) => {
|
|
165
|
+
return `User ID: ${id}`;
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Multiple parameters:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
Route.add(
|
|
173
|
+
"/courses/{category}/{name}",
|
|
174
|
+
({ params: { category, name } }) => {
|
|
175
|
+
return `${category} / ${name}`;
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
# 🛡 Middleware
|
|
183
|
+
|
|
184
|
+
Middleware allows you to execute custom logic before rendering a route.
|
|
185
|
+
|
|
186
|
+
Common use cases:
|
|
187
|
+
|
|
188
|
+
* Authentication checks
|
|
189
|
+
* Logging
|
|
190
|
+
* Analytics
|
|
191
|
+
* Permissions
|
|
192
|
+
* Data preparation
|
|
193
|
+
|
|
194
|
+
Example:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
const logger = () => {
|
|
198
|
+
console.log("[LOG] Route visited");
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
Route.add(
|
|
202
|
+
"/dashboard",
|
|
203
|
+
() => "Dashboard"
|
|
204
|
+
).middleware([logger]);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Group middleware:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
Route.group("/admin", () => {
|
|
211
|
+
Route.add("/users", () => "Users");
|
|
212
|
+
Route.add("/settings", () => "Settings");
|
|
213
|
+
}).middleware([logger]);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
# 🔀 Route Redirection
|
|
219
|
+
|
|
220
|
+
Redirect users to another route.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
Route.add("/login", () => "Login Page");
|
|
224
|
+
|
|
225
|
+
Route.add("/dashboard", () => {
|
|
226
|
+
return Route.redirect("/login");
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
# 🏷 Page Titles
|
|
233
|
+
|
|
234
|
+
Change the browser tab title dynamically.
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
Route.add("/", () => "Home")
|
|
238
|
+
.title("My Awesome SPA");
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
If no title is specified, the router uses the default `document.title`.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
# 📂 Example Project Structure
|
|
246
|
+
|
|
247
|
+
```txt
|
|
248
|
+
my-spa/
|
|
249
|
+
|
|
|
250
|
+
├── index.html
|
|
251
|
+
|
|
|
252
|
+
├── app.js
|
|
253
|
+
|
|
|
254
|
+
└── node_modules/
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
# 💡 Use Cases
|
|
260
|
+
|
|
261
|
+
Router can be used for:
|
|
262
|
+
|
|
263
|
+
* Single Page Applications (SPA)
|
|
264
|
+
* Dashboard interfaces
|
|
265
|
+
* Admin panels
|
|
266
|
+
* Personal websites
|
|
267
|
+
* Progressive Web Applications
|
|
268
|
+
* Educational projects to learn routing concepts
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
# 🔥 Why Router?
|
|
273
|
+
|
|
274
|
+
Traditional websites require a full page reload for every navigation.
|
|
275
|
+
|
|
276
|
+
With Router:
|
|
277
|
+
|
|
278
|
+
```txt
|
|
279
|
+
Traditional Website
|
|
280
|
+
|
|
281
|
+
Click Link
|
|
282
|
+
|
|
|
283
|
+
HTTP Request
|
|
284
|
+
|
|
|
285
|
+
Server Response
|
|
286
|
+
|
|
|
287
|
+
Reload Entire Page
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
SPA Router
|
|
291
|
+
|
|
292
|
+
Click Link
|
|
293
|
+
|
|
|
294
|
+
JavaScript Router
|
|
295
|
+
|
|
|
296
|
+
Change Route
|
|
297
|
+
|
|
|
298
|
+
Update DOM
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
This results in a faster and smoother user experience.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
# 🧠 Concepts You Will Learn
|
|
306
|
+
|
|
307
|
+
By studying this project, you can understand:
|
|
308
|
+
|
|
309
|
+
* Browser History API
|
|
310
|
+
* URL parsing
|
|
311
|
+
* Route matching algorithms
|
|
312
|
+
* Dynamic parameters
|
|
313
|
+
* Middleware patterns
|
|
314
|
+
* Event handling
|
|
315
|
+
* Client-side rendering
|
|
316
|
+
* SPA architecture
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
# 👨💻 Author
|
|
321
|
+
|
|
322
|
+
**Aref Shojaei**
|
|
323
|
+
- 📧 Email: [arefshojaei82@gmail.com](mailto:arefshojaei82@gmail.com)
|
|
324
|
+
- 🐙 GitHub: [@ArefShojaei](https://github.com/ArefShojaei)
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
# ⭐ Show Your Support
|
|
329
|
+
|
|
330
|
+
If this project helps you understand SPA architecture and client-side routing, consider giving it a **Star ⭐ on GitHub**.
|
|
331
|
+
|
|
332
|
+
Your support helps the project grow.
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
* {
|
|
2
|
-
box-sizing: border-box;
|
|
3
|
-
padding: 0;
|
|
4
|
-
margin: 0;
|
|
5
|
-
font-family: sans-serif;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
body {
|
|
9
|
-
display: flex;
|
|
10
|
-
flex-direction: column;
|
|
11
|
-
align-items: center;
|
|
12
|
-
padding: 24px;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
ul {
|
|
16
|
-
display: flex;
|
|
17
|
-
align-items: center;
|
|
18
|
-
margin-top: 16px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
ul li {
|
|
22
|
-
margin: 0 24px;
|
|
23
|
-
list-style: none;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
ul li a {
|
|
27
|
-
padding: 4 8px;
|
|
28
|
-
color: #81a6f4;
|
|
29
|
-
text-decoration: none;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
ul li a:hover {
|
|
33
|
-
color: #2b2b2a;
|
|
34
|
-
transition: all .5s ease;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#root {
|
|
39
|
-
padding: 16px;
|
|
40
|
-
text-align: center;
|
|
41
|
-
margin-top: 40px;
|
|
42
|
-
background: #ded7d7;
|
|
43
|
-
width: 600px;
|
|
44
|
-
height: 250px;
|
|
45
|
-
border-radius: 16px;
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
padding: 0;
|
|
4
|
+
margin: 0;
|
|
5
|
+
font-family: sans-serif;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
align-items: center;
|
|
12
|
+
padding: 24px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ul {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
margin-top: 16px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
ul li {
|
|
22
|
+
margin: 0 24px;
|
|
23
|
+
list-style: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ul li a {
|
|
27
|
+
padding: 4 8px;
|
|
28
|
+
color: #81a6f4;
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ul li a:hover {
|
|
33
|
+
color: #2b2b2a;
|
|
34
|
+
transition: all .5s ease;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
#root {
|
|
39
|
+
padding: 16px;
|
|
40
|
+
text-align: center;
|
|
41
|
+
margin-top: 40px;
|
|
42
|
+
background: #ded7d7;
|
|
43
|
+
width: 600px;
|
|
44
|
+
height: 250px;
|
|
45
|
+
border-radius: 16px;
|
|
46
46
|
}
|
package/example/assets/js/app.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Router.configure({ window, document })
|
|
2
|
-
|
|
3
|
-
Route.add("/", () => "Welcome Page")
|
|
4
|
-
Route.add("/users", () => "Users Page")
|
|
5
|
-
Route.add("/users/{name}", ({ params : { name } }) => `User #${name} Page`)
|
|
6
|
-
Route.add("/redirection", () => Route.redirect("/"))
|
|
7
|
-
|
|
1
|
+
Router.configure({ window, document })
|
|
2
|
+
|
|
3
|
+
Route.add("/", () => "Welcome Page")
|
|
4
|
+
Route.add("/users", () => "Users Page")
|
|
5
|
+
Route.add("/users/{name}", ({ params : { name } }) => `User #${name} Page`)
|
|
6
|
+
Route.add("/redirection", () => Route.redirect("/"))
|
|
7
|
+
|
|
8
8
|
Router.run()
|