├── .gitignore ├── example ├── assets │ └── icon.png ├── stores │ └── clicks.js ├── manifest.json ├── views │ ├── 404.js │ └── main.js ├── index.js ├── package.json ├── README.md └── sw.js ├── package.json ├── index.js ├── LICENSE └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | npm-debug.log* 4 | .nyc_output 5 | -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/service-worker-renderer/master/example/assets/icon.png -------------------------------------------------------------------------------- /example/stores/clicks.js: -------------------------------------------------------------------------------- 1 | module.exports = store 2 | 3 | function store (state, emitter) { 4 | state.totalClicks = 0 5 | 6 | emitter.on('DOMContentLoaded', function () { 7 | emitter.on('clicks:add', function (count) { 8 | state.totalClicks += count 9 | emitter.emit(state.events.RENDER) 10 | }) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /example/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "description": "A very cute app", 5 | "start_url": "/", 6 | "display": "standalone", 7 | "background_color": "#ffc0cb", 8 | "theme_color": "#ffc0cb", 9 | "icons": [{ 10 | "src": "/assets/icon.png", 11 | "type": "image/png", 12 | "sizes": "512x512" 13 | }] 14 | } -------------------------------------------------------------------------------- /example/views/404.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var TITLE = '🚂🚋🚋 - route not found' 4 | 5 | module.exports = view 6 | 7 | function view (state, emit) { 8 | if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE) 9 | return html` 10 | 11 |

12 | 404 - route not found 13 |

14 |
15 | 16 | Back to main 17 | 18 |
19 | 20 | ` 21 | } 22 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | var css = require('sheetify') 2 | var choo = require('choo') 3 | var store = require('./stores/clicks') 4 | 5 | css('tachyons') 6 | 7 | var app = choo() 8 | if (process.env.NODE_ENV !== 'production') { 9 | app.use(require('choo-devtools')()) 10 | } else { 11 | // Enable once you want service workers support. At the moment you'll 12 | // need to insert the file names yourself & bump the dep version by hand. 13 | // app.use(require('choo-service-worker')()) 14 | } 15 | 16 | app.use(store) 17 | 18 | app.route('/', require('./views/main')) 19 | app.route('/*', require('./views/404')) 20 | 21 | if (!module.parent) app.mount('body') 22 | else module.exports = app 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "service-worker-renderer", 3 | "description": "Service worker side renderer", 4 | "author": "YerkoPalma", 5 | "version": "0.1.0", 6 | "main": "index.js", 7 | "files": [ 8 | "index.js" 9 | ], 10 | "scripts": { 11 | "test": "standard --verbose | snazzy && tape test.js | tap-summary", 12 | "start": "node index.js" 13 | }, 14 | "repository": "YerkoPalma/service-worker-renderer", 15 | "license": "MIT", 16 | "keywords": [ 17 | "service-worker", 18 | "server", 19 | "render", 20 | "web" 21 | ], 22 | "devDependencies": { 23 | "snazzy": "^7.0.0", 24 | "standard": "^10.0.3", 25 | "tap-summary": "^4.0.0", 26 | "tape": "^4.8.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/views/main.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var TITLE = '🚂🚋🚋' 4 | 5 | module.exports = view 6 | 7 | function view (state, emit) { 8 | if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE) 9 | 10 | return html` 11 | 12 |

13 | Choo choo! 14 |

15 | 16 |
17 |

Current number of clicks: ${state.totalClicks}

18 | 19 | 20 |
21 | 22 | ` 23 | 24 | function handleClick () { 25 | emit('clicks:add', 1) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "bankai build index.js", 7 | "create": "choo-scaffold", 8 | "inspect": "bankai inspect index.js", 9 | "start": "bankai start index.js", 10 | "test": "standard && npm run test-deps", 11 | "test-deps": "dependency-check . && dependency-check . --extra --no-dev -i tachyons" 12 | }, 13 | "dependencies": { 14 | "choo": "^6.7.0", 15 | "choo-devtools": "^2.3.3", 16 | "choo-service-worker": "^2.3.1", 17 | "sheetify": "^7.0.0", 18 | "tachyons": "^4.9.1" 19 | }, 20 | "devDependencies": { 21 | "bankai": "^9.3.1", 22 | "choo-scaffold": "^1.1.2", 23 | "dependency-check": "^3.0.0", 24 | "standard": "^10.0.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | A very cute app 3 | 4 | ## Routes 5 | Route | File | Description | 6 | -------------------|--------------------|---------------------------------| 7 | `/` | `views/main.js` | The main view 8 | `/*` | `views/404.js` | Display unhandled routes 9 | 10 | ## Commands 11 | Command | Description | 12 | -----------------------|--------------------------------------------------| 13 | `$ npm start` | Start the development server 14 | `$ npm test` | Lint, validate deps & run tests 15 | `$ npm run build` | Compile all files into `dist/` 16 | `$ npm run create` | Generate a scaffold file 17 | `$ npm run inspect` | Inspect the bundle's dependencies -------------------------------------------------------------------------------- /example/sw.js: -------------------------------------------------------------------------------- 1 | /* global self */ 2 | 3 | var VERSION = require('./package.json').version 4 | var URLS = process.env.FILE_LIST 5 | 6 | // Respond with cached resources 7 | self.addEventListener('fetch', function (e) { 8 | e.respondWith(self.caches.match(e.request).then(function (request) { 9 | if (request) return request 10 | else return self.fetch(e.request) 11 | })) 12 | }) 13 | 14 | // Register worker 15 | self.addEventListener('install', function (e) { 16 | e.waitUntil(self.caches.open(VERSION).then(function (cache) { 17 | return cache.addAll(URLS) 18 | })) 19 | }) 20 | 21 | // Remove outdated resources 22 | self.addEventListener('activate', function (e) { 23 | e.waitUntil(self.caches.keys().then(function (keyList) { 24 | return Promise.all(keyList.map(function (key, i) { 25 | if (keyList[i] !== VERSION) return self.caches.delete(keyList[i]) 26 | })) 27 | })) 28 | }) 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env serviceworker */ 2 | (function () { 3 | self.getTemplate = function (templateUrl) { 4 | self.caches.match(templateUrl).then(function (response) { 5 | return response.text() 6 | }) 7 | } 8 | self.renderTemplate = function (template, state) { 9 | return '' 10 | } 11 | function Router () { 12 | this.routes = new Map() 13 | this.current = null 14 | } 15 | Router.prototype.route = function (route, template) { 16 | // route should be a regex 17 | if (typeof route === 'string') { 18 | this.router.set(new RegExp('^' + route.replace(/:.*\//g, '(.*)/') + '$'), template) 19 | } 20 | this.routes.set(route, template) 21 | } 22 | Router.prototype.match = function (url, state) { 23 | for (var regex in this.router.keys()) { 24 | if (regex.test(url)) { 25 | this.current = this.routes.get(regex) 26 | break 27 | } 28 | } 29 | if (state) { 30 | return self.renderTemplate(this.current, state) 31 | } 32 | return this.current 33 | } 34 | })() 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Yerko Palma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # service-worker-renderer 2 | [![Build Status](https://img.shields.io/travis/YerkoPalma/service-worker-renderer/master.svg?style=flat-square)](https://travis-ci.org/YerkoPalma/service-worker-renderer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) 3 | 4 | > Service worker side renderer 5 | 6 | ## Usage 7 | 8 | ```js 9 | // sw.js 10 | importScript('/.service-worker-renderer.js') 11 | 12 | self.addEventListener('fetch', async function (event) { 13 | event.respondWith( 14 | const template = await parseTemplate('/article-template.html') 15 | return new Response(renderTemplate(template, state), { 16 | headers: { 17 | 'Content-Type': 'text/html' 18 | } 19 | }) 20 | ) 21 | } 22 | ``` 23 | 24 | ```js 25 | // sw.js 26 | importScript('/.service-worker-renderer.js') 27 | 28 | // define router 29 | self.addEventListener('install', function (event) { 30 | // ... 31 | var router = new Router() 32 | router.route('/', '/main-template.html') 33 | router.route('/article', '/article-template.html') 34 | 35 | self.router = router 36 | }) 37 | 38 | self.addEventListener('fetch', function (event) { 39 | event.respondWith( 40 | return router.match(event.request.url, state) 41 | ) 42 | } 43 | ``` 44 | 45 | ## API 46 | ### `getParams` 47 | ### `parseTemplate` 48 | ### `renderTemplate` 49 | ### `Router` 50 | ## License 51 | [MIT](/license) 52 | --------------------------------------------------------------------------------