diff --git a/CHANGELOG.md b/CHANGELOG.md
index d692da9..6baa194 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# sapper changelog
+## 0.25.0
+
+* Force refresh on `goto(current_url)` ([#484](https://github.com/sveltejs/sapper/pull/484))
+* Fix preloading navigation bug ([#532](https://github.com/sveltejs/sapper/issues/532))
+* Don't mutate opts.headers ([#528](https://github.com/sveltejs/sapper/issues/528))
+* Don't crawl hundreds of pages simultaneously ([#369](https://github.com/sveltejs/sapper/pull/369))
+
+## 0.24.3
+
+* Add service-worker-index.html shell file for offline support ([#422](https://github.com/sveltejs/sapper/issues/422))
+* Don't cache .map files ([#534](https://github.com/sveltejs/sapper/issues/534))
+
+## 0.24.2
+
+* Support Rollup 1.0 ([#541](https://github.com/sveltejs/sapper/pull/541))
+
## 0.24.1
* Include CSS chunks in webpack build info to avoid duplication ([#529](https://github.com/sveltejs/sapper/pull/529))
diff --git a/package-lock.json b/package-lock.json
index 51abda0..6ee03a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "sapper",
- "version": "0.25.0-alpha2",
+ "version": "0.26.0-alpha.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -43,9 +43,9 @@
"dev": true
},
"@types/events": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
- "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
+ "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
"dev": true
},
"@types/glob": {
@@ -81,15 +81,15 @@
"dev": true
},
"@types/node": {
- "version": "10.12.19",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.19.tgz",
- "integrity": "sha512-2NVovndCjJQj6fUUn9jCgpP4WSqr+u1SoUZMZyJkhGeBFsm6dE46l31S7lPUYt9uQ28XI+ibrJA1f5XyH5HNtA==",
+ "version": "10.12.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz",
+ "integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ==",
"dev": true
},
"@types/puppeteer": {
- "version": "1.11.2",
- "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-1.11.2.tgz",
- "integrity": "sha512-eHBXpiZz0+PrnvHID68OjwcBjTbK1V49sa4lxjq+jiEe2eaLbRl2F77icNg0ewiB2fgdHJUHBD/9ubjfKrvTEw==",
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-1.11.3.tgz",
+ "integrity": "sha512-i/kNectDkLqU4y8FfeMAdMv4KGVVCPUVqp+bfa5+teq0JdoAwplu7k6t38+rpAAbEmPSywf6aqWbg9JbUDJqiQ==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -897,9 +897,9 @@
"dev": true
},
"big.js": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
- "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
+ "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
"dev": true
},
"binary-extensions": {
@@ -1047,9 +1047,9 @@
"dev": true
},
"builtin-modules": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.0.0.tgz",
- "integrity": "sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
"builtin-status-codes": {
@@ -1078,6 +1078,14 @@
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ }
}
},
"cache-base": {
@@ -1121,9 +1129,9 @@
}
},
"chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
@@ -1742,17 +1750,16 @@
}
},
"es-abstract": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
- "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
+ "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
"dev": true,
"requires": {
- "es-to-primitive": "^1.2.0",
+ "es-to-primitive": "^1.1.1",
"function-bind": "^1.1.1",
- "has": "^1.0.3",
- "is-callable": "^1.1.4",
- "is-regex": "^1.0.4",
- "object-keys": "^1.0.12"
+ "has": "^1.0.1",
+ "is-callable": "^1.1.3",
+ "is-regex": "^1.0.4"
}
},
"es-to-primitive": {
@@ -1928,6 +1935,15 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
+ },
+ "resolve": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
+ "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
}
}
},
@@ -2922,15 +2938,15 @@
"dev": true
},
"globrex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
- "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.1.tgz",
+ "integrity": "sha512-bqKcPhb+ZtrISivpu6oLmwIyINlPlzueO/BDCdfnzUeu7SYxnHTXmWP7uQI5PnQXc5yGXOscGBEGagloA2hcSw==",
"dev": true
},
"graceful-fs": {
- "version": "4.1.15",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
- "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
},
"growl": {
@@ -3041,9 +3057,10 @@
}
},
"he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+ "dev": true
},
"hmac-drbg": {
"version": "1.0.1",
@@ -3074,6 +3091,13 @@
"param-case": "2.1.x",
"relateurl": "0.2.x",
"uglify-js": "3.4.x"
+ },
+ "dependencies": {
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+ }
}
},
"https-browserify": {
@@ -3169,21 +3193,21 @@
"dev": true
},
"inquirer": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
- "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
+ "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
"dev": true,
"requires": {
- "ansi-escapes": "^3.0.0",
- "chalk": "^2.0.0",
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
- "external-editor": "^3.0.0",
+ "external-editor": "^3.0.3",
"figures": "^2.0.0",
- "lodash": "^4.17.10",
+ "lodash": "^4.17.11",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
- "rxjs": "^6.1.0",
+ "rxjs": "^6.4.0",
"string-width": "^2.1.0",
"strip-ansi": "^5.0.0",
"through": "^2.3.6"
@@ -3195,6 +3219,17 @@
"integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==",
"dev": true
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"strip-ansi": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz",
@@ -3237,12 +3272,12 @@
"dev": true
},
"is-builtin-module": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.0.0.tgz",
- "integrity": "sha512-/93sDihsAD652hrMEbJGbMAVBf1qc96kyThHQ0CAOONHaE3aROLpTjDe4WQ5aoC5ITHFxEq1z8XqSU7km+8amw==",
+ "version": "1.0.0",
+ "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
- "builtin-modules": "^3.0.0"
+ "builtin-modules": "^1.0.0"
}
},
"is-callable": {
@@ -3457,21 +3492,10 @@
"dev": true
},
"json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.0"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true
- }
- }
+ "version": "0.5.1",
+ "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "dev": true
},
"jsonify": {
"version": "0.0.0",
@@ -3523,14 +3547,14 @@
"dev": true
},
"loader-utils": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
- "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
"dev": true,
"requires": {
- "big.js": "^5.2.2",
+ "big.js": "^3.1.3",
"emojis-list": "^2.0.0",
- "json5": "^1.0.1"
+ "json5": "^0.5.0"
}
},
"locate-path": {
@@ -3617,18 +3641,18 @@
}
},
"matchit": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.0.7.tgz",
- "integrity": "sha512-6GQP+4ukhBEL4pQPQlipd51XnpOlycit/3o6p4XhhZt2+9hc7JlHr7NuWbTLQ2MdSzcxR603L7LF4T8x1e1mXA==",
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.0.6.tgz",
+ "integrity": "sha1-gl2gZGi9Mk8CGevijhKkG/tVJMQ=",
"dev": true,
"requires": {
"@arr/every": "^1.0.0"
}
},
"math-random": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
- "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
+ "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=",
"dev": true
},
"md5.js": {
@@ -3690,9 +3714,9 @@
}
},
"mime": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
- "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz",
+ "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==",
"dev": true
},
"mimic-fn": {
@@ -3724,7 +3748,7 @@
},
"minimist": {
"version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
@@ -3769,7 +3793,7 @@
},
"mkdirp": {
"version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
@@ -3797,7 +3821,7 @@
"dependencies": {
"commander": {
"version": "2.15.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
+ "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
"dev": true
},
@@ -3824,12 +3848,6 @@
"path-is-absolute": "^1.0.0"
}
},
- "he": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
- "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
- "dev": true
- },
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -3997,13 +4015,13 @@
}
},
"normalize-package-data": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
- "integrity": "sha512-ZVuHxWJv1bopjv/SD5uPhgwUhLqxdJ+SsdUQbGR9HWlXrvnd/C08Cn9Bq48PbvX3y5V97GIpAHpL5Bk9BwChGg==",
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
- "is-builtin-module": "^3.0.0",
+ "is-builtin-module": "^1.0.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
@@ -4532,9 +4550,9 @@
"dev": true
},
"puppeteer": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.11.0.tgz",
- "integrity": "sha512-iG4iMOHixc2EpzqRV+pv7o3GgmU2dNYEMkvKwSaQO/vMZURakwSOn/EYJ6OIRFYOque1qorzIBvrytPIQB3YzQ==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.12.0.tgz",
+ "integrity": "sha512-+riSxJFPQpwGZvNHFeB7vEefwfdHNSstQmjdzUKZxPp/Qt1Dw9iKRAewl8X0ntdXZz4UR4jODLiM03Iw9HDnyw==",
"dev": true,
"requires": {
"debug": "^4.1.0",
@@ -4560,9 +4578,9 @@
"dev": true
},
"randomatic": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
- "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz",
+ "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==",
"dev": true,
"requires": {
"is-number": "^4.0.0",
@@ -4996,12 +5014,12 @@
"dev": true
},
"resolve": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
- "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
"dev": true,
"requires": {
- "path-parse": "^1.0.6"
+ "path-parse": "^1.0.5"
}
},
"resolve-from": {
@@ -5060,6 +5078,14 @@
"@types/estree": "0.0.39",
"@types/node": "*",
"acorn": "^6.0.5"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "6.0.6",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz",
+ "integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA==",
+ "dev": true
+ }
}
},
"rollup-plugin-commonjs": {
@@ -5092,6 +5118,14 @@
"builtin-modules": "^3.0.0",
"is-module": "^1.0.0",
"resolve": "^1.8.1"
+ },
+ "dependencies": {
+ "builtin-modules": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.0.0.tgz",
+ "integrity": "sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg==",
+ "dev": true
+ }
}
},
"rollup-plugin-replace": {
@@ -5122,7 +5156,7 @@
},
"rollup-pluginutils": {
"version": "1.5.2",
- "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz",
+ "resolved": "http://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz",
"integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=",
"dev": true,
"requires": {
@@ -5141,6 +5175,14 @@
"require-relative": "^0.8.7",
"rollup-pluginutils": "^2.3.3",
"sourcemap-codec": "^1.4.4"
+ },
+ "dependencies": {
+ "sourcemap-codec": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz",
+ "integrity": "sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg==",
+ "dev": true
+ }
}
},
"rollup-plugin-typescript": {
@@ -5532,9 +5574,9 @@
"integrity": "sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg=="
},
"spdx-correct": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
- "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",
+ "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
@@ -5558,9 +5600,9 @@
}
},
"spdx-license-ids": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz",
- "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz",
+ "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==",
"dev": true
},
"split-string": {
@@ -5825,9 +5867,9 @@
}
},
"tiny-glob": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.6.tgz",
- "integrity": "sha512-A7ewMqPu1B5PWwC3m7KVgAu96Ch5LA0w4SnEN/LbDREj/gAD0nPWboRbn8YoP9ISZXqeNAlMvKSKoEuhcfK3Pw==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.2.tgz",
+ "integrity": "sha512-o8rak1FRmr55Nd1Bdcfd+yetPGclFCVHXiKmoBHYULc+FQXBbqb9S3zKAWyqk+RdWvutlGUOw0kCHC0JLF/T4Q==",
"dev": true,
"requires": {
"globalyzer": "^0.1.0",
@@ -5940,9 +5982,9 @@
"dev": true
},
"typescript": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz",
- "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.1.tgz",
+ "integrity": "sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA==",
"dev": true
},
"uglify-js": {
@@ -6570,6 +6612,12 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz",
"integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==",
"dev": true
+ },
+ "yootils": {
+ "version": "0.0.14",
+ "resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.14.tgz",
+ "integrity": "sha512-yWoA/a/4aVUp5nqfqdjbTdyXcR8d0OAbRQ8Ktu3ZsfQnArwLpS81oqZl3adIszX3p8NEhT0aNHARPsaTwBH/Qw==",
+ "dev": true
}
}
}
diff --git a/package.json b/package.json
index beb95b5..97c282b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sapper",
- "version": "0.25.0-alpha2",
+ "version": "0.26.0-alpha.1",
"description": "Military-grade apps, engineered by Svelte",
"bin": {
"sapper": "./sapper"
@@ -18,36 +18,36 @@
"test": "test"
},
"dependencies": {
- "html-minifier": "^3.5.20",
+ "html-minifier": "^3.5.21",
"shimport": "0.0.14",
- "source-map-support": "^0.5.9",
- "sourcemap-codec": "^1.4.3",
+ "source-map-support": "^0.5.10",
+ "sourcemap-codec": "^1.4.4",
"string-hash": "^1.1.3",
"tslib": "^1.9.3"
},
"devDependencies": {
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^5.2.5",
- "@types/node": "^10.12.0",
- "@types/puppeteer": "^1.9.0",
+ "@types/node": "^10.12.21",
+ "@types/puppeteer": "^1.11.3",
"@types/rimraf": "^2.0.2",
"agadoo": "^1.0.1",
- "cheap-watch": "^1.0.0",
+ "cheap-watch": "^1.0.2",
"cookie": "^0.3.1",
- "devalue": "^1.0.4",
- "eslint": "^5.7.0",
- "eslint-plugin-import": "^2.14.0",
+ "devalue": "^1.1.0",
+ "eslint": "^5.12.1",
+ "eslint-plugin-import": "^2.16.0",
"kleur": "^3.0.1",
"mkdirp": "^0.5.1",
"mocha": "^5.2.0",
- "node-fetch": "^2.2.0",
+ "node-fetch": "^2.3.0",
"npm-run-all": "^4.1.5",
"polka": "^0.5.1",
"port-authority": "^1.0.5",
"pretty-bytes": "^5.1.0",
- "puppeteer": "^1.9.0",
+ "puppeteer": "^1.12.0",
"require-relative": "^0.8.7",
- "rimraf": "^2.6.2",
+ "rimraf": "^2.6.3",
"rollup": "^1.1.2",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-json": "^3.1.0",
@@ -56,15 +56,16 @@
"rollup-plugin-string": "^2.0.2",
"rollup-plugin-svelte": "^5.0.1",
"rollup-plugin-typescript": "^1.0.0",
- "sade": "^1.4.1",
+ "sade": "^1.4.2",
"sander": "^0.6.0",
"sirv": "^0.2.2",
"svelte": "^3.0.0-alpha26",
- "svelte-loader": "^2.11.0",
+ "svelte-loader": "^2.12.0",
"ts-node": "^8.0.2",
- "typescript": "^3.1.3",
- "webpack": "^4.20.2",
- "webpack-format-messages": "^2.0.3"
+ "typescript": "^3.3.1",
+ "webpack": "^4.29.0",
+ "webpack-format-messages": "^2.0.5",
+ "yootils": "0.0.14"
},
"scripts": {
"test": "mocha --opts mocha.opts",
diff --git a/src/api/build.ts b/src/api/build.ts
index 2fbeff0..85f88ca 100644
--- a/src/api/build.ts
+++ b/src/api/build.ts
@@ -42,7 +42,6 @@ export async function build({
routes = path.resolve(cwd, routes);
output = path.resolve(cwd, output);
static_files = path.resolve(cwd, static_files);
- dest = path.resolve(cwd, dest);
if (legacy && bundler === 'webpack') {
throw new Error(`Legacy builds are not supported for projects using webpack`);
@@ -119,10 +118,15 @@ export async function build({
let serviceworker_stats;
if (serviceworker) {
+
+ const client_files = client_result.chunks
+ .filter(chunk => !chunk.file.endsWith('.map')) // SW does not need to cache sourcemap files
+ .map(chunk => `client/${chunk.file}`);
+
create_serviceworker_manifest({
manifest_data,
output,
- client_files: client_result.chunks.map(chunk => `client/${chunk.file}`),
+ client_files,
static_files
});
diff --git a/src/api/export.ts b/src/api/export.ts
index 482ba51..ed601e4 100644
--- a/src/api/export.ts
+++ b/src/api/export.ts
@@ -3,6 +3,7 @@ import * as path from 'path';
import * as sander from 'sander';
import * as url from 'url';
import fetch from 'node-fetch';
+import * as yootils from 'yootils';
import * as ports from 'port-authority';
import clean_html from './utils/clean_html';
import minify_html from './utils/minify_html';
@@ -94,7 +95,9 @@ async function _export({
const is_html = type === 'text/html';
if (is_html) {
- file = file === '' ? 'index.html' : `${file}/index.html`;
+ if (pathname !== '/service-worker-index.html') {
+ file = file === '' ? 'index.html' : `${file}/index.html`;
+ }
body = minify_html(body);
}
@@ -113,7 +116,10 @@ async function _export({
});
async function handle(url: URL) {
- const pathname = (url.pathname.replace(root.pathname, '') || '/');
+ let pathname = url.pathname;
+ if (pathname !== '/service-worker-index.html') {
+ pathname = pathname.replace(root.pathname, '') || '/'
+ }
if (seen.has(pathname)) return;
seen.add(pathname);
@@ -138,11 +144,12 @@ async function _export({
const range = ~~(r.status / 100);
if (range === 2) {
- if (type === 'text/html') {
- const urls: URL[] = [];
-
+ if (type === 'text/html' && pathname !== '/service-worker-index.html') {
const cleaned = clean_html(body);
+ const q = yootils.queue(8);
+ let promise;
+
const base_match = //m.exec(cleaned);
const base_href = base_match && get_href(base_match[1]);
const base = resolve(url.href, base_href);
@@ -158,12 +165,12 @@ async function _export({
const url = resolve(base.href, href);
if (url.protocol === protocol && url.host === host) {
- urls.push(url);
+ promise = q.add(() => handle(url));
}
}
}
- await Promise.all(urls.map(handle));
+ await promise;
}
}
@@ -181,6 +188,7 @@ async function _export({
return ports.wait(port)
.then(() => handle(root))
+ .then(() => handle(resolve(root.href, 'service-worker-index.html')))
.then(() => proc.kill())
.catch(err => {
proc.kill();
diff --git a/src/core/create_manifests.ts b/src/core/create_manifests.ts
index abb752f..2f28f17 100644
--- a/src/core/create_manifests.ts
+++ b/src/core/create_manifests.ts
@@ -48,17 +48,15 @@ export function create_serviceworker_manifest({ manifest_data, output, client_fi
client_files: string[];
static_files: string;
}) {
- let files: string[];
+ let files: string[] = ['/service-worker-index.html'];
if (fs.existsSync(static_files)) {
- files = walk(static_files);
+ files = files.concat(walk(static_files));
} else {
// TODO remove in a future version
if (fs.existsSync('assets')) {
throw new Error(`As of Sapper 0.21, the assets/ directory should become static/`);
}
-
- files = [];
}
let code = `
diff --git a/templates/src/app/app.ts b/templates/src/app/app.ts
index 2c02d6d..d6c8e0a 100644
--- a/templates/src/app/app.ts
+++ b/templates/src/app/app.ts
@@ -38,7 +38,7 @@ const root_props: RootProps = {
export let prefetching: {
href: string;
- promise: Promise<{ redirect?: Redirect, data?: any, nullable_depth?: number }>;
+ promise: Promise<{ redirect?: Redirect, data?: any, nullable_depth?: number, new_segments?: any }>;
} = null;
export function set_prefetching(href, promise) {
prefetching = { href, promise };
@@ -141,10 +141,13 @@ export function navigate(target: Target, id: number, noscroll?: boolean, hash?:
const token = current_token = {};
- return loaded.then(({ redirect, data, nullable_depth }) => {
+ return loaded.then(({ redirect, data, nullable_depth, new_segments }) => {
if (redirect) {
return goto(redirect.location, { replaceState: true });
}
+ if (new_segments) {
+ segments = new_segments;
+ }
render(data, nullable_depth, scroll_history[id], noscroll, hash, token);
if (document.activeElement) document.activeElement.blur();
});
@@ -231,6 +234,10 @@ export function prepare_page(target: Target): Promise<{
segments[changed_from] === new_segments[changed_from]
) changed_from += 1;
+ if (changed_from === new_segments.length) {
+ changed_from -= 1;
+ }
+
let redirect: Redirect = null;
let error: { statusCode: number, message: Error | string } = null;
@@ -297,11 +304,9 @@ export function prepare_page(target: Target): Promise<{
}
}).then(results => {
if (redirect) {
- return { redirect };
+ return { redirect, new_segments };
}
- segments = new_segments;
-
const get_params = page.parts[page.parts.length - 1].params || (() => ({}));
const params = get_params(target.match);
@@ -316,6 +321,7 @@ export function prepare_page(target: Target): Promise<{
return {
nullable_depth: 0,
+ new_segments,
data: Object.assign({}, props, {
child: {
component: ErrorComponent,
@@ -329,7 +335,7 @@ export function prepare_page(target: Target): Promise<{
const data = {
path,
child: Object.assign({}, root_props.child, {
- segment: segments[0]
+ segment: new_segments[0]
})
};
if (changed(query, root_props.query)) data.query = query;
@@ -360,10 +366,10 @@ export function prepare_page(target: Target): Promise<{
}
level = level.props.child;
- level.segment = segments[i + 1];
+ level.segment = new_segments[i + 1];
}
- return { data, nullable_depth };
+ return { data, nullable_depth, new_segments };
});
}
@@ -400,4 +406,4 @@ function detach(node: Node) {
function changed(a: Record, b: Record) {
return JSON.stringify(a) !== JSON.stringify(b);
-}
\ No newline at end of file
+}
diff --git a/templates/src/server/middleware/get_page_handler.ts b/templates/src/server/middleware/get_page_handler.ts
index aa7b5e3..a2ccc19 100644
--- a/templates/src/server/middleware/get_page_handler.ts
+++ b/templates/src/server/middleware/get_page_handler.ts
@@ -1,9 +1,9 @@
-import * as fs from 'fs';
-import * as path from 'path';
+import fs from 'fs';
+import path from 'path';
import cookie from 'cookie';
import devalue from 'devalue';
import fetch from 'node-fetch';
-import { URL, resolve } from 'url';
+import URL from 'url';
import * as stores from '../../shared/stores';
import { build_dir, dev, src_dir, IGNORE } from '../placeholders';
import { Manifest, Page, Props, Req, Res } from './types';
@@ -36,6 +36,7 @@ export function get_page_handler(
}
async function handle_page(page: Page, req: Req, res: Res, status = 200, error: Error | string = null) {
+ const isSWIndexHtml = req.path === '/service-worker-index.html';
const build_info: {
bundler: 'rollup' | 'webpack',
shimport: string | null,
@@ -49,7 +50,7 @@ export function get_page_handler(
// preload main.js and current route
// TODO detect other stuff we can preload? images, CSS, fonts?
let preloaded_chunks = Array.isArray(build_info.assets.main) ? build_info.assets.main : [build_info.assets.main];
- if (!error) {
+ if (!error && !isSWIndexHtml) {
page.parts.forEach(part => {
if (!part) return;
@@ -95,7 +96,7 @@ export function get_page_handler(
preload_error = { statusCode, message };
},
fetch: (url: string, opts?: any) => {
- const parsed = new URL(url, `http://127.0.0.1:${process.env.PORT}${req.baseUrl ? req.baseUrl + '/' :''}`);
+ const parsed = new URL.URL(url, `http://127.0.0.1:${process.env.PORT}${req.baseUrl ? req.baseUrl + '/' :''}`);
if (opts) {
opts = Object.assign({}, opts);
@@ -106,7 +107,7 @@ export function get_page_handler(
);
if (include_cookies) {
- if (!opts.headers) opts.headers = {};
+ opts.headers = Object.assign({}, opts.headers);
const cookies = Object.assign(
{},
@@ -146,17 +147,22 @@ export function get_page_handler(
match = error ? null : page.pattern.exec(req.path);
- preloaded = await Promise.all([root_preloaded].concat(page.parts.map(part => {
- if (!part) return null;
+ let toPreload = [root_preloaded];
+ if (!isSWIndexHtml) {
+ toPreload = toPreload.concat(page.parts.map(part => {
+ if (!part) return null;
- return part.preload
- ? part.preload.call(preload_context, {
- path: req.path,
- query: req.query,
- params: part.params ? part.params(match) : {}
- })
- : {};
- })));
+ return part.preload
+ ? part.preload.call(preload_context, {
+ path: req.path,
+ query: req.query,
+ params: part.params ? part.params(match) : {}
+ })
+ : {};
+ }))
+ }
+
+ preloaded = await Promise.all(toPreload);
} catch (err) {
preload_error = { statusCode: 500, message: err };
preloaded = []; // appease TypeScript
@@ -164,7 +170,7 @@ export function get_page_handler(
try {
if (redirect) {
- const location = resolve(req.baseUrl || '/', redirect.location);
+ const location = URL.resolve(req.baseUrl || '/', redirect.location);
res.statusCode = redirect.statusCode;
res.setHeader('Location', location);
@@ -200,23 +206,29 @@ export function get_page_handler(
});
let level = data.child;
- for (let i = 0; i < page.parts.length; i += 1) {
- const part = page.parts[i];
- if (!part) continue;
+ if (isSWIndexHtml) {
+ level.props = Object.assign({}, props, {
+ params: {}
+ })
+ } else {
+ for (let i = 0; i < page.parts.length; i += 1) {
+ const part = page.parts[i];
+ if (!part) continue;
- const get_params = part.params || (() => ({}));
+ const get_params = part.params || (() => ({}));
- Object.assign(level, {
- component: part.component,
- props: Object.assign({}, props, {
- params: get_params(match)
- }, preloaded[i + 1])
- });
+ Object.assign(level, {
+ component: part.component,
+ props: Object.assign({}, props, {
+ params: get_params(match)
+ }, preloaded[i + 1])
+ });
- level.props.child = {
- segment: segments[i + 1]
- };
- level = level.props.child;
+ level.props.child = {
+ segment: segments[i + 1]
+ };
+ level = level.props.child;
+ }
}
stores.page.set({
@@ -314,6 +326,12 @@ export function get_page_handler(
return function find_route(req: Req, res: Res, next: () => void) {
if (req[IGNORE]) return next();
+ if (req.path === '/service-worker-index.html') {
+ const homePage = pages.find(page => page.pattern.test('/'));
+ handle_page(homePage, req, res);
+ return;
+ }
+
if (!server_routes.some(route => route.pattern.test(req.path))) {
for (const page of pages) {
if (page.pattern.test(req.path)) {
diff --git a/templates/src/server/middleware/index.ts b/templates/src/server/middleware/index.ts
index ae6dcb7..f2e3a88 100644
--- a/templates/src/server/middleware/index.ts
+++ b/templates/src/server/middleware/index.ts
@@ -1,5 +1,5 @@
-import * as fs from 'fs';
-import * as path from 'path';
+import fs from 'fs';
+import path from 'path';
import { build_dir, dev, manifest, IGNORE } from '../placeholders';
import { Handler, Req, Res, Store } from './types';
import { get_server_route_handler } from './get_server_route_handler';
diff --git a/test/apps/AppRunner.ts b/test/apps/AppRunner.ts
index 84dd6b6..4bfdcce 100644
--- a/test/apps/AppRunner.ts
+++ b/test/apps/AppRunner.ts
@@ -64,11 +64,11 @@ export class AppRunner {
base: `http://localhost:${this.port}`,
// helpers
- start: () => this.page.evaluate(() => start()),
- prefetchRoutes: () => this.page.evaluate(() => prefetchRoutes()),
- prefetch: (href: string) => this.page.evaluate((href: string) => prefetch(href), href),
- goto: (href: string) => this.page.evaluate((href: string) => goto(href), href),
- title: () => this.page.$eval('h1', node => node.textContent)
+ start: () => this.page.evaluate(() => start()).then(() => void 0),
+ prefetchRoutes: () => this.page.evaluate(() => prefetchRoutes()).then(() => void 0),
+ prefetch: (href: string) => this.page.evaluate((href: string) => prefetch(href), href).then(() => void 0),
+ goto: (href: string) => this.page.evaluate((href: string) => goto(href), href).then(() => void 0),
+ title: () => this.page.$eval('h1', node => node.textContent).then(serializable => String(serializable))
};
}
diff --git a/test/apps/basics/test.ts b/test/apps/basics/test.ts
index c27b519..c2d28d3 100644
--- a/test/apps/basics/test.ts
+++ b/test/apps/basics/test.ts
@@ -261,7 +261,7 @@ describe('basics', function() {
await page.goto(`${base}/unsafe-replacement`);
await start();
- const html = await page.evaluate(() => document.body.innerHTML);
+ const html = String(await page.evaluate(() => document.body.innerHTML));
assert.equal(html.indexOf('%sapper'), -1);
});
});
\ No newline at end of file
diff --git a/test/apps/export/test.ts b/test/apps/export/test.ts
index 9bb8339..897bc5f 100644
--- a/test/apps/export/test.ts
+++ b/test/apps/export/test.ts
@@ -30,6 +30,7 @@ describe('export', function() {
'blog/index.html',
'global.css',
'index.html',
+ 'service-worker-index.html',
'service-worker.js'
]);
});
diff --git a/test/apps/layout/test.ts b/test/apps/layout/test.ts
index 1cadbe1..36eda4e 100644
--- a/test/apps/layout/test.ts
+++ b/test/apps/layout/test.ts
@@ -28,7 +28,7 @@ describe('layout', function() {
await page.goto(`${base}/foo/bar/baz`);
await start();
- const text1 = await page.evaluate(() => document.querySelector('#sapper').textContent);
+ const text1 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
assert.deepEqual(text1.split('\n').filter(Boolean), [
'y: bar 1',
'z: baz 1',
@@ -39,7 +39,7 @@ describe('layout', function() {
await page.click('[href="foo/bar/qux"]');
await wait(50);
- const text2 = await page.evaluate(() => document.querySelector('#sapper').textContent);
+ const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
assert.deepEqual(text2.split('\n').filter(Boolean), [
'y: bar 1',
'z: qux 2',
diff --git a/test/apps/preloading/src/routes/index.html b/test/apps/preloading/src/routes/index.html
index e269e81..c214f0c 100644
--- a/test/apps/preloading/src/routes/index.html
+++ b/test/apps/preloading/src/routes/index.html
@@ -1,4 +1,6 @@
Great success!
slow preload
-foo
\ No newline at end of file
+foo
+prefetch qwe
+prefetch xyz
diff --git a/test/apps/preloading/src/routes/prefetch/[slug]/index.html b/test/apps/preloading/src/routes/prefetch/[slug]/index.html
new file mode 100644
index 0000000..d13188c
--- /dev/null
+++ b/test/apps/preloading/src/routes/prefetch/[slug]/index.html
@@ -0,0 +1 @@
+{params.slug}
diff --git a/test/apps/preloading/src/routes/prefetch/_layout.html b/test/apps/preloading/src/routes/prefetch/_layout.html
new file mode 100644
index 0000000..f11eb2a
--- /dev/null
+++ b/test/apps/preloading/src/routes/prefetch/_layout.html
@@ -0,0 +1 @@
+
diff --git a/test/apps/preloading/src/routes/prefetch/index.html b/test/apps/preloading/src/routes/prefetch/index.html
new file mode 100644
index 0000000..7771d91
--- /dev/null
+++ b/test/apps/preloading/src/routes/prefetch/index.html
@@ -0,0 +1 @@
+prefetch
diff --git a/test/apps/preloading/test.ts b/test/apps/preloading/test.ts
index 8445c86..d30a8d1 100644
--- a/test/apps/preloading/test.ts
+++ b/test/apps/preloading/test.ts
@@ -81,4 +81,31 @@ describe('preloading', function() {
assert.equal(page.url(), `${base}/foo`);
assert.equal(await title(), 'foo');
});
-});
\ No newline at end of file
+
+ it('navigates to prefetched urls', async () => {
+ await page.goto(base);
+ await start();
+ await prefetchRoutes();
+
+ await page.hover('a[href="prefetch/qwe"]');
+ await wait(100);
+ await page.hover('a[href="prefetch/xyz"]');
+ await wait(100);
+
+ await page.click('a[href="prefetch/qwe"]');
+ await wait(50);
+
+ assert.equal(
+ await title(),
+ 'qwe'
+ );
+
+ await page.goto(`${base}/prefetch`);
+ await wait(50);
+
+ assert.equal(
+ await title(),
+ 'prefetch'
+ );
+ });
+});
diff --git a/test/apps/scroll/test.ts b/test/apps/scroll/test.ts
index 6bae656..11130ff 100644
--- a/test/apps/scroll/test.ts
+++ b/test/apps/scroll/test.ts
@@ -31,7 +31,7 @@ describe('scroll', function() {
await start();
const scrollY = await page.evaluate(() => window.scrollY);
- assert.ok(scrollY > 0, scrollY);
+ assert.ok(scrollY > 0, String(scrollY));
});
it('scrolls to any deeplink if it was already active', async () => {
@@ -39,17 +39,17 @@ describe('scroll', function() {
await start();
let scrollY = await page.evaluate(() => window.scrollY);
- assert.ok(scrollY > 0, scrollY);
+ assert.ok(scrollY > 0, String(scrollY));
scrollY = await page.evaluate(() => {
window.scrollTo(0, 0)
return window.scrollY
});
- assert.ok(scrollY === 0, scrollY);
+ assert.ok(scrollY === 0, String(scrollY));
await page.click('[href="tall-page#foo"]');
scrollY = await page.evaluate(() => window.scrollY);
- assert.ok(scrollY > 0, scrollY);
+ assert.ok(scrollY > 0, String(scrollY));
});
it('resets scroll when a link is clicked', async () => {
diff --git a/test/apps/with-basepath/test.ts b/test/apps/with-basepath/test.ts
index 93bbcbf..5741d1b 100644
--- a/test/apps/with-basepath/test.ts
+++ b/test/apps/with-basepath/test.ts
@@ -56,6 +56,7 @@ describe('with-basepath', function() {
assert.deepEqual(non_client_assets, [
'custom-basepath/global.css',
'custom-basepath/index.html',
+ 'custom-basepath/service-worker-index.html',
'custom-basepath/service-worker.js'
]);
});
diff --git a/test/apps/with-sourcemaps-webpack/src/client.js b/test/apps/with-sourcemaps-webpack/src/client.js
new file mode 100644
index 0000000..6cce7e6
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/client.js
@@ -0,0 +1,9 @@
+import * as sapper from '@sapper/app';
+
+window.start = () => sapper.start({
+ target: document.querySelector('#sapper')
+});
+
+window.prefetchRoutes = () => sapper.prefetchRoutes();
+window.prefetch = href => sapper.prefetch(href);
+window.goto = href => sapper.goto(href);
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps-webpack/src/routes/_error.html b/test/apps/with-sourcemaps-webpack/src/routes/_error.html
new file mode 100644
index 0000000..4cd55d2
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/routes/_error.html
@@ -0,0 +1,3 @@
+{status}
+
+{error.message}
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps-webpack/src/routes/index.html b/test/apps/with-sourcemaps-webpack/src/routes/index.html
new file mode 100644
index 0000000..abaff72
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/routes/index.html
@@ -0,0 +1,3 @@
+Great success!
+
+Woot!
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps-webpack/src/server.js b/test/apps/with-sourcemaps-webpack/src/server.js
new file mode 100644
index 0000000..7f090b8
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/server.js
@@ -0,0 +1,8 @@
+import polka from 'polka';
+import * as sapper from '@sapper/server';
+
+const { PORT } = process.env;
+
+polka()
+ .use(sapper.middleware())
+ .listen(PORT);
diff --git a/test/apps/with-sourcemaps-webpack/src/service-worker.js b/test/apps/with-sourcemaps-webpack/src/service-worker.js
new file mode 100644
index 0000000..67da6f0
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/service-worker.js
@@ -0,0 +1,82 @@
+import { timestamp, files, shell, routes } from '@sapper/service-worker';
+
+const ASSETS = `cache${timestamp}`;
+
+// `shell` is an array of all the files generated by webpack,
+// `files` is an array of everything in the `static` directory
+const to_cache = shell.concat(ASSETS);
+const cached = new Set(to_cache);
+
+self.addEventListener('install', event => {
+ event.waitUntil(
+ caches
+ .open(ASSETS)
+ .then(cache => cache.addAll(to_cache))
+ .then(() => {
+ self.skipWaiting();
+ })
+ );
+});
+
+self.addEventListener('activate', event => {
+ event.waitUntil(
+ caches.keys().then(async keys => {
+ // delete old caches
+ for (const key of keys) {
+ if (key !== ASSETS) await caches.delete(key);
+ }
+
+ self.clients.claim();
+ })
+ );
+});
+
+self.addEventListener('fetch', event => {
+ if (event.request.method !== 'GET') return;
+
+ const url = new URL(event.request.url);
+
+ // don't try to handle e.g. data: URIs
+ if (!url.protocol.startsWith('http')) return;
+
+ // ignore dev server requests
+ if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
+
+ // always serve assets and webpack-generated files from cache
+ if (url.host === self.location.host && cached.has(url.pathname)) {
+ event.respondWith(caches.match(event.request));
+ return;
+ }
+
+ // for pages, you might want to serve a shell `index.html` file,
+ // which Sapper has generated for you. It's not right for every
+ // app, but if it's right for yours then uncomment this section
+ /*
+ if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
+ event.respondWith(caches.match('/index.html'));
+ return;
+ }
+ */
+
+ if (event.request.cache === 'only-if-cached') return;
+
+ // for everything else, try the network first, falling back to
+ // cache if the user is offline. (If the pages never change, you
+ // might prefer a cache-first approach to a network-first one.)
+ event.respondWith(
+ caches
+ .open(`offline${timestamp}`)
+ .then(async cache => {
+ try {
+ const response = await fetch(event.request);
+ cache.put(event.request, response.clone());
+ return response;
+ } catch(err) {
+ const response = await cache.match(event.request);
+ if (response) return response;
+
+ throw err;
+ }
+ })
+ );
+});
diff --git a/test/apps/with-sourcemaps-webpack/src/template.html b/test/apps/with-sourcemaps-webpack/src/template.html
new file mode 100644
index 0000000..0eb1f3b
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/src/template.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ %sapper.base%
+ %sapper.styles%
+ %sapper.head%
+
+
+ %sapper.html%
+ %sapper.scripts%
+
+
diff --git a/test/apps/with-sourcemaps-webpack/test.ts b/test/apps/with-sourcemaps-webpack/test.ts
new file mode 100644
index 0000000..cb0a3ca
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/test.ts
@@ -0,0 +1,43 @@
+import * as puppeteer from 'puppeteer';
+import { build } from '../../../api';
+import * as assert from "assert";
+import { AppRunner } from '../AppRunner';
+import * as fs from "fs";
+import * as path from "path";
+
+describe('with-sourcemaps-webpack', function() {
+ this.timeout(10000);
+
+ let runner: AppRunner;
+ let page: puppeteer.Page;
+ let base: string;
+
+ // helpers
+ let start: () => Promise;
+ let prefetchRoutes: () => Promise;
+ let prefetch: (href: string) => Promise;
+ let goto: (href: string) => Promise;
+
+ // hooks
+ before(async () => {
+ await build({ cwd: __dirname, bundler: 'webpack' });
+
+ runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
+ ({ base, page, start, prefetchRoutes, prefetch, goto } = await runner.start());
+ });
+
+ it('does not put sourcemap files in service worker shell', async () => {
+ const serviceWorker = await import(`${__dirname}/__sapper__/service-worker.js`);
+ const shell: string[] = serviceWorker.shell;
+
+ assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
+ 'sourcemap files are not cached in SW');
+
+ const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
+ const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
+ assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
+ });
+
+ after(() => runner.end());
+
+});
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps-webpack/webpack.config.js b/test/apps/with-sourcemaps-webpack/webpack.config.js
new file mode 100644
index 0000000..eca656b
--- /dev/null
+++ b/test/apps/with-sourcemaps-webpack/webpack.config.js
@@ -0,0 +1,73 @@
+const webpack = require('webpack');
+const config = require('../../../config/webpack.js');
+
+const mode = process.env.NODE_ENV;
+const dev = mode === 'development';
+
+module.exports = {
+ client: {
+ entry: config.client.entry(),
+ output: config.client.output(),
+ resolve: {
+ extensions: ['.mjs', '.js', '.json', '.html'],
+ mainFields: ['svelte', 'module', 'browser', 'main']
+ },
+ module: {
+ rules: [
+ {
+ test: /\.html$/,
+ use: {
+ loader: 'svelte-loader',
+ options: {
+ dev,
+ hydratable: true,
+ hotReload: true
+ }
+ }
+ }
+ ]
+ },
+ mode,
+ plugins: [
+ dev && new webpack.HotModuleReplacementPlugin(),
+ new webpack.DefinePlugin({
+ 'process.browser': true,
+ 'process.env.NODE_ENV': JSON.stringify(mode)
+ }),
+ ].filter(Boolean),
+ devtool: dev ? 'inline-source-map' : 'source-map'
+ },
+
+ server: {
+ entry: config.server.entry(),
+ output: config.server.output(),
+ target: 'node',
+ resolve: {
+ extensions: ['.mjs', '.js', '.json', '.html'],
+ mainFields: ['svelte', 'module', 'browser', 'main']
+ },
+ module: {
+ rules: [
+ {
+ test: /\.html$/,
+ use: {
+ loader: 'svelte-loader',
+ options: {
+ css: false,
+ generate: 'ssr',
+ dev
+ }
+ }
+ }
+ ]
+ },
+ mode: process.env.NODE_ENV
+ },
+
+ serviceworker: {
+ entry: config.serviceworker.entry(),
+ output: config.serviceworker.output(),
+ mode: process.env.NODE_ENV,
+ devtool: 'sourcemap'
+ }
+};
diff --git a/test/apps/with-sourcemaps/rollup.config.js b/test/apps/with-sourcemaps/rollup.config.js
new file mode 100644
index 0000000..c057e2e
--- /dev/null
+++ b/test/apps/with-sourcemaps/rollup.config.js
@@ -0,0 +1,64 @@
+import resolve from 'rollup-plugin-node-resolve';
+import replace from 'rollup-plugin-replace';
+import svelte from 'rollup-plugin-svelte';
+
+const mode = process.env.NODE_ENV;
+const dev = mode === 'development';
+
+const config = require('../../../config/rollup.js');
+
+export default {
+ client: {
+ input: config.client.input(),
+ output: Object.assign({}, config.client.output(), { sourcemap: true }),
+ plugins: [
+ replace({
+ 'process.browser': true,
+ 'process.env.NODE_ENV': JSON.stringify(mode)
+ }),
+ svelte({
+ dev,
+ hydratable: true,
+ emitCss: true
+ }),
+ resolve()
+ ],
+
+ // temporary, pending Rollup 1.0
+ experimentalCodeSplitting: true
+ },
+
+ server: {
+ input: config.server.input(),
+ output: config.server.output(),
+ plugins: [
+ replace({
+ 'process.browser': false,
+ 'process.env.NODE_ENV': JSON.stringify(mode)
+ }),
+ svelte({
+ generate: 'ssr',
+ dev
+ }),
+ resolve({
+ preferBuiltins: true
+ })
+ ],
+ external: ['sirv', 'polka'],
+
+ // temporary, pending Rollup 1.0
+ experimentalCodeSplitting: true
+ },
+
+ serviceworker: {
+ input: config.serviceworker.input(),
+ output: config.serviceworker.output(),
+ plugins: [
+ resolve(),
+ replace({
+ 'process.browser': true,
+ 'process.env.NODE_ENV': JSON.stringify(mode)
+ })
+ ]
+ }
+};
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps/src/client.js b/test/apps/with-sourcemaps/src/client.js
new file mode 100644
index 0000000..0865a4a
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/client.js
@@ -0,0 +1,9 @@
+import * as sapper from '../__sapper__/client.js';
+
+window.start = () => sapper.start({
+ target: document.querySelector('#sapper')
+});
+
+window.prefetchRoutes = () => sapper.prefetchRoutes();
+window.prefetch = href => sapper.prefetch(href);
+window.goto = href => sapper.goto(href);
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps/src/routes/_error.html b/test/apps/with-sourcemaps/src/routes/_error.html
new file mode 100644
index 0000000..4cd55d2
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/routes/_error.html
@@ -0,0 +1,3 @@
+{status}
+
+{error.message}
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps/src/routes/index.html b/test/apps/with-sourcemaps/src/routes/index.html
new file mode 100644
index 0000000..abaff72
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/routes/index.html
@@ -0,0 +1,3 @@
+Great success!
+
+Woot!
\ No newline at end of file
diff --git a/test/apps/with-sourcemaps/src/server.js b/test/apps/with-sourcemaps/src/server.js
new file mode 100644
index 0000000..0e7741c
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/server.js
@@ -0,0 +1,8 @@
+import polka from 'polka';
+import * as sapper from '../__sapper__/server.js';
+
+const { PORT } = process.env;
+
+polka()
+ .use(sapper.middleware())
+ .listen(PORT);
diff --git a/test/apps/with-sourcemaps/src/service-worker.js b/test/apps/with-sourcemaps/src/service-worker.js
new file mode 100644
index 0000000..9d2ac9d
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/service-worker.js
@@ -0,0 +1,82 @@
+import { timestamp, files, shell, routes } from '../__sapper__/service-worker.js';
+
+const ASSETS = `cache${timestamp}`;
+
+// `shell` is an array of all the files generated by webpack,
+// `files` is an array of everything in the `static` directory
+const to_cache = shell.concat(ASSETS);
+const cached = new Set(to_cache);
+
+self.addEventListener('install', event => {
+ event.waitUntil(
+ caches
+ .open(ASSETS)
+ .then(cache => cache.addAll(to_cache))
+ .then(() => {
+ self.skipWaiting();
+ })
+ );
+});
+
+self.addEventListener('activate', event => {
+ event.waitUntil(
+ caches.keys().then(async keys => {
+ // delete old caches
+ for (const key of keys) {
+ if (key !== ASSETS) await caches.delete(key);
+ }
+
+ self.clients.claim();
+ })
+ );
+});
+
+self.addEventListener('fetch', event => {
+ if (event.request.method !== 'GET') return;
+
+ const url = new URL(event.request.url);
+
+ // don't try to handle e.g. data: URIs
+ if (!url.protocol.startsWith('http')) return;
+
+ // ignore dev server requests
+ if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
+
+ // always serve assets and webpack-generated files from cache
+ if (url.host === self.location.host && cached.has(url.pathname)) {
+ event.respondWith(caches.match(event.request));
+ return;
+ }
+
+ // for pages, you might want to serve a shell `index.html` file,
+ // which Sapper has generated for you. It's not right for every
+ // app, but if it's right for yours then uncomment this section
+ /*
+ if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
+ event.respondWith(caches.match('/index.html'));
+ return;
+ }
+ */
+
+ if (event.request.cache === 'only-if-cached') return;
+
+ // for everything else, try the network first, falling back to
+ // cache if the user is offline. (If the pages never change, you
+ // might prefer a cache-first approach to a network-first one.)
+ event.respondWith(
+ caches
+ .open(`offline${timestamp}`)
+ .then(async cache => {
+ try {
+ const response = await fetch(event.request);
+ cache.put(event.request, response.clone());
+ return response;
+ } catch(err) {
+ const response = await cache.match(event.request);
+ if (response) return response;
+
+ throw err;
+ }
+ })
+ );
+});
diff --git a/test/apps/with-sourcemaps/src/template.html b/test/apps/with-sourcemaps/src/template.html
new file mode 100644
index 0000000..0eb1f3b
--- /dev/null
+++ b/test/apps/with-sourcemaps/src/template.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ %sapper.base%
+ %sapper.styles%
+ %sapper.head%
+
+
+ %sapper.html%
+ %sapper.scripts%
+
+
diff --git a/test/apps/with-sourcemaps/test.ts b/test/apps/with-sourcemaps/test.ts
new file mode 100644
index 0000000..1b61c28
--- /dev/null
+++ b/test/apps/with-sourcemaps/test.ts
@@ -0,0 +1,43 @@
+import * as puppeteer from 'puppeteer';
+import { build } from '../../../api';
+import * as assert from "assert";
+import { AppRunner } from '../AppRunner';
+import * as fs from 'fs';
+import * as path from "path";
+
+describe('with-sourcemaps', function() {
+ this.timeout(10000);
+
+ let runner: AppRunner;
+ let page: puppeteer.Page;
+ let base: string;
+
+ // helpers
+ let start: () => Promise;
+ let prefetchRoutes: () => Promise;
+ let prefetch: (href: string) => Promise;
+ let goto: (href: string) => Promise;
+
+ // hooks
+ before(async () => {
+ await build({ cwd: __dirname });
+
+ runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
+ ({ base, page, start, prefetchRoutes, prefetch, goto } = await runner.start());
+ });
+
+ it('does not put sourcemap files in service worker shell', async () => {
+ const serviceWorker = await import(`${__dirname}/__sapper__/service-worker.js`);
+ const shell: string[] = serviceWorker.shell;
+
+ assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
+ 'sourcemap files are not cached in SW');
+
+ const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
+ const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
+ assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
+ });
+
+ after(() => runner.end());
+
+});
\ No newline at end of file