swtl

A Service Worker Templating Language (swtl) for component-like templating i...

README

swtl


Check out the swtl-starter app


A Service Worker Templating Language (swtl) for component-like templating in service workers. Streams templates to the browser as they're being parsed, and handles rendering iterables/Responses in templates by default.

  1. ```bash
  2. npm i swtl
  3. ```

Example


  1. ```js
  2. import { html, Router, CacheFirst } from 'swtl';
  3. import { BreadCrumbs } from './BreadCrumbs.js'

  4. function HtmlPage({children, title}) {
  5.   return html`<html><head><title>${title}</title>head><body>${children}</body>html>`;
  6. }

  7. function Footer() {
  8.   return html`<footer>Copyright</footer>`;
  9. }

  10. const router = new Router({
  11.   routes: [
  12.     {
  13.       path: '/',
  14.       render: ({url, params, query, request}) => html`
  15.         <${HtmlPage} title="Home">
  16.           <h1>Home</h1>
  17.           <nav>
  18.             <${BreadCrumbs} path=${request.url.pathname}/>
  19.           </nav>
  20.           ${fetch('./some-partial.html')}
  21.           ${caches.match('./another-partial.html')}
  22.           <ul>
  23.             ${['foo', 'bar', 'baz'].map(i => html`<li>${i}</li>`)}
  24.           </ul>
  25.           <${CacheFirst} file="./some-file.html"/>
  26.           <${Footer}/>
  27.         <//>
  28.       `
  29.     },
  30.   ]
  31. });

  32. self.addEventListener('fetch', (event) => {
  33.   if (event.request.mode === 'navigate') {
  34.     event.respondWith(router.handleRequest(event.request));
  35.   }
  36. });
  37. ```

Router


Uses URLPattern internally for matching thepaths. The render callback gets passed the native [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object, as well as any route params or query params.

  1. ```js
  2. import { html, Router } from 'swtl';

  3. const router = new Router({
  4.   routes: [
  5.     {
  6.       path: '/',
  7.       render: () => html`<h1>Home</h1>`
  8.     },
  9.     {
  10.       path: '/:foo',
  11.       render: ({params}) => html`<h1>${params.foo}</h1>`
  12.     },
  13.     {
  14.       path: '/:foo/:bar',
  15.       render: ({params}) => html`<h1>${params.foo}/${params.bar}h1>`
  16.     },
  17.     {
  18.       path: '/:foo/:bar',
  19.       render: ({url, params, query, request}) => html`<h1>${params.foo}/${params.bar}h1>`
  20.     },
  21.   ]
  22. });

  23. self.addEventListener('fetch', (event) => {
  24.   if (event.request.mode === 'navigate') {
  25.     event.respondWith(router.handleRequest(event.request));
  26.   }
  27. });
  28. ```

baseHref


You can also specify a baseHref, for example if your app is served under a specific base route, like https://my-app.com/foo/bar/:

  1. ```js
  2. const router = new Router({
  3.   baseHref: '/foo/bar/',
  4.   routes: [
  5.     {
  6.       // The url will be: https://my-app.com/foo/bar/
  7.       path: '',
  8.       render: () => html`<${Home}/>`
  9.     },
  10.     {
  11.       // The url will be: https://my-app.com/foo/bar/users/1
  12.       path: 'users/:id',
  13.       render: ({params}) => html`<${User} id=${params.id}/>`
  14.     }
  15.   ]
  16. });
  17. ```

Note that you also have the set the base tag in your HTML:
  1. ```html
  2. <base href="/foo/bar/">
  3. ```

fallback


You can also provide a fallback in case no routes are matched. If you don't provide a fallback, the request will not be handled by the service worker, and go through to the network.

  1. ```js
  2. const router = new Router({
  3.   routes: [
  4.     {
  5.       path: '/',
  6.       render: () => html`<${Home}/>`
  7.     }
  8.   ],
  9.   fallback: ({query, request}) => html`<${NotFound}/>`
  10. });
  11. ```