├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── public └── index.html ├── rollup.config.js ├── server.js └── src ├── App.svelte ├── main.js └── url.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public/build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bjorn Lu 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 | # Svelte URL 2 | 3 | Barebones routing with reactive URLs 4 | 5 | https://svelte.dev/repl/5abaac000b164aa1aacc6051d5c4f584?version=3 6 | 7 | ```svelte 8 | {#if $url.pathname === '/'} 9 |

Home Sweet Home

10 | {:else if $url.pathname === '/about'} 11 |

About What?

12 | {:else} 13 |

404

14 | {/if} 15 | ``` 16 | 17 | ## How to use 18 | 19 | This is not an NPM package. The heart of this repo is at [src/url.js](./src/url.js). It's only a single file so feel free to copy-paste it into your project. 20 | 21 | ## Try it out 22 | 23 | ```bash 24 | # Copy project with degit 25 | $ npx degit bluwy/svelte-url svelte-app 26 | 27 | # Change to project directory 28 | $ cd svelte-app 29 | 30 | # Install dependencies 31 | $ pnpm install 32 | 33 | # Build project 34 | $ pnpm build 35 | 36 | # Serve SPA at http://localhost:5001 37 | $ pnpm serve:spa 38 | 39 | # Or serve SSR at http://localhost:5002 40 | $ pnpm serve:ssr 41 | ``` 42 | 43 | ## License 44 | 45 | MIT 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-url", 3 | "version": "1.0.0", 4 | "description": "Svelte reactive URL", 5 | "private": true, 6 | "author": "Bjorn Lu", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "rollup -c", 10 | "serve:spa": "sirv public -s --port 3000", 11 | "serve:ssr": "node server.js" 12 | }, 13 | "devDependencies": { 14 | "@rollup/plugin-node-resolve": "^9.0.0", 15 | "@types/node": "^14.18.54", 16 | "polka": "^0.5.2", 17 | "rollup": "^2.79.1", 18 | "rollup-plugin-svelte": "^6.1.1", 19 | "sirv": "^1.0.19", 20 | "sirv-cli": "^1.0.14", 21 | "svelte": "^3.59.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | devDependencies: 8 | '@rollup/plugin-node-resolve': 9 | specifier: ^9.0.0 10 | version: 9.0.0(rollup@2.79.1) 11 | '@types/node': 12 | specifier: ^14.18.54 13 | version: 14.18.54 14 | polka: 15 | specifier: ^0.5.2 16 | version: 0.5.2 17 | rollup: 18 | specifier: ^2.79.1 19 | version: 2.79.1 20 | rollup-plugin-svelte: 21 | specifier: ^6.1.1 22 | version: 6.1.1(rollup@2.79.1)(svelte@3.59.2) 23 | sirv: 24 | specifier: ^1.0.19 25 | version: 1.0.19 26 | sirv-cli: 27 | specifier: ^1.0.14 28 | version: 1.0.14 29 | svelte: 30 | specifier: ^3.59.2 31 | version: 3.59.2 32 | 33 | packages: 34 | 35 | /@arr/every@1.0.1: 36 | resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} 37 | engines: {node: '>=4'} 38 | dev: true 39 | 40 | /@polka/url@0.5.0: 41 | resolution: {integrity: sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==} 42 | dev: true 43 | 44 | /@polka/url@1.0.0-next.21: 45 | resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} 46 | dev: true 47 | 48 | /@rollup/plugin-node-resolve@9.0.0(rollup@2.79.1): 49 | resolution: {integrity: sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==} 50 | engines: {node: '>= 10.0.0'} 51 | peerDependencies: 52 | rollup: ^1.20.0||^2.0.0 53 | dependencies: 54 | '@rollup/pluginutils': 3.1.0(rollup@2.79.1) 55 | '@types/resolve': 1.17.1 56 | builtin-modules: 3.3.0 57 | deepmerge: 4.3.1 58 | is-module: 1.0.0 59 | resolve: 1.22.2 60 | rollup: 2.79.1 61 | dev: true 62 | 63 | /@rollup/pluginutils@3.1.0(rollup@2.79.1): 64 | resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} 65 | engines: {node: '>= 8.0.0'} 66 | peerDependencies: 67 | rollup: ^1.20.0||^2.0.0 68 | dependencies: 69 | '@types/estree': 0.0.39 70 | estree-walker: 1.0.1 71 | picomatch: 2.3.1 72 | rollup: 2.79.1 73 | dev: true 74 | 75 | /@types/estree@0.0.39: 76 | resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} 77 | dev: true 78 | 79 | /@types/node@14.18.54: 80 | resolution: {integrity: sha512-uq7O52wvo2Lggsx1x21tKZgqkJpvwCseBBPtX/nKQfpVlEsLOb11zZ1CRsWUKvJF0+lzuA9jwvA7Pr2Wt7i3xw==} 81 | dev: true 82 | 83 | /@types/resolve@1.17.1: 84 | resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} 85 | dependencies: 86 | '@types/node': 14.18.54 87 | dev: true 88 | 89 | /builtin-modules@3.3.0: 90 | resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} 91 | engines: {node: '>=6'} 92 | dev: true 93 | 94 | /console-clear@1.1.1: 95 | resolution: {integrity: sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==} 96 | engines: {node: '>=4'} 97 | dev: true 98 | 99 | /deepmerge@4.3.1: 100 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 101 | engines: {node: '>=0.10.0'} 102 | dev: true 103 | 104 | /estree-walker@0.6.1: 105 | resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} 106 | dev: true 107 | 108 | /estree-walker@1.0.1: 109 | resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} 110 | dev: true 111 | 112 | /fsevents@2.3.2: 113 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 114 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 115 | os: [darwin] 116 | requiresBuild: true 117 | dev: true 118 | optional: true 119 | 120 | /function-bind@1.1.1: 121 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 122 | dev: true 123 | 124 | /get-port@3.2.0: 125 | resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} 126 | engines: {node: '>=4'} 127 | dev: true 128 | 129 | /has@1.0.3: 130 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 131 | engines: {node: '>= 0.4.0'} 132 | dependencies: 133 | function-bind: 1.1.1 134 | dev: true 135 | 136 | /is-core-module@2.12.1: 137 | resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} 138 | dependencies: 139 | has: 1.0.3 140 | dev: true 141 | 142 | /is-module@1.0.0: 143 | resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 144 | dev: true 145 | 146 | /kleur@3.0.3: 147 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} 148 | engines: {node: '>=6'} 149 | dev: true 150 | 151 | /local-access@1.1.0: 152 | resolution: {integrity: sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==} 153 | engines: {node: '>=6'} 154 | dev: true 155 | 156 | /matchit@1.1.0: 157 | resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==} 158 | engines: {node: '>=6'} 159 | dependencies: 160 | '@arr/every': 1.0.1 161 | dev: true 162 | 163 | /mri@1.2.0: 164 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 165 | engines: {node: '>=4'} 166 | dev: true 167 | 168 | /mrmime@1.0.1: 169 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} 170 | engines: {node: '>=10'} 171 | dev: true 172 | 173 | /path-parse@1.0.7: 174 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 175 | dev: true 176 | 177 | /picomatch@2.3.1: 178 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 179 | engines: {node: '>=8.6'} 180 | dev: true 181 | 182 | /polka@0.5.2: 183 | resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==} 184 | dependencies: 185 | '@polka/url': 0.5.0 186 | trouter: 2.0.1 187 | dev: true 188 | 189 | /require-relative@0.8.7: 190 | resolution: {integrity: sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==} 191 | dev: true 192 | 193 | /resolve@1.22.2: 194 | resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} 195 | hasBin: true 196 | dependencies: 197 | is-core-module: 2.12.1 198 | path-parse: 1.0.7 199 | supports-preserve-symlinks-flag: 1.0.0 200 | dev: true 201 | 202 | /rollup-plugin-svelte@6.1.1(rollup@2.79.1)(svelte@3.59.2): 203 | resolution: {integrity: sha512-ijnm0pH1ScrY4uxwaNXBpNVejVzpL2769hIEbAlnqNUWZrffLspu5/k9/l/Wsj3NrEHLQ6wCKGagVJonyfN7ow==} 204 | peerDependencies: 205 | rollup: '>=1.19.2' 206 | svelte: '*' 207 | dependencies: 208 | require-relative: 0.8.7 209 | rollup: 2.79.1 210 | rollup-pluginutils: 2.8.2 211 | sourcemap-codec: 1.4.8 212 | svelte: 3.59.2 213 | dev: true 214 | 215 | /rollup-pluginutils@2.8.2: 216 | resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} 217 | dependencies: 218 | estree-walker: 0.6.1 219 | dev: true 220 | 221 | /rollup@2.79.1: 222 | resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} 223 | engines: {node: '>=10.0.0'} 224 | hasBin: true 225 | optionalDependencies: 226 | fsevents: 2.3.2 227 | dev: true 228 | 229 | /sade@1.8.1: 230 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 231 | engines: {node: '>=6'} 232 | dependencies: 233 | mri: 1.2.0 234 | dev: true 235 | 236 | /semiver@1.1.0: 237 | resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==} 238 | engines: {node: '>=6'} 239 | dev: true 240 | 241 | /sirv-cli@1.0.14: 242 | resolution: {integrity: sha512-yyUTNr984ANKDloqepkYbBSqvx3buwYg2sQKPWjSU+IBia5loaoka2If8N9CMwt8AfP179cdEl7kYJ//iWJHjQ==} 243 | engines: {node: '>= 10'} 244 | hasBin: true 245 | dependencies: 246 | console-clear: 1.1.1 247 | get-port: 3.2.0 248 | kleur: 3.0.3 249 | local-access: 1.1.0 250 | sade: 1.8.1 251 | semiver: 1.1.0 252 | sirv: 1.0.19 253 | tinydate: 1.3.0 254 | dev: true 255 | 256 | /sirv@1.0.19: 257 | resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} 258 | engines: {node: '>= 10'} 259 | dependencies: 260 | '@polka/url': 1.0.0-next.21 261 | mrmime: 1.0.1 262 | totalist: 1.1.0 263 | dev: true 264 | 265 | /sourcemap-codec@1.4.8: 266 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 267 | deprecated: Please use @jridgewell/sourcemap-codec instead 268 | dev: true 269 | 270 | /supports-preserve-symlinks-flag@1.0.0: 271 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 272 | engines: {node: '>= 0.4'} 273 | dev: true 274 | 275 | /svelte@3.59.2: 276 | resolution: {integrity: sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==} 277 | engines: {node: '>= 8'} 278 | dev: true 279 | 280 | /tinydate@1.3.0: 281 | resolution: {integrity: sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==} 282 | engines: {node: '>=4'} 283 | dev: true 284 | 285 | /totalist@1.1.0: 286 | resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==} 287 | engines: {node: '>=6'} 288 | dev: true 289 | 290 | /trouter@2.0.1: 291 | resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==} 292 | engines: {node: '>=6'} 293 | dependencies: 294 | matchit: 1.1.0 295 | dev: true 296 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Svelte URL 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve' 2 | import svelte from 'rollup-plugin-svelte' 3 | 4 | export default [ 5 | // SPA 6 | { 7 | input: 'src/main.js', 8 | output: { 9 | format: 'iife', 10 | name: 'app', 11 | file: 'public/build/bundle.js', 12 | }, 13 | plugins: [ 14 | svelte({ 15 | dev: true, 16 | hydratable: true, 17 | css: (css) => { 18 | css.write('bundle.css') 19 | }, 20 | }), 21 | resolve({ 22 | browser: true, 23 | dedupe: ['svelte'], 24 | }), 25 | ], 26 | }, 27 | // SSR 28 | { 29 | input: 'src/App.svelte', 30 | output: { 31 | format: 'cjs', 32 | name: 'app', 33 | file: 'public/build/App.js', 34 | exports: 'named', 35 | }, 36 | plugins: [ 37 | svelte({ 38 | dev: true, 39 | generate: 'ssr', 40 | css: (css) => { 41 | css.write('bundle.css') 42 | }, 43 | }), 44 | resolve({ 45 | browser: false, 46 | dedupe: ['svelte'], 47 | }), 48 | ], 49 | }, 50 | ] 51 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { URL } = require('url') 3 | const sirv = require('sirv') 4 | const polka = require('polka') 5 | const App = require('./public/build/App').default 6 | 7 | const baseHtml = fs.readFileSync('public/index.html', { encoding: 'utf-8' }) 8 | 9 | polka() 10 | .use(sirv('public', { extensions: [] })) 11 | .use((req, res) => { 12 | const { html } = App.render({ 13 | props: { 14 | ssrUrl: new URL(req.url, `http://${req.headers.host}`).href 15 | } 16 | }) 17 | 18 | const result = baseHtml.replace( 19 | '
', 20 | `
${html}
` 21 | ) 22 | 23 | res.write(result) 24 | res.end() 25 | }) 26 | .listen(3001, (err) => { 27 | if (err) throw err 28 | console.log('Ready at http://localhost:3001') 29 | }) 30 | -------------------------------------------------------------------------------- /src/App.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | {#if $url.pathname === '/'} 26 |

Home Sweet Home

27 | {:else if $url.pathname === '/about'} 28 |

About What?

29 | {:else} 30 |

404

31 | {/if} 32 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte' 2 | 3 | const app = new App({ 4 | target: document.getElementById('app'), 5 | hydrate: true, 6 | }) 7 | 8 | export default app 9 | -------------------------------------------------------------------------------- /src/url.js: -------------------------------------------------------------------------------- 1 | import { derived, writable } from 'svelte/store' 2 | 3 | export function createUrlStore(ssrUrl) { 4 | // Ideally a bundler constant so that it's tree-shakable 5 | if (typeof window === 'undefined') { 6 | const { subscribe } = writable(ssrUrl) 7 | return { subscribe } 8 | } 9 | 10 | const href = writable(window.location.href) 11 | 12 | const originalPushState = history.pushState 13 | const originalReplaceState = history.replaceState 14 | 15 | const updateHref = () => href.set(window.location.href) 16 | 17 | history.pushState = function () { 18 | originalPushState.apply(this, arguments) 19 | updateHref() 20 | } 21 | 22 | history.replaceState = function () { 23 | originalReplaceState.apply(this, arguments) 24 | updateHref() 25 | } 26 | 27 | window.addEventListener('popstate', updateHref) 28 | window.addEventListener('hashchange', updateHref) 29 | 30 | return { 31 | subscribe: derived(href, ($href) => new URL($href)).subscribe 32 | } 33 | } 34 | 35 | // If you're using in a pure SPA, you can return a store directly and share it everywhere 36 | // export default createUrlStore() 37 | --------------------------------------------------------------------------------