├── .github └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js ├── src ├── client.ts ├── routes │ ├── _error.svelte │ ├── _layout.svelte │ ├── example.ts │ └── index.svelte ├── server.ts ├── service-worker.ts └── template.html ├── static ├── favicon.png ├── logo-192.png ├── logo-512.png └── manifest.json ├── svelte.config.js └── tsconfig.json /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: push 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [10.x, 12.x, 14.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - run: npm i 24 | - run: npm run build 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .DS_Store 3 | /.history/ 4 | /node_modules/ 5 | __sapper__/ 6 | /src/node_modules/@sapper/ 7 | package-lock.json 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tom Bazarnik 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 | # Sapper Typescript ESBuild 2 | 3 | This is a minimal Sapper project template, inspired by [@babichjacob](https://github.com/babichjacob)'s [`sapper-typescript-graphql-template`](https://github.com/babichjacob/sapper-typescript-graphql-template), which uses `@rollup/plugin-typescript` and `@rollup/plugin-babel`, which are ditched in favor of `rollup-plugin-esbuild` in this template to increase performance, while `tsc` and `svelte-check` will type-check source files in parallel. 4 | 5 | ### Getting started 6 | 7 | ```bash 8 | npm install 9 | npm run dev 10 | ``` 11 | 12 | ### Export 13 | 14 | ```bash 15 | npm run export 16 | ``` 17 | 18 | ### Caveats 19 | 20 | - Server code minification is disabled if using Sapper `0.28.1` or newer, due to a known issue with ESBuild ([#3](https://github.com/tommywalkie/sapper-typescript-esbuild-template/issues/3)). 21 | 22 | - Normal comments inside ` 8 | 9 | 29 | 30 |
31 |

{error.message}

32 |

{status}

33 |
34 | 35 | {#if dev && error.stack} 36 |
{error.stack}
37 | {/if} -------------------------------------------------------------------------------- /src/routes/_layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 15 | 16 | {path ? path.charAt(0).toUpperCase() + path.slice(1) : "Index"} 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/routes/example.ts: -------------------------------------------------------------------------------- 1 | export const a: number = 1 2 | -------------------------------------------------------------------------------- /src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 15 | 16 |
17 |

Hello {dest}, magic number is {a}

18 |
-------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import * as sapper from '@sapper/server' 2 | import compression from 'compression' 3 | import polka from 'polka' 4 | import sirv from 'sirv' 5 | 6 | const PORT = process.env.PORT 7 | const mode = process.env.NODE_ENV 8 | const dev: boolean = mode === "development" 9 | 10 | const app = polka() 11 | 12 | app.use( 13 | compression({ threshold: 0 }), 14 | sirv("static", { dev }), 15 | sapper.middleware(), 16 | ).listen(PORT, (err: any) => { 17 | if (err) console.log('error', err) 18 | }) -------------------------------------------------------------------------------- /src/service-worker.ts: -------------------------------------------------------------------------------- 1 | import { timestamp, files, shell } from "@sapper/service-worker"; 2 | 3 | const ASSETS = `cache${timestamp}`; 4 | 5 | // `shell` is an array of all the files generated by the bundler, 6 | // `files` is an array of everything in the `static` directory 7 | const toCache = (shell as string[]).concat(files as string[]); 8 | const cached = new Set(toCache); 9 | 10 | self.addEventListener("install", (event: EventType) => { 11 | event.waitUntil( 12 | caches 13 | .open(ASSETS) 14 | .then((cache) => cache.addAll(toCache)) 15 | .then(() => { 16 | (self as any as ServiceWorkerGlobalScope).skipWaiting(); 17 | }), 18 | ); 19 | }); 20 | 21 | self.addEventListener("activate", (event: EventType) => { 22 | event.waitUntil( 23 | caches.keys().then(async (keys) => { 24 | // delete old caches 25 | for (const key of keys) { // eslint-disable-line no-restricted-syntax 26 | if (key !== ASSETS) await caches.delete(key); // eslint-disable-line no-await-in-loop 27 | } 28 | 29 | (self as any as {clients: Clients}).clients.claim(); 30 | }), 31 | ); 32 | }); 33 | 34 | self.addEventListener("fetch", (event: EventType) => { 35 | if (event.request.method !== "GET" || event.request.headers.has("range")) return; 36 | 37 | const url = new URL(event.request.url); 38 | 39 | // don't try to handle e.g. data: URIs 40 | if (!url.protocol.startsWith("http")) return; 41 | 42 | // ignore dev server requests 43 | if (url.hostname === self.location.hostname && url.port !== self.location.port) return; 44 | 45 | // always serve static files and bundler-generated assets from cache 46 | if (url.host === self.location.host && cached.has(url.pathname)) { 47 | caches.match(event.request).then((match): void => { 48 | if (match) event.respondWith(match); 49 | }); 50 | return; 51 | } 52 | 53 | // for pages, you might want to serve a shell `service-worker-index.html` file, 54 | // which Sapper has generated for you. It's not right for every 55 | // app, but if it's right for yours then uncomment this section 56 | /* 57 | if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) { 58 | event.respondWith(caches.match('/service-worker-index.html')); 59 | return; 60 | } 61 | */ 62 | 63 | if (event.request.cache === "only-if-cached") return; 64 | 65 | // for everything else, try the network first, falling back to 66 | // cache if the user is offline. (If the pages never change, you 67 | // might prefer a cache-first approach to a network-first one.) 68 | event.respondWith( 69 | caches 70 | .open(`offline${timestamp}`) 71 | .then(async (cache) => { 72 | try { 73 | const response = await fetch(event.request); 74 | cache.put(event.request, response.clone()); 75 | return response; 76 | } catch (err) { 77 | const response = await cache.match(event.request); 78 | if (response) return response; 79 | 80 | throw err; 81 | } 82 | }), 83 | ); 84 | }); -------------------------------------------------------------------------------- /src/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sapper.base% 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | %sapper.styles% 18 | 19 | 21 | %sapper.head% 22 | 23 | 24 | 25 |
26 | %sapper.html% 27 |
28 | 29 | %sapper.scripts% 30 | 31 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommywalkie/sapper-typescript-esbuild-template/3cffca8ec2deca541735a40d3785698be620f1aa/static/favicon.png -------------------------------------------------------------------------------- /static/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommywalkie/sapper-typescript-esbuild-template/3cffca8ec2deca541735a40d3785698be620f1aa/static/logo-192.png -------------------------------------------------------------------------------- /static/logo-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommywalkie/sapper-typescript-esbuild-template/3cffca8ec2deca541735a40d3785698be620f1aa/static/logo-512.png -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background_color": "#ffffff", 3 | "theme_color": "#333333", 4 | "name": "sapper-typescript-esbuild", 5 | "short_name": "sapper-ts-esbuild", 6 | "display": "minimal-ui", 7 | "start_url": "/", 8 | "icons": [ 9 | { 10 | "src": "logo-192.png", 11 | "sizes": "192x192", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "logo-512.png", 16 | "sizes": "512x512", 17 | "type": "image/png" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require("svelte-preprocess"); 2 | 3 | const defaults = { 4 | script: "typescript", 5 | }; 6 | 7 | module.exports = { 8 | // Real svelte-preprocess configuration is in `rollup.config.js` 9 | // This is only for the language server for VS Code and svelte-check 10 | preprocess: sveltePreprocess({ defaults }) 11 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "include": ["src/**/*"], 4 | "exclude": [ 5 | "node_modules/**/*", 6 | "__sapper__/**/*", 7 | "public/**/*" 8 | ], 9 | "compilerOptions": { 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "lib": ["DOM", "WebWorker"], 14 | "types": ["svelte", "node", "sapper/runtime"], 15 | "typeRoots": [ "./node_modules/@types" ] 16 | } 17 | } --------------------------------------------------------------------------------