├── assets ├── robots.txt ├── favicon.ico ├── favicon.png ├── global.css ├── images │ └── touch-icons │ │ ├── logo-192.png │ │ └── logo-800.png ├── manifest.json ├── __app.html └── 404.svg ├── sandbox.config.json ├── src ├── pages │ ├── _layout.svelte │ ├── index.svelte │ └── _fallback.svelte ├── main.js ├── App.svelte ├── Serviceworker.svelte └── sw.js ├── .gitignore ├── api ├── vercel-ssr │ ├── package.json │ ├── index.js │ └── build.js └── netlify │ ├── package.json │ ├── ssr.js │ └── utils │ └── build.js ├── .nolluprc.js ├── postcss.config.js ├── vercel.json ├── LICENSE ├── netlify.toml ├── tailwind.config.js ├── README.md ├── package.json └── rollup.config.js /assets/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /sandbox.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "container": { 3 | "port": 5000 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/_layout.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamualfa/routify-tailwind/HEAD/assets/favicon.ico -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamualfa/routify-tailwind/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /assets/global.css: -------------------------------------------------------------------------------- 1 | 2 | @import "tailwindcss/base.css"; 3 | @import "tailwindcss/components.css"; 4 | @import "tailwindcss/utilities.css"; -------------------------------------------------------------------------------- /assets/images/touch-icons/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamualfa/routify-tailwind/HEAD/assets/images/touch-icons/logo-192.png -------------------------------------------------------------------------------- /assets/images/touch-icons/logo-800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamualfa/routify-tailwind/HEAD/assets/images/touch-icons/logo-800.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | /dist/ 3 | .DS_Store 4 | **/.history 5 | src/tmp/ 6 | .routify 7 | .netlify 8 | assets/build 9 | .vercel 10 | -------------------------------------------------------------------------------- /api/vercel-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "vercel-build": "node ./build.js" 4 | }, 5 | "devDependencies": { 6 | "rollup": "^2.28.2" 7 | } 8 | } -------------------------------------------------------------------------------- /.nolluprc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | hot: true, 3 | contentBase: 'assets', 4 | publicPath: 'build', 5 | historyApiFallback: '__app.html', 6 | port: 5000 7 | } 8 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import HMR from '@roxi/routify/hmr' 2 | import App from './App.svelte'; 3 | 4 | const app = HMR(App, { target: document.body }, 'routify-app') 5 | 6 | export default app; -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('tailwindcss'), 5 | require('postcss-preset-env')({ stage: 1 }), 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /src/App.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "functions": { 4 | "api/vercel-ssr/index.js": { 5 | "includeFiles": "dist/**" 6 | } 7 | }, 8 | "routes": [ 9 | { 10 | "handle": "filesystem" 11 | }, 12 | { 13 | "src": "/.*", 14 | "dest": "/api/vercel-ssr/index.js" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/index.svelte: -------------------------------------------------------------------------------- 1 |
2 |

Routify + Tailwind CSS template

3 |

4 | Visit 5 | Official Repository 8 | for further information. 9 |

10 |
11 | -------------------------------------------------------------------------------- /api/netlify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssr", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "ssr.js", 6 | "scripts": { 7 | "build": "node utils/build.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "esbuild": "^0.8.8", 14 | "tossr": "^1.3.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /api/vercel-ssr/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { tossr } = require('tossr') 3 | 4 | const script = fs.readFileSync(require.resolve('../../dist/build/bundle.js'), 'utf8') 5 | const template = fs.readFileSync(require.resolve('../../dist/__app.html'), 'utf8') 6 | 7 | module.exports = async (req, res) => { 8 | const html = await tossr(template, script, req.url, {}) 9 | res.send(html + '\n') 10 | } 11 | 12 | -------------------------------------------------------------------------------- /api/netlify/ssr.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { tossr } = require('tossr') 3 | const { script, template } = require('./bundle.json') 4 | 5 | exports.handler = async (event, context) => { 6 | const qs = Object.entries(event.queryStringParameters) 7 | .map(([key, value]) => `${key}=${value}`) 8 | .join('&'); 9 | const body = await tossr(template, script, `${event.path}?${qs}`); 10 | return { statusCode: 200, body: body + '\n' } 11 | } 12 | -------------------------------------------------------------------------------- /src/pages/_fallback.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 18 |
19 |
404
20 |
Page not found. 21 | 22 | Go back 23 |
24 |
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2020 Laode Muhammad Al Fatih 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | 2 | [build] 3 | publish = "dist" 4 | functions = "api/netlify" 5 | command = "npm run build && cd api/netlify && npm run build" 6 | 7 | # Dev doesn't work yet. Any takers? 8 | # [dev] 9 | # command = "npm run dev:ssr" 10 | # targetPort = 5000 11 | # publish = "assets" 12 | # autoLaunch = true 13 | 14 | [[redirects]] 15 | # SSR and SPA 16 | from = "/*" 17 | to = "/.netlify/functions/ssr" 18 | status = 200 19 | 20 | # SPA only 21 | # from = "/*" 22 | # to = "/__app.html" 23 | # status = 200 -------------------------------------------------------------------------------- /assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background_color": "#ffffff", 3 | "theme_color": "#E938C2", 4 | "name": "Routify app", 5 | "short_name": "Routify app", 6 | "start_url": "/", 7 | "display": "standalone", 8 | "icons": [ 9 | { 10 | "src": "/images/touch-icons/logo-192.png", 11 | "sizes": "192x192", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "/images/touch-icons/logo-800.png", 16 | "sizes": "800x800", 17 | "type": "image/png", 18 | "purpose": "maskable any" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/Serviceworker.svelte: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /assets/__app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Routify + TailwindCSS 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /api/netlify/utils/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creates a JSON and inlines it with esbuild for ssr.js to consume 3 | * { 4 | * data: duh, 5 | * script: inlined main.js 6 | * template: __app.html 7 | * } 8 | */ 9 | 10 | const { resolve } = require('path') 11 | const { readFileSync, writeFileSync } = require('fs') 12 | const { build } = require('esbuild') 13 | 14 | const scriptPath = resolve(__dirname, '../../../dist/build/main.js') 15 | const templatePath = resolve(__dirname, '../../../dist/__app.html') 16 | const bundlePath = resolve(__dirname, '../build/bundle.js') 17 | 18 | build({ entryPoints: [scriptPath], outfile: bundlePath, bundle: true }).then(() => { 19 | const bundle = { 20 | date: new Date, 21 | script: readFileSync(bundlePath, 'utf8'), 22 | template: readFileSync(templatePath, 'utf8') 23 | } 24 | 25 | writeFileSync(resolve(__dirname, '../bundle.json'), JSON.stringify(bundle, null, 2)) 26 | }) 27 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const { tailwindExtractor } = require('tailwindcss/lib/lib/purgeUnusedStyles'); 2 | 3 | const svelteClassColonExtractor = (content) => { 4 | return content.match(/(?<=class:)([a-zA-Z0-9_-]+)/gm) || []; 5 | }; 6 | 7 | module.exports = { 8 | purge: { 9 | enabled: !process.env.ROLLUP_WATCH, 10 | content: [ 11 | './src/**/*.svelte', 12 | './src/**/*.html', 13 | './src/**/*.css', 14 | './index.html', 15 | ], 16 | preserveHtmlElements: true, 17 | options: { 18 | safelist: [/svelte-/], 19 | defaultExtractor: (content) => { 20 | // WARNING: tailwindExtractor is internal tailwind api 21 | // if this breaks after a tailwind update, report to svite repo 22 | return [ 23 | ...tailwindExtractor(content), 24 | ...svelteClassColonExtractor(content), 25 | ]; 26 | }, 27 | keyframes: true, 28 | }, 29 | }, 30 | theme: { 31 | extend: {}, 32 | }, 33 | variants: {}, 34 | plugins: [], 35 | }; 36 | -------------------------------------------------------------------------------- /api/vercel-ssr/build.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path') 2 | const { existsSync } = require('fs') 3 | const { execSync } = require('child_process') 4 | const { rollup } = require('rollup') 5 | 6 | const shouldBuildSpa = process.env.NOW_GITHUB_DEPLOYMENT || process.env.NOW_BUILDER 7 | const script = resolve(__dirname, '../../dist/build/main.js') 8 | const bundlePath = resolve(__dirname, '../../dist/build/bundle.js') 9 | 10 | build() 11 | 12 | 13 | async function build() { 14 | if (shouldBuildSpa) 15 | execSync('npm install && npm run build:app', { cwd: resolve('..', '..'), stdio: 'inherit' }) 16 | else 17 | await waitForAppToExist() 18 | 19 | buildSSRBundle() 20 | } 21 | 22 | async function waitForAppToExist() { 23 | while (!existsSync(script)) { 24 | console.log(`checking if "${script}" exists`) 25 | await new Promise(r => setTimeout(r, 2000)) 26 | } 27 | console.log(`found "${script}"`) 28 | } 29 | 30 | async function buildSSRBundle() { 31 | const bundle = await rollup({ 32 | input: script, 33 | inlineDynamicImports: true, 34 | }) 35 | await bundle.write({ format: 'umd', file: bundlePath, name: 'roxi-ssr' }) 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Use Routify with Tailwind CSS 2 | 3 | Check out demo [Here](https://routify-tailwind.vercel.app/). 4 | 5 | ## Features 6 | 7 | - Purging Styles in Svelte component 8 | 9 | ## Installation 10 | 11 | ```bash 12 | npx degit lamualfa/routify-tailwind folder-name 13 | ``` 14 | 15 | The command above will create a new folder with the name `folder-name` which contains Routify + Tailwind CSS template. 16 | 17 | ## Environment Used 18 | 19 | - Routify `2.5.1-next-major` 20 | - Tailwind `2.0.2` 21 | - PostCSS `8.2.1` 22 | 23 | ## Note 24 | 25 | **This template use _Tailwind CSS_ `v2.0.2`.** If you need the latest version, just run the command `yarn add tailwindcss` or `npm install tailwindcss` to update the Tailwind CSS. 26 | 27 | Special thank's to [dominikg/svite](https://github.com/dominikg/svite) for the Tailwind configuration file. 28 | 29 |
30 | 31 | ## Related 32 | 33 | - [routify-ts](https://github.com/lamualfa/routify-ts) - Use Typescript in Routify Project. 34 | - [routify-twind](https://github.com/lamualfa/routify-twind) - Use Twind (_Tailwind CSS in JS version_) in Routify. 35 | - [routify-windi](https://github.com/lamualfa/routify-windi) - Use Windi CSS (_Next generation of Tailwind CSS compiler_) in Routify. 36 | - [routify-carbon](https://github.com/lamualfa/routify-carbon) - Use IBM Carbon Framework in Routify. 37 | - [routify-vite](https://github.com/lamualfa/routify-vite) Use Vite (_Next Generation Frontend Tooling_) in Routify. 38 | - [routify-vite-ts](https://github.com/lamualfa/routify-vite-ts) Use Vite (_Next Generation Frontend Tooling_) & Typescript in Routify. 39 | 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "version": "1.0.0", 4 | "@comments scripts": { 5 | "dev": "develop with blazing fast rebuilds", 6 | "dev:features": "develop with features like SSR and serviceworker enabled", 7 | "build": "run build scripts below", 8 | "build:app": "build single page application (SPA)", 9 | "build:static": "Generate static pages", 10 | "serve": "serve content in 'dist' folder", 11 | "rollup": "run the rollup bundler", 12 | "nollup": "run the nollup no-bundler", 13 | "routify": "run routify" 14 | }, 15 | "scripts": { 16 | "dev": "run-p routify nollup", 17 | "dev:ssr": "run-p routify rollup", 18 | "build": "run-s build:*", 19 | "build:app": "routify -b && rollup -c", 20 | "build:static": "spank", 21 | "serve": "spassr --ssr", 22 | "rollup": "rollup -cw", 23 | "nollup": "nollup -c", 24 | "routify": "routify" 25 | }, 26 | "devDependencies": { 27 | "@rollup/plugin-commonjs": "^15.0.0", 28 | "@rollup/plugin-node-resolve": "^10.0.0", 29 | "@roxi/routify": "^2.8.5", 30 | "cross-env": "^7.0.3", 31 | "fs-extra": "^9.0.1", 32 | "nollup": "^0.13.13", 33 | "npm-run-all": "^4.1.5", 34 | "postcss": "^8.2.1", 35 | "postcss-import": "^14.0.0", 36 | "postcss-load-config": "^3.0.0", 37 | "postcss-preset-env": "^6.7.0", 38 | "rollup": "^2.33.1", 39 | "rollup-plugin-hot": "^0.1.1", 40 | "rollup-plugin-inject-process-env": "^1.3.1", 41 | "rollup-plugin-livereload": "^2.0.0", 42 | "rollup-plugin-svelte": "^6.1.0", 43 | "rollup-plugin-svelte-hot": "^0.11.1", 44 | "rollup-plugin-terser": "^7.0.2", 45 | "rollup-plugin-workbox": "^5.2.1", 46 | "spank": "^1.4.0", 47 | "spassr": "^2.1.6", 48 | "svelte": "^3.29.4", 49 | "svelte-preprocess": "^4.5.2", 50 | "tailwindcss": "^2.0.2", 51 | "tossr": "^1.3.1" 52 | }, 53 | "routify": { 54 | "extensions": "svelte,html,svx,md" 55 | }, 56 | "spassr": { 57 | "assetsDir": [ 58 | "dist", 59 | "assets" 60 | ], 61 | "script": "dist/build/main.js", 62 | "ssrOptions": { 63 | "inlineDynamicImports": true 64 | } 65 | }, 66 | "spank": { 67 | "blacklist": [ 68 | "/example/modal/basic/4" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import svelte from 'rollup-plugin-svelte-hot'; 2 | import Hmr from 'rollup-plugin-hot' 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import commonjs from '@rollup/plugin-commonjs'; 5 | import livereload from 'rollup-plugin-livereload'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | import { copySync, removeSync } from 'fs-extra' 8 | import { spassr } from 'spassr' 9 | import getConfig from '@roxi/routify/lib/utils/config' 10 | import autoPreprocess from 'svelte-preprocess' 11 | import { injectManifest } from 'rollup-plugin-workbox' 12 | import injectProcessEnv from 'rollup-plugin-inject-process-env'; 13 | 14 | 15 | const { distDir } = getConfig() // use Routify's distDir for SSOT 16 | const assetsDir = 'assets' 17 | const buildDir = `dist/build` 18 | const isNollup = !!process.env.NOLLUP 19 | const production = !process.env.ROLLUP_WATCH; 20 | 21 | // clear previous builds 22 | removeSync(distDir) 23 | removeSync(buildDir) 24 | 25 | 26 | const serve = () => ({ 27 | writeBundle: async () => { 28 | const options = { 29 | assetsDir: [assetsDir, distDir], 30 | entrypoint: `${assetsDir}/__app.html`, 31 | script: `${buildDir}/main.js` 32 | } 33 | spassr({ ...options, port: 5000 }) 34 | spassr({ ...options, ssr: true, port: 5005, ssrOptions: { inlineDynamicImports: true, dev: true } }) 35 | } 36 | }) 37 | const copyToDist = () => ({ writeBundle() { copySync(assetsDir, distDir) } }) 38 | 39 | 40 | export default { 41 | preserveEntrySignatures: false, 42 | input: [`src/main.js`], 43 | output: { 44 | sourcemap: true, 45 | format: 'esm', 46 | dir: buildDir, 47 | // for performance, disabling filename hashing in development 48 | chunkFileNames: `[name]${(production && '-[hash]') || ''}.js`, 49 | }, 50 | plugins: [ 51 | svelte({ 52 | dev: !production, // run-time checks 53 | // Extract component CSS — better performance 54 | css: (css) => css.write(`bundle.css`), 55 | hot: isNollup, 56 | preprocess: [ 57 | autoPreprocess({ 58 | postcss: { configFilePath: './postcss.config.js' }, 59 | defaults: { style: 'postcss' }, 60 | }), 61 | ], 62 | }), 63 | 64 | // resolve matching modules from current working directory 65 | resolve({ 66 | browser: true, 67 | dedupe: (importee) => !!importee.match(/svelte(\/|$)/), 68 | }), 69 | commonjs(), 70 | 71 | production && terser(), 72 | !production && !isNollup && serve(), 73 | !production && !isNollup && livereload(distDir), // refresh entire window when code is updated 74 | !production && isNollup && Hmr({ inMemory: true, public: assetsDir }), // refresh only updated code 75 | injectProcessEnv({ 76 | NODE_ENV: production ? 'production' : 'development', 77 | }), 78 | injectManifest({ 79 | globDirectory: assetsDir, 80 | globPatterns: ['**/*.{js,css,svg}', '__app.html'], 81 | swSrc: `src/sw.js`, 82 | swDest: `dist/serviceworker.js`, 83 | maximumFileSizeToCacheInBytes: 10000000, // 10 MB, 84 | mode: 'production', 85 | }), 86 | production && copyToDist(), 87 | ], 88 | watch: { 89 | clearScreen: false, 90 | buildDelay: 100, 91 | }, 92 | }; -------------------------------------------------------------------------------- /assets/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sw.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import { registerRoute, setDefaultHandler, setCatchHandler } from 'workbox-routing'; 4 | import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'; 5 | import { skipWaiting, clientsClaim } from 'workbox-core'; 6 | import { precacheAndRoute, matchPrecache } from 'workbox-precaching'; 7 | import { ExpirationPlugin } from 'workbox-expiration'; 8 | import { RoutifyPlugin, freshCacheData } from '@roxi/routify/workbox-plugin' 9 | 10 | 11 | 12 | /********** 13 | * CONFIG * 14 | **********/ 15 | 16 | const entrypointUrl = '__app.html' // entrypoint 17 | const fallbackImage = '404.svg' 18 | const files = self.__WB_MANIFEST // files matching globDirectory and globPattern in rollup.config.js 19 | 20 | const externalAssetsConfig = () => ({ 21 | cacheName: 'external', 22 | plugins: [ 23 | RoutifyPlugin({ 24 | validFor: 60 // cache is considered fresh for n seconds. 25 | }), 26 | new ExpirationPlugin({ 27 | maxEntries: 50, // last used entries will be purged when we hit this limit 28 | purgeOnQuotaError: true // purge external assets on quota error 29 | })] 30 | }) 31 | 32 | 33 | 34 | 35 | /************** 36 | * INITIALIZE * 37 | **************/ 38 | 39 | /** 40 | * precache all files 41 | * remember to precache __app.html and 404.svg if caching of all files is disabled 42 | */ 43 | precacheAndRoute(files) 44 | 45 | /** precache only fallback files */ 46 | // precacheAndRoute(files.filter(file => 47 | // ['__app.html', '404.svg'] 48 | // .includes(file.url) 49 | // )) 50 | 51 | skipWaiting() // auto update service workers across all tabs when new release is available 52 | clientsClaim() // take control of client without having to wait for refresh 53 | 54 | /** 55 | * manually upgrade service worker by sending a SKIP_WAITING message. 56 | * (remember to disable skipWaiting() above) 57 | */ 58 | // addEventListener('message', event => { if (event.data && event.data.type === 'SKIP_WAITING') skipWaiting(); }); 59 | 60 | 61 | 62 | /********** 63 | * ROUTES * 64 | **********/ 65 | 66 | // serve local pages from the SPA entry point (__app.html) 67 | registerRoute(isLocalPage, matchPrecache(entrypointUrl)) 68 | 69 | // serve local assets from cache first 70 | registerRoute(isLocalAsset, new CacheFirst()) 71 | 72 | // serve external assets from cache if they're fresh 73 | registerRoute(hasFreshCache, new CacheFirst(externalAssetsConfig())) 74 | 75 | // serve external pages and assets 76 | setDefaultHandler(new NetworkFirst(externalAssetsConfig())); 77 | 78 | // serve a fallback for 404s if possible or respond with an error 79 | setCatchHandler(async ({ event }) => { 80 | switch (event.request.destination) { 81 | case 'document': 82 | return await matchPrecache(entrypointUrl) 83 | case 'image': 84 | return await matchPrecache(fallbackImage) 85 | default: 86 | return Response.error(); 87 | } 88 | }) 89 | 90 | 91 | 92 | /********** 93 | * CONDITIONS * 94 | **********/ 95 | 96 | function isLocalAsset({ url, request }) { return url.host === self.location.host && request.destination != 'document' } 97 | function isLocalPage({ url, request }) { return url.host === self.location.host && request.destination === 'document' } 98 | function hasFreshCache(event) { return !!freshCacheData(event) } 99 | 100 | /** Example condition */ 101 | function hasWitheringCache(event) { 102 | const cache = freshCacheData(event) 103 | if (cache) { 104 | const { cachedAt, validFor, validLeft, validUntil } = cache 105 | // return true if half the fresh time has passed 106 | return validFor / 2 > validFor - validLeft 107 | } 108 | } --------------------------------------------------------------------------------