lightweight-router 1.0.4 → 1.0.6
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 +36 -31
- package/dist/router.min.js +1 -1
- package/package.json +1 -1
- package/router.ultramin.js +1 -1
- package/src/router.js +15 -7
package/README.md
CHANGED
|
@@ -34,6 +34,10 @@ Example:
|
|
|
34
34
|
```javascript
|
|
35
35
|
import { startRouter } from "lightweight-router";
|
|
36
36
|
|
|
37
|
+
startRouter()
|
|
38
|
+
|
|
39
|
+
//or with your callback
|
|
40
|
+
|
|
37
41
|
startRouter({
|
|
38
42
|
onRouteChange: currentRoute => {
|
|
39
43
|
console.log("Route changed:", currentRoute);
|
|
@@ -55,7 +59,7 @@ You can also directly import the minified version of the router in your HTML fil
|
|
|
55
59
|
</head>
|
|
56
60
|
<body>
|
|
57
61
|
<!-- Your website content -->
|
|
58
|
-
<script src="path/to/
|
|
62
|
+
<script src="path/to/router.ultramin.js"></script>
|
|
59
63
|
</body>
|
|
60
64
|
</html>
|
|
61
65
|
```
|
|
@@ -88,9 +92,39 @@ Your website content
|
|
|
88
92
|
</script>
|
|
89
93
|
```
|
|
90
94
|
|
|
95
|
+
## Prefetching
|
|
96
|
+
|
|
97
|
+
By default, links are prefetched when they get in the user's screen using an `IntersectionObserver`. This ensures that the content is loaded in the background before the user clicks on the link, providing a smoother navigation experience.
|
|
98
|
+
This behaviour is automatically disabled if the user has data saving preferences.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
If you have too many links at once or too many requests, you can add the `prefetch="onHover"` attribute to your links or some of them (usually links to huge pages that are not often visited):
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<a href="/archive" prefetch="onHover">Archive</a>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
P.S. you can easily test in your website by pasting the ultra minified version into the console.
|
|
108
|
+
The minified version was created with uglify-js, clean.css and then ultra minified with https://packjs.com
|
|
109
|
+
The size of the gzipped version was calculated with: https://dafrok.github.io/gzip-size-online/
|
|
110
|
+
It's worth to note that nonetheless Terser give better results than uglify-js. The final uglify version packed by packjs.com was even smaller.
|
|
111
|
+
|
|
112
|
+
## Browser Support
|
|
113
|
+
|
|
114
|
+
The router supports all modern browsers. Required features:
|
|
115
|
+
|
|
116
|
+
- IntersectionObserver
|
|
117
|
+
- Fetch API
|
|
118
|
+
- History API
|
|
119
|
+
|
|
120
|
+
For older browsers, consider using the following polyfills:
|
|
121
|
+
|
|
122
|
+
- intersection-observer
|
|
123
|
+
- whatwg-fetch
|
|
124
|
+
|
|
91
125
|
## Server Configuration
|
|
92
126
|
|
|
93
|
-
Configuring your server to return only the route content can make the router much more efficient. Instead of returning the entire page, the server
|
|
127
|
+
Configuring your server to return only the route content can make the router much more efficient. Instead of returning the entire page, the server could return only the content for the requested route when it detects a request with the message "onlyRoute".
|
|
94
128
|
|
|
95
129
|
```javascript
|
|
96
130
|
await fetch(url, { method: "POST", body: "onlyRoute" });
|
|
@@ -123,35 +157,6 @@ Right now errors are shown without styling as the content of the page.
|
|
|
123
157
|
|
|
124
158
|
Soon there will be a DenoJS library that will help you deal with all these routes stuff. It will also come with api routes functionality 🔥
|
|
125
159
|
|
|
126
|
-
## Prefetching
|
|
127
|
-
|
|
128
|
-
By default, links are prefetched when they get in the user's screen using an `IntersectionObserver`. This ensures that the content is loaded in the background before the user clicks on the link, providing a smoother navigation experience.
|
|
129
|
-
|
|
130
|
-
If you have too many links at once or too many requests, you can add the `prefetch="onHover"` attribute to your links or some of them (usually links to huge pages that are not often visited):
|
|
131
|
-
|
|
132
|
-
```html
|
|
133
|
-
<a href="/archive" prefetch="onHover">Archive</a>
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
P.S. you can easily test in your website by pasting this minified version into the console.
|
|
137
|
-
|
|
138
|
-
The minified version was created with uglify-js, clean.css and then minified again with https://packjs.com
|
|
139
|
-
The size of the gzipped version was calculated with: https://dafrok.github.io/gzip-size-online/
|
|
140
|
-
It's worth to note that nonethewise Terser give better results than uglify-js. The final uglify version packed by packjs.com was even smaller.
|
|
141
|
-
|
|
142
|
-
## Browser Support
|
|
143
|
-
|
|
144
|
-
The router supports all modern browsers. Required features:
|
|
145
|
-
|
|
146
|
-
- IntersectionObserver
|
|
147
|
-
- Fetch API
|
|
148
|
-
- History API
|
|
149
|
-
|
|
150
|
-
For older browsers, consider using the following polyfills:
|
|
151
|
-
|
|
152
|
-
- intersection-observer
|
|
153
|
-
- whatwg-fetch
|
|
154
|
-
|
|
155
160
|
## Performance Tips
|
|
156
161
|
|
|
157
162
|
- Use `content-visibility: auto` on route elements to improve rendering performance
|
package/dist/router.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{let c={},n=async()=>{var e=document.querySelector("router"),t=globalThis.location.pathname;let o=e.querySelector(`route[path="${t}"]`),n=(o||((o=document.createElement("route")).setAttribute("path",globalThis.location.pathname),e.appendChild(o)),document.body.classList.add("loading"),c[globalThis.location.href]);n||(n=await d(globalThis.location.href),c[globalThis.location.href]=n);var r,a=(new DOMParser).parseFromString(n,"text/html"),i=a.querySelector("title"),i=(i&&(document.title=i.textContent),o.innerHTML=a.body.innerHTML,Array.from(o.querySelectorAll("script")));for(r of i){var l=document.createElement("script");r.src?l.src=r.src:l.textContent=r.textContent,r.parentNode.replaceChild(l,r)}e.querySelectorAll("route").forEach(e=>e.style.display="none"),o.style.display="contents",document.body.classList.remove("loading"),window.scrollTo(0,0),s&&s(t)},r=async e=>{c[e.href]||(c[e.href]=await d(e.href))},a=(e,t)=>{e.forEach(e=>{e.isIntersecting&&(e=e.target,c[e.href]||(r(e),t.unobserve(e)))})},i=e=>{var t=e.target.closest("A");t&&t.href&&l(t.href)&&t.origin===location.origin&&(e.preventDefault(),globalThis.history.pushState(null,null,t.href),globalThis.dispatchEvent(new Event("popstate")))};function l(e){if(e&&!e.startsWith("#")&&!e.startsWith("javascript:")){if(e.startsWith("/"))return 1;try{var t=new URL(e,window.location.origin),o=new URL(window.location.href);return o.hostname.replace(/^www\./,"")===t.hostname.replace(/^www\./,"")?o.pathname!==t.pathname||!t.hash:void 0}catch{}}}let s,d=async e=>{e=await t(e);return e.ok?e.text():"Couldn't fetch the route - HTTP error! status: "+e.status},t=async e=>{if(!h){var t=await fetch(e,{method:"POST",body:"onlyRoute"});if(t.ok)return t}return fetch(e)},h=!1,e=(e={})=>{var t,e=e.onRouteChange,e=(e&&(e=e,s=e),document.createElement("style")),e=(e.textContent="
|
|
1
|
+
(()=>{let c={},n=async()=>{var e=document.querySelector("router"),t=globalThis.location.pathname;let o=e.querySelector(`route[path="${t}"]`),n=(o||((o=document.createElement("route")).setAttribute("path",globalThis.location.pathname),e.appendChild(o)),document.body.classList.add("loading"),c[globalThis.location.href]);n||(n=await d(globalThis.location.href),c[globalThis.location.href]=n);var r,a=(new DOMParser).parseFromString(n,"text/html"),i=a.querySelector("title"),i=(i&&(document.title=i.textContent),o.innerHTML=a.body.innerHTML,Array.from(o.querySelectorAll("script")));for(r of i){var l=document.createElement("script");r.src?l.src=r.src:l.textContent=r.textContent,r.parentNode.replaceChild(l,r)}e.querySelectorAll("route").forEach(e=>e.style.display="none"),o.style.display="contents",document.body.classList.remove("loading"),window.scrollTo(0,0),s&&s(t)},r=async e=>{c[e.href]||(c[e.href]=await d(e.href))},a=(e,t)=>{e.forEach(e=>{e.isIntersecting&&(e=e.target,c[e.href]||(r(e),t.unobserve(e)))})},i=e=>{var t=e.target.closest("A");t&&t.href&&l(t.href)&&t.origin===location.origin&&(e.preventDefault(),globalThis.history.pushState(null,null,t.href),globalThis.dispatchEvent(new Event("popstate")))};function l(e){if(e&&!e.startsWith("#")&&!e.startsWith("javascript:")){if(e.startsWith("/"))return 1;try{var t=new URL(e,window.location.origin),o=new URL(window.location.href);return o.hostname.replace(/^www\./,"")===t.hostname.replace(/^www\./,"")?o.pathname!==t.pathname||!t.hash:void 0}catch{}}}let s,d=async e=>{e=await t(e);return e.ok?e.text():"Couldn't fetch the route - HTTP error! status: "+e.status},t=async e=>{if(!h){var t=await fetch(e,{method:"POST",body:"onlyRoute"});if(t.ok)return t}return fetch(e)},h=!1,e=(e={})=>{var t,e=e.onRouteChange,e=(e&&(e=e,s=e),document.createElement("style")),e=(e.textContent=".loading{animation:pulse 1s infinite alternate}@keyframes pulse{from{opacity:.6}to{opacity:.1}}route{content-visibility:auto}",document.head.appendChild(e),document.querySelector("router")),o=globalThis.location.pathname,o=(e||(e=document.createElement("router"),(t=document.createElement("route")).setAttribute("path",o),t.innerHTML=document.body.innerHTML,e.appendChild(t),document.body.innerHTML="",document.body.appendChild(e),h=!0),globalThis.addEventListener("popstate",n),document.addEventListener("click",i),document.body.addEventListener("mouseover",e=>{"A"===e.target.tagName&&"onHover"===e.target.getAttribute("prefetch")&&(async e=>{e=e.target;!c[e.href]&&l(e.href)&&await r(e)})(e)}),new IntersectionObserver(a,{root:null,threshold:.5}));(t=>{let o=navigator.connection&&navigator.connection.saveData;document.querySelectorAll("a").forEach(e=>{"onHover"===e.getAttribute("prefetch")||o||l(e.href)||t.observe(e)})})(o)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>e()):e()})();
|
package/package.json
CHANGED
package/router.ultramin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
s;
|
|
1
|
+
$="(£ìc={},n=async£ìܵ¨¢t=êð;¦úè(`ä[pÓh=${t}]`÷n=(oÊ((o´êð÷ú½(o)÷Æç.addöÛ³¼nÊ(n=×d(êó³=n¼Ür,a=(ÍDOMParsõ).parseF°mString(n,ýxt/html¢i=a.èötàle¢i=(iÞ(¾tàlµi.Ý÷¥î=a.¬.î,Array.f°m(¥¹Éé)¼for(r of i){Ül=ßÉé;r«?l«=r«:l.Ý=r.Ý,r.paùïNodÐChild(l,rØú¹äé.fÔ=>ú²nëeé÷¥²c¡sÑÆç.ùmo·öÛ¢Ïsc°llTo(0,0÷sÞs(tØ,r=âËÊ(Ë=×dªØ,a=ô,t)ìúfÔìúisIÀngÞôí,ËÊ(rô÷Õun®))±Ø,i=eìÜtí.closeçöAé;tÞÕóÞl(Õó)ÞÕÈÒ=lüÈÞ(úpù·ïDefault(ºhiçory.pushStaý(¸¸ÕóºdispÓchE·ï(ÍE·ïö¯é)Ø;functië lô){ifô©#é©javaÉ:é){ Öhö/é)á1;try{Üt=ÍURLô,ÏlüÈ÷¦ÍURL(Ïlüó¼á¥¤Ò=Õ¤?¥ð!ÒÕðÊ!Õhash:void 0}cÓch{}}}s,d=âµ×tô¼áúok?úýxt£:Couldn't Ì the ä - HTTP õ°r! çÓus: +úçÓus},t=â !h){Üt=×Ìô,{mÚhod:POSTѬ:ëlyRouý}¼ Õok)át}áÌôØ,h=!1,µô={})ìÜt,µúëRouýChange,µôÞô=e,s=e÷ßçyleé÷µ(úÝ=¬.Û{animÓië:¶ 1s infiniý alýrnaý}@keyframes ¶{f°m§8}to§3}}Ѿhead.½ô÷¨é÷¦êð,¦ôÊô=ßär¢(t´o÷Õçylúc¡Visibilày=autoÑÕî=òî,ú½(t÷òî=Ñò½ô÷h=!0ºÙ¯Ñn÷¾ÙclickÑi÷òÙmouseovõÑôìAÒí.tagNameÞ»í.¿Þ(âeí;!ËÞlªÞ×rô±ô±÷ÍIÀëObsõvõ(a,{°ot:¸thùshold:.5})¼(tì¦naÁÞnaÁ.sa·DÓa;¾¹aé.fÔì»=ú¿ÊoÊlªÊÕ®±±(oØ;ÛÒ=¾ùadyStaý?¾ÙDOMC¡LoadedÑ(£=>e£)):e(±(¼";l="if(ëýï÷()hoÂéo.o={oÎ:.¾èöärÞ!Öhö(úó).srcbodylÚ obsõ·ôpopçaýroØ)çylÇ=÷c[êó]=ßäÅÓhÑe=pulseOÎvenull,èAllö÷glû.ëHovõÒ);aãlddþgÚAåpùÌénýrsectivigÃctiëÄwww./,Óor.cëneçnamÐ(/^é).sÚAåpòclassLiúdisplayoriginscript||c[úó]fÚchnew pacàywindow.úùplace,==atorEach(ôt.úçartsWàawaà )}addEveæetloadingvar ýxtCëýï&&dñmeïöitùturn async eìppendChirouýttribuýöïLisýnõöstquõør)glû.lüon=>{=útargetinnõHTMLntpathnameþcùaýEledþbody.hùf(eer(),ySelectoree.obalThisocation.teocument.".split('');_=" ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ";for(i=0;i<95;i++){$=$.split(_[i]).join(l[i])};eval($.replace(//g,'"').replace(//g,'\\').replace(//g,String.fromCharCode(10)));
|
package/src/router.js
CHANGED
|
@@ -148,13 +148,15 @@ const startRouter = (options = {}) => {
|
|
|
148
148
|
if (onRouteChange) setRouteChangeHandler(onRouteChange);
|
|
149
149
|
const style = document.createElement("style");
|
|
150
150
|
style.textContent = `
|
|
151
|
-
|
|
152
|
-
animation:
|
|
151
|
+
.loading {
|
|
152
|
+
animation: pulse 1s infinite alternate;
|
|
153
153
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
@keyframes pulse {
|
|
155
|
+
from { opacity: 0.6; }
|
|
156
|
+
to { opacity: 0.1; }
|
|
157
|
+
}
|
|
158
|
+
route {
|
|
159
|
+
content-visibility: auto;
|
|
158
160
|
}
|
|
159
161
|
`;
|
|
160
162
|
document.head.appendChild(style);
|
|
@@ -166,7 +168,6 @@ const startRouter = (options = {}) => {
|
|
|
166
168
|
router = document.createElement("router");
|
|
167
169
|
const route = document.createElement("route");
|
|
168
170
|
route.setAttribute("path", currentPath);
|
|
169
|
-
route.style.contentVisibility = "auto";
|
|
170
171
|
route.innerHTML = document.body.innerHTML;
|
|
171
172
|
router.appendChild(route);
|
|
172
173
|
document.body.innerHTML = "";
|
|
@@ -188,3 +189,10 @@ const startRouter = (options = {}) => {
|
|
|
188
189
|
};
|
|
189
190
|
|
|
190
191
|
export { startRouter };
|
|
192
|
+
|
|
193
|
+
// TODO: create ultra minified version or deploy
|
|
194
|
+
// - add support for prefetching on hover
|
|
195
|
+
// - add support for prefetching on click
|
|
196
|
+
// - add support for prefetching on scroll
|
|
197
|
+
// - add support for prefetching on focus
|
|
198
|
+
// - add support for prefetching on touch
|