mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-14 12:04:39 +00:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6390ba692b | ||
|
|
0e131cc81e | ||
|
|
bd3d5713cb | ||
|
|
9ec23c47ad | ||
|
|
b7bb69925e | ||
|
|
25124f6ee7 | ||
|
|
73d491cd19 | ||
|
|
e25fceb4b8 | ||
|
|
3807147c57 | ||
|
|
a523ba58ff | ||
|
|
fe03fd3a52 | ||
|
|
89c430a0cb | ||
|
|
8ef312849c | ||
|
|
4200446684 | ||
|
|
681ed005b8 | ||
|
|
d457af8d51 | ||
|
|
0c158b9e1f | ||
|
|
50011e2077 | ||
|
|
f27b7973e3 | ||
|
|
2af2ab3cb9 | ||
|
|
6a4dc1901c | ||
|
|
fbbc0e9e19 | ||
|
|
1213c3da46 | ||
|
|
4cc2104088 | ||
|
|
d6dda371ca | ||
|
|
304c06085e | ||
|
|
33b6450e34 | ||
|
|
8faa98af6a | ||
|
|
14df138528 | ||
|
|
44285cdb2f | ||
|
|
bd656cfd5b | ||
|
|
c4b4bd587d | ||
|
|
2abfdb03d5 | ||
|
|
a80ac3a8b8 | ||
|
|
887cb09386 | ||
|
|
cfeeafded4 | ||
|
|
2cae674033 | ||
|
|
7c0f32662d | ||
|
|
b4fb1c3268 | ||
|
|
ecd0f673a9 | ||
|
|
40d16852f7 | ||
|
|
133be03791 | ||
|
|
727a76ebb5 | ||
|
|
e3c047831a | ||
|
|
81b5e0d764 | ||
|
|
98e904dcfc | ||
|
|
ca51372150 | ||
|
|
7cef1f1120 | ||
|
|
1b73baabce | ||
|
|
5aa01b922b | ||
|
|
f0bc68be88 | ||
|
|
be7c53becc | ||
|
|
9ea4137b87 | ||
|
|
7588911108 | ||
|
|
fc8280adea | ||
|
|
d08f9eb5a4 | ||
|
|
2b3472b1b1 | ||
|
|
30ddb3dd7e | ||
|
|
0c891ba79e | ||
|
|
ee94f355d5 | ||
|
|
bea9b7965a | ||
|
|
1312aede1f | ||
|
|
50e307e0c0 | ||
|
|
e87ac1f367 | ||
|
|
5da9d0926a | ||
|
|
9538499d51 | ||
|
|
ff1e632057 | ||
|
|
aeeb231477 | ||
|
|
d1940db8c0 | ||
|
|
98f9a64b64 | ||
|
|
b9bef802d3 | ||
|
|
a7024b3806 | ||
|
|
423e02aeae | ||
|
|
12b73ecebf | ||
|
|
e1bc38b5a7 | ||
|
|
b66f624f01 | ||
|
|
502dd547d1 | ||
|
|
4c343490d2 | ||
|
|
b3027c5816 | ||
|
|
c29e8022cc | ||
|
|
e4cd4c9cb0 | ||
|
|
feddad42b2 | ||
|
|
3c4ebcda30 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
cypress/screenshots
|
cypress/screenshots
|
||||||
test/app/.sapper
|
test/app/.sapper
|
||||||
|
runtime.js
|
||||||
|
yarn.lock
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ sudo: false
|
|||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
|
- "6"
|
||||||
- "stable"
|
- "stable"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
|||||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,5 +1,34 @@
|
|||||||
# sapper changelog
|
# sapper changelog
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
* Experimental support for `sapper export` ([#9](https://github.com/sveltejs/sapper/issues/9))
|
||||||
|
* Lazily load chokidar, for faster startup ([#64](https://github.com/sveltejs/sapper/pull/64))
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
* `%sapper.main%` has been replaced with `%sapper.scripts%` ([#86](https://github.com/sveltejs/sapper/issues/86))
|
||||||
|
* Node 6 support ([#67](https://github.com/sveltejs/sapper/pull/67))
|
||||||
|
* Explicitly load css-loader and style-loader ([#72](https://github.com/sveltejs/sapper/pull/72))
|
||||||
|
* DELETE requests are handled with `del` exports ([#77](https://github.com/sveltejs/sapper/issues/77))
|
||||||
|
* Send preloaded data for first route to client, where possible ([#3](https://github.com/sveltejs/sapper/issues/3))
|
||||||
|
|
||||||
|
## 0.3.2
|
||||||
|
|
||||||
|
* Expose `prefetch` function ([#61](https://github.com/sveltejs/sapper/pull/61))
|
||||||
|
|
||||||
|
## 0.3.1
|
||||||
|
|
||||||
|
* Fix missing `runtime.js`
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
|
||||||
|
* Move `sapper/runtime/app.js` to `sapper/runtime.js`
|
||||||
|
* Cancel navigation if overtaken by second navigation ([#48](https://github.com/sveltejs/sapper/issues/48))
|
||||||
|
* Store preloaded data, to avoiding double prefetching ([#49](https://github.com/sveltejs/sapper/issues/49))
|
||||||
|
* Pass server request object to `preload` ([#54](https://github.com/sveltejs/sapper/pull/54))
|
||||||
|
* Nested routes ([#55](https://github.com/sveltejs/sapper/issues/55))
|
||||||
|
|
||||||
## 0.2.10
|
## 0.2.10
|
||||||
|
|
||||||
* Handle deep links correctly ([#44](https://github.com/sveltejs/sapper/issues/44))
|
* Handle deep links correctly ([#44](https://github.com/sveltejs/sapper/issues/44))
|
||||||
|
|||||||
9
LICENSE
Normal file
9
LICENSE
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Copyright (c) 2017 [these people](https://github.com/sveltejs/sapper/graphs/contributors).
|
||||||
|
|
||||||
|
Permission is hereby granted by the authors of this software, to any person, to use the software for any purpose, free of charge, including the rights to run, read, copy, change, distribute and sell it, and including usage rights to any patents the authors may hold on it, subject to the following conditions:
|
||||||
|
|
||||||
|
This license, or a link to its text, must be included with all copies of the software and any derivative works.
|
||||||
|
|
||||||
|
Any modification to the software submitted to the authors may be incorporated into the software under the terms of this license.
|
||||||
|
|
||||||
|
The software is provided "as is", without warranty of any kind, including but not limited to the warranties of title, fitness, merchantability and non-infringement. The authors have no obligation to provide support or updates for the software, and may not be held liable for any damages, claims or other liability arising from its use.
|
||||||
151
README.md
151
README.md
@@ -1,150 +1,37 @@
|
|||||||
# sapper
|
# sapper
|
||||||
|
|
||||||
Combat-ready apps, engineered by Svelte.
|
[Military-grade progressive web apps, powered by Svelte.](https://sapper.svelte.technology)
|
||||||
|
|
||||||
## This is not a thing yet
|
|
||||||
|
|
||||||
If you visit this README in a few weeks, hopefully it will have blossomed into the app development framework we deserve. Right now, it's just a set of ideas.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Next.js](https://github.com/zeit/next.js/) introduced a beautiful idea — that you should be able to build your app as universal React components in a special `pages` directory, and the framework should take care of routing and rendering on both client and server. What if we did the same thing for Svelte?
|
|
||||||
|
|
||||||
High-level goals:
|
|
||||||
|
|
||||||
* Extreme ease of development
|
|
||||||
* Code-splitting and HMR out of the box (probably via webpack)
|
|
||||||
* Best-in-class performance
|
|
||||||
* As little magic as possible. Anyone should be able to understand how everything fits together, and e.g. make changes to the webpack config
|
|
||||||
* Links are just `<a>` tags, no special `<Link>` components
|
|
||||||
|
|
||||||
|
|
||||||
## Design
|
## What is Sapper?
|
||||||
|
|
||||||
A Sapper app is just an Express app (conventionally, `server.js`) that uses the `sapper` middleware:
|
Sapper is a framework for building high-performance universal web apps. [Read the guide](https://sapper.svelte.technology/guide) or the [introductory blog post](https://svelte.technology/blog/sapper-towards-the-ideal-web-app-framework) to learn more.
|
||||||
|
|
||||||
```js
|
|
||||||
const app = require('express')();
|
|
||||||
const sapper = require('sapper');
|
|
||||||
|
|
||||||
app.use(sapper());
|
## Get started
|
||||||
|
|
||||||
const { PORT = 3000 } = process.env;
|
Clone the [starter project template](https://github.com/sveltejs/sapper-template) with [degit](https://github.com/rich-harris/degit)...
|
||||||
app.listen(PORT, () => {
|
|
||||||
console.log(`listening on port ${PORT}`);
|
```bash
|
||||||
});
|
npx degit sveltejs/sapper-template my-app
|
||||||
```
|
```
|
||||||
|
|
||||||
The middleware serves pages that match files in the `routes` directory, and assets generated by webpack. In development mode, the middleware once activated watches `routes` to keep the app up-to-date.
|
...then install dependencies and start the dev server...
|
||||||
|
|
||||||
|
```bash
|
||||||
## Routing
|
cd my-app
|
||||||
|
npm install
|
||||||
Like Next, routes are defined by the project directory structure, but with some crucial differences:
|
npm run dev
|
||||||
|
|
||||||
* Files with an `.html` extension are treated as Svelte components. The `routes/about.html` (or `routes/about/index.html`) would create the `/about` route.
|
|
||||||
* Files with a `.js` or `.mjs` extension are more generic route handlers. These files should export functions corresponding to the HTTP methods they support (example below).
|
|
||||||
* Instead of route masking, we embed parameters in the filename. For example `post/[id].html` maps to `/post/:id`, and the component will be rendered with the appropriate parameter.
|
|
||||||
* Nested routes (read [this article](https://joshduff.com/2015-06-why-you-need-a-state-router.md)) can be handled by creating a file that matches the subroute — for example, `routes/app/settings/[submenu].html` would match `/app/settings/profile` *and* `app/settings`, but in the latter case the `submenu` parameter would be `null`.
|
|
||||||
|
|
||||||
An example of a generic route:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// routes/api/post/[id].js
|
|
||||||
export async function get(req, res) {
|
|
||||||
try {
|
|
||||||
const data = await getPostFromDatabase(req.params.id);
|
|
||||||
const json = JSON.stringify(data);
|
|
||||||
|
|
||||||
res.set({
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Content-Length': json.length
|
|
||||||
});
|
|
||||||
|
|
||||||
res.send(json);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).send(err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you omit the `res` argument, it can use the return value:
|
...and navigate to [localhost:3000](http://localhost:3000). To build and run in production mode:
|
||||||
|
|
||||||
```js
|
```bash
|
||||||
// routes/api/post/[id].js
|
npm run build
|
||||||
export async function get(req) {
|
npm start
|
||||||
return await getPostFromDatabase(req.params.id);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Client-side app
|
## License
|
||||||
|
|
||||||
Sapper will create (and in development mode, update) a barebones `main.js` file that dynamically imports individual routes and renders them — something like this:
|
[LIL](LICENSE)
|
||||||
|
|
||||||
```js
|
|
||||||
window.addEventListener('click', event => {
|
|
||||||
let a = event.target;
|
|
||||||
while (a && a.nodeName !== 'A') a = a.parentNode;
|
|
||||||
if (!a) return;
|
|
||||||
|
|
||||||
if (navigate(new URL(a.href))) event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
const target = document.querySelector('#sapper');
|
|
||||||
let component;
|
|
||||||
|
|
||||||
function navigate(url) {
|
|
||||||
if (url.origin !== window.location.origin) return;
|
|
||||||
|
|
||||||
let match;
|
|
||||||
let params = {};
|
|
||||||
const query = {};
|
|
||||||
|
|
||||||
function render(mod) {
|
|
||||||
if (component) {
|
|
||||||
component.destroy();
|
|
||||||
} else {
|
|
||||||
target.innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
component = new mod.default({
|
|
||||||
target,
|
|
||||||
data: { query, params },
|
|
||||||
hydrate: !!component
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.pathname === '/about') {
|
|
||||||
import('/about/index.html').then(render);
|
|
||||||
} else if (url.pathname === '/') {
|
|
||||||
import('/index.js').then(render);
|
|
||||||
} else if (match = /^\/post\/([^\/]+)$/.exec(url.pathname)) {
|
|
||||||
params.id = match[1];
|
|
||||||
import('/post/[id].html').then(render);
|
|
||||||
} else if (match = /^\/([^\/]+)$/.exec(url.pathname)) {
|
|
||||||
params.wildcard = match[1];
|
|
||||||
import('/[wildcard].html').then(render);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigate(window.location);
|
|
||||||
```
|
|
||||||
|
|
||||||
We're glossing over a lot of important stuff here — e.g. handling `popstate` — but you get the idea. Knowledge of all the possible routes means we can generate optimal code, much in the same way that statically analysing Svelte templates allows the compiler to generate optimal code.
|
|
||||||
|
|
||||||
|
|
||||||
## Things to figure out
|
|
||||||
|
|
||||||
* How to customise the overall page template
|
|
||||||
* An equivalent of `getInitialProps`
|
|
||||||
* Critical CSS
|
|
||||||
* `store` integration
|
|
||||||
* Route transitions
|
|
||||||
* Equivalent of `next export`
|
|
||||||
* A good story for realtime/GraphQL stuff
|
|
||||||
* Service worker
|
|
||||||
* Using `Link...rel=preload` headers to push main.js/[route].js plus styles
|
|
||||||
* ...and lots of other things that haven't occurred to me yet.
|
|
||||||
25
cli/index.js
25
cli/index.js
@@ -1,8 +1,29 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const build = require('../lib/build.js');
|
||||||
|
|
||||||
const cmd = process.argv[2];
|
const cmd = process.argv[2];
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
if (cmd === 'build') {
|
if (cmd === 'build') {
|
||||||
process.env.NODE_ENV = 'production';
|
build()
|
||||||
require('../lib/build.js')();
|
.then(() => {
|
||||||
|
const elapsed = Date.now() - start;
|
||||||
|
console.error(`built in ${elapsed}ms`); // TODO beautify this, e.g. 'built in 4.7 seconds'
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
|
||||||
|
});
|
||||||
|
} else if (cmd === 'export') {
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
|
build()
|
||||||
|
.then(() => require('../lib/utils/export.js')())
|
||||||
|
.then(() => {
|
||||||
|
const elapsed = Date.now() - start;
|
||||||
|
console.error(`extracted in ${elapsed}ms`); // TODO beautify this, e.g. 'built in 4.7 seconds'
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
43
lib/build.js
43
lib/build.js
@@ -1,3 +1,5 @@
|
|||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const mkdirp = require('mkdirp');
|
const mkdirp = require('mkdirp');
|
||||||
@@ -14,29 +16,32 @@ module.exports = () => {
|
|||||||
// create main.js and server-routes.js
|
// create main.js and server-routes.js
|
||||||
create_app();
|
create_app();
|
||||||
|
|
||||||
function handleErrors(err, stats) {
|
return new Promise((fulfil, reject) => {
|
||||||
if (err) {
|
function handleErrors(err, stats) {
|
||||||
console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
|
if (err) {
|
||||||
process.exit(1);
|
reject(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
console.error(stats.toString({ colors: true }));
|
||||||
|
reject(new Error(`Encountered errors while building app`));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.hasErrors()) {
|
client.run((err, clientStats) => {
|
||||||
console.log(stats.toString({ colors: true }));
|
handleErrors(err, clientStats);
|
||||||
process.exit(1);
|
const clientInfo = clientStats.toJson();
|
||||||
}
|
fs.writeFileSync(path.join(dest, 'stats.client.json'), JSON.stringify(clientInfo, null, ' '));
|
||||||
}
|
|
||||||
|
|
||||||
client.run((err, clientStats) => {
|
server.run((err, serverStats) => {
|
||||||
handleErrors(err, clientStats);
|
handleErrors(err, serverStats);
|
||||||
const clientInfo = clientStats.toJson();
|
const serverInfo = serverStats.toJson();
|
||||||
fs.writeFileSync(path.join(dest, 'stats.client.json'), JSON.stringify(clientInfo, null, ' '));
|
fs.writeFileSync(path.join(dest, 'stats.server.json'), JSON.stringify(serverInfo, null, ' '));
|
||||||
|
|
||||||
server.run((err, serverStats) => {
|
generate_asset_cache(clientInfo, serverInfo);
|
||||||
handleErrors(err, serverStats);
|
fulfil();
|
||||||
const serverInfo = serverStats.toJson();
|
});
|
||||||
fs.writeFileSync(path.join(dest, 'stats.server.json'), JSON.stringify(serverInfo, null, ' '));
|
|
||||||
|
|
||||||
generate_asset_cache(clientInfo, serverInfo);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
163
lib/index.js
163
lib/index.js
@@ -1,5 +1,6 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const serialize = require('serialize-javascript');
|
||||||
const route_manager = require('./route_manager.js');
|
const route_manager = require('./route_manager.js');
|
||||||
const templates = require('./templates.js');
|
const templates = require('./templates.js');
|
||||||
const create_app = require('./utils/create_app.js');
|
const create_app = require('./utils/create_app.js');
|
||||||
@@ -23,9 +24,11 @@ function connect_dev() {
|
|||||||
heartbeat: 10 * 1000
|
heartbeat: 10 * 1000
|
||||||
}),
|
}),
|
||||||
|
|
||||||
async (req, res, next) => {
|
(req, res, next) => {
|
||||||
asset_cache = await watcher.ready;
|
watcher.ready.then(cache => {
|
||||||
next();
|
asset_cache = cache;
|
||||||
|
next();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
set_req_pathname,
|
set_req_pathname,
|
||||||
@@ -125,76 +128,98 @@ function get_asset_handler(opts) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_route_handler(fn) {
|
const resolved = Promise.resolve();
|
||||||
return async function handle_route(req, res, next) {
|
|
||||||
const url = req.pathname;
|
|
||||||
|
|
||||||
const { client, server } = fn();
|
function get_route_handler(fn) {
|
||||||
|
function handle_route(route, req, res, next, { client, server }) {
|
||||||
|
req.params = route.exec(req.pathname);
|
||||||
|
|
||||||
|
const mod = require(server.entry)[route.id];
|
||||||
|
|
||||||
|
if (route.type === 'page') {
|
||||||
|
// preload main.js and current route
|
||||||
|
// TODO detect other stuff we can preload? images, CSS, fonts?
|
||||||
|
res.set('Link', `<${client.main_file}>;rel="preload";as="script", <${client.routes[route.id]}>;rel="preload";as="script"`);
|
||||||
|
|
||||||
|
const data = { params: req.params, query: req.query };
|
||||||
|
|
||||||
|
if (mod.preload) {
|
||||||
|
const promise = Promise.resolve(mod.preload(req)).then(preloaded => {
|
||||||
|
const serialized = try_serialize(preloaded);
|
||||||
|
Object.assign(data, preloaded);
|
||||||
|
|
||||||
|
return { rendered: mod.render(data), serialized };
|
||||||
|
});
|
||||||
|
|
||||||
|
return templates.stream(res, 200, {
|
||||||
|
scripts: promise.then(({ serialized }) => {
|
||||||
|
const main = `<script src='${client.main_file}'></script>`;
|
||||||
|
|
||||||
|
if (serialized) {
|
||||||
|
return `<script>__SAPPER__ = { preloaded: ${serialized} };</script>${main}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return main;
|
||||||
|
}),
|
||||||
|
html: promise.then(({ rendered }) => rendered.html),
|
||||||
|
head: promise.then(({ rendered }) => `<noscript id='sapper-head-start'></noscript>${rendered.head}<noscript id='sapper-head-end'></noscript>`),
|
||||||
|
styles: promise.then(({ rendered }) => (rendered.css && rendered.css.code ? `<style>${rendered.css.code}</style>` : ''))
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const { html, head, css } = mod.render(data);
|
||||||
|
|
||||||
|
const page = templates.render(200, {
|
||||||
|
scripts: `<script src='${client.main_file}'></script>`,
|
||||||
|
html,
|
||||||
|
head: `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`,
|
||||||
|
styles: (css && css.code ? `<style>${css.code}</style>` : '')
|
||||||
|
});
|
||||||
|
|
||||||
|
res.end(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
const method = req.method.toLowerCase();
|
||||||
|
// 'delete' cannot be exported from a module because it is a keyword,
|
||||||
|
// so check for 'del' instead
|
||||||
|
const method_export = method === 'delete' ? 'del' : method;
|
||||||
|
const handler = mod[method_export];
|
||||||
|
if (handler) {
|
||||||
|
handler(req, res, next);
|
||||||
|
} else {
|
||||||
|
// no matching handler for method — 404
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function find_route(req, res, next) {
|
||||||
|
const url = req.pathname;
|
||||||
|
|
||||||
// whatever happens, we're going to serve some HTML
|
// whatever happens, we're going to serve some HTML
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'text/html'
|
'Content-Type': 'text/html'
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
resolved
|
||||||
for (const route of route_manager.routes) {
|
.then(() => {
|
||||||
if (route.test(url)) {
|
for (const route of route_manager.routes) {
|
||||||
req.params = route.exec(url);
|
if (route.test(url)) return handle_route(route, req, res, next, fn());
|
||||||
|
|
||||||
const mod = require(server.entry)[route.id];
|
|
||||||
|
|
||||||
if (route.type === 'page') {
|
|
||||||
// preload main.js and current route
|
|
||||||
// TODO detect other stuff we can preload? images, CSS, fonts?
|
|
||||||
res.set('Link', `<${client.main_file}>;rel="preload";as="script", <${client.routes[route.id]}>;rel="preload";as="script"`);
|
|
||||||
|
|
||||||
const data = { params: req.params, query: req.query };
|
|
||||||
|
|
||||||
if (mod.preload) {
|
|
||||||
const promise = Promise.resolve(mod.preload(data)).then(preloaded => {
|
|
||||||
Object.assign(data, preloaded);
|
|
||||||
return mod.render(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
await templates.stream(res, 200, {
|
|
||||||
main: client.main_file,
|
|
||||||
html: promise.then(rendered => rendered.html),
|
|
||||||
head: promise.then(({ head }) => `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`),
|
|
||||||
styles: promise.then(({ css }) => (css && css.code ? `<style>${css.code}</style>` : ''))
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const { html, head, css } = mod.render(data);
|
|
||||||
|
|
||||||
const page = templates.render(200, {
|
|
||||||
main: client.main_file,
|
|
||||||
html,
|
|
||||||
head: `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`,
|
|
||||||
styles: (css && css.code ? `<style>${css.code}</style>` : '')
|
|
||||||
});
|
|
||||||
|
|
||||||
res.end(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
const handler = mod[req.method.toLowerCase()];
|
|
||||||
if (handler) handler(req, res, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
// no matching route — 404
|
||||||
} catch(err) {
|
next();
|
||||||
res.status(500);
|
})
|
||||||
res.end(templates.render(500, {
|
.catch(err => {
|
||||||
title: (err && err.name) || 'Internal server error',
|
res.status(500);
|
||||||
url,
|
res.end(templates.render(500, {
|
||||||
error: escape_html(err && (err.details || err.message || err) || 'Unknown error'),
|
title: (err && err.name) || 'Internal server error',
|
||||||
stack: err && err.stack.split('\n').slice(1).join('\n')
|
url,
|
||||||
}));
|
error: escape_html(err && (err.details || err.message || err) || 'Unknown error'),
|
||||||
}
|
stack: err && err.stack.split('\n').slice(1).join('\n')
|
||||||
|
}));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +232,7 @@ function get_not_found_handler(fn) {
|
|||||||
title: 'Not found',
|
title: 'Not found',
|
||||||
status: 404,
|
status: 404,
|
||||||
method: req.method,
|
method: req.method,
|
||||||
main: asset_cache.client.main_file,
|
scripts: `<script src='${asset_cache.client.main_file}'></script>`,
|
||||||
url: req.url
|
url: req.url
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@@ -236,3 +261,11 @@ function compose_handlers(handlers) {
|
|||||||
function read_json(file) {
|
function read_json(file) {
|
||||||
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function try_serialize(data) {
|
||||||
|
try {
|
||||||
|
return serialize(data);
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const chokidar = require('chokidar');
|
|
||||||
const create_routes = require('./utils/create_routes.js');
|
const create_routes = require('./utils/create_routes.js');
|
||||||
const { src, dev } = require('./config.js');
|
const { src, dev } = require('./config.js');
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ function update() {
|
|||||||
update();
|
update();
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
const watcher = chokidar.watch(`${src}/**/*.+(html|js|mjs)`, {
|
const watcher = require('chokidar').watch(`${src}/**/*.+(html|js|mjs)`, {
|
||||||
ignoreInitial: true,
|
ignoreInitial: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const chokidar = require('chokidar');
|
const chalk = require('chalk');
|
||||||
|
const framer = require('code-frame');
|
||||||
|
const { locate } = require('locate-character');
|
||||||
const { dev } = require('./config.js');
|
const { dev } = require('./config.js');
|
||||||
|
|
||||||
let templates;
|
let templates;
|
||||||
|
|
||||||
|
function error(e) {
|
||||||
|
if (e.title) console.error(chalk.bold.red(e.title));
|
||||||
|
if (e.body) console.error(chalk.red(e.body));
|
||||||
|
if (e.url) console.error(chalk.cyan(e.url));
|
||||||
|
if (e.frame) console.error(chalk.grey(e.frame));
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
function create_templates() {
|
function create_templates() {
|
||||||
templates = glob.sync('*.html', { cwd: 'templates' })
|
templates = glob.sync('*.html', { cwd: 'templates' })
|
||||||
.map(file => {
|
.map(file => {
|
||||||
@@ -12,7 +23,24 @@ function create_templates() {
|
|||||||
const status = file.replace('.html', '').toLowerCase();
|
const status = file.replace('.html', '').toLowerCase();
|
||||||
|
|
||||||
if (!/^[0-9x]{3}$/.test(status)) {
|
if (!/^[0-9x]{3}$/.test(status)) {
|
||||||
throw new Error(`Bad template — should be a valid status code like 404.html, or a wildcard like 2xx.html`);
|
error({
|
||||||
|
title: `templates/${file}`,
|
||||||
|
body: `Bad template — should be a valid status code like 404.html, or a wildcard like 2xx.html`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = template.indexOf('%sapper.main%');
|
||||||
|
if (index !== -1) {
|
||||||
|
// TODO remove this in a future version
|
||||||
|
const { line, column } = locate(template, index, { offsetLine: 1 });
|
||||||
|
const frame = framer(template, line, column);
|
||||||
|
|
||||||
|
error({
|
||||||
|
title: `templates/${file}`,
|
||||||
|
body: `<script src='%sapper.main%'> is unsupported — use %sapper.scripts% (without the <script> tag) instead`,
|
||||||
|
url: 'https://github.com/sveltejs/sapper/issues/86',
|
||||||
|
frame
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const specificity = (
|
const specificity = (
|
||||||
@@ -31,10 +59,14 @@ function create_templates() {
|
|||||||
return key in data ? data[key] : '';
|
return key in data ? data[key] : '';
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
stream: async (res, data) => {
|
stream: (res, data) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
do {
|
function stream_inner() {
|
||||||
|
if (i >= template.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const start = template.indexOf('%sapper', i);
|
const start = template.indexOf('%sapper', i);
|
||||||
|
|
||||||
if (start === -1) {
|
if (start === -1) {
|
||||||
@@ -53,9 +85,14 @@ function create_templates() {
|
|||||||
const match = /sapper\.(\w+)/.exec(tag);
|
const match = /sapper\.(\w+)/.exec(tag);
|
||||||
if (!match || !(match[1] in data)) throw new Error(`Bad template`); // TODO ditto
|
if (!match || !(match[1] in data)) throw new Error(`Bad template`); // TODO ditto
|
||||||
|
|
||||||
res.write(await data[match[1]]);
|
return Promise.resolve(data[match[1]]).then(datamatch => {
|
||||||
i = end + 1;
|
res.write(datamatch);
|
||||||
} while (i < template.length);
|
i = end + 1;
|
||||||
|
return stream_inner();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve().then(stream_inner);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -65,7 +102,7 @@ function create_templates() {
|
|||||||
create_templates();
|
create_templates();
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
const watcher = chokidar.watch('templates/**.html', {
|
const watcher = require('chokidar').watch('templates/**.html', {
|
||||||
ignoreInitial: true,
|
ignoreInitial: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const chokidar = require('chokidar');
|
|
||||||
const route_manager = require('../route_manager.js');
|
const route_manager = require('../route_manager.js');
|
||||||
const { src, entry, dev } = require('../config.js');
|
const { src, entry, dev } = require('../config.js');
|
||||||
|
|
||||||
@@ -70,7 +69,7 @@ function create_app() {
|
|||||||
if (dev) {
|
if (dev) {
|
||||||
route_manager.onchange(create_app);
|
route_manager.onchange(create_app);
|
||||||
|
|
||||||
const watcher = chokidar.watch(`templates/main.js`, {
|
const watcher = require('chokidar').watch(`templates/main.js`, {
|
||||||
ignoreInitial: true,
|
ignoreInitial: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,9 +16,22 @@ module.exports = function create_matchers(files) {
|
|||||||
.filter(part => part[0] === '[')
|
.filter(part => part[0] === '[')
|
||||||
.map(part => part.slice(1, -1));
|
.map(part => part.slice(1, -1));
|
||||||
|
|
||||||
const pattern = new RegExp(
|
let pattern_string = '';
|
||||||
`^\\/${parts.map(p => p[0] === '[' ? '([^/]+)' : p).join('\\/')}$`
|
let i = parts.length;
|
||||||
);
|
let nested = true;
|
||||||
|
while (i--) {
|
||||||
|
const part = parts[i];
|
||||||
|
const dynamic = part[0] === '[';
|
||||||
|
|
||||||
|
if (dynamic) {
|
||||||
|
pattern_string = nested ? `(?:\\/([^/]+)${pattern_string})?` : `\\/([^/]+)${pattern_string}`;
|
||||||
|
} else {
|
||||||
|
nested = false;
|
||||||
|
pattern_string = `\\/${part}${pattern_string}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = new RegExp(`^${pattern_string}\\/?$`);
|
||||||
|
|
||||||
const test = url => pattern.test(url);
|
const test = url => pattern.test(url);
|
||||||
|
|
||||||
@@ -58,8 +71,8 @@ module.exports = function create_matchers(files) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!a_part) return 1;
|
if (!a_part) return -1;
|
||||||
if (!b_part) return -1;
|
if (!b_part) return 1;
|
||||||
|
|
||||||
const a_is_dynamic = a_part[0] === '[';
|
const a_is_dynamic = a_part[0] === '[';
|
||||||
const b_is_dynamic = b_part[0] === '[';
|
const b_is_dynamic = b_part[0] === '[';
|
||||||
|
|||||||
87
lib/utils/export.js
Normal file
87
lib/utils/export.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
const sander = require('sander');
|
||||||
|
const app = require('express')();
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const URL = require('url-parse');
|
||||||
|
const sapper = require('../index.js');
|
||||||
|
|
||||||
|
const { PORT = 3000, OUTPUT_DIR = 'dist' } = process.env;
|
||||||
|
const { dest } = require('../config.js');
|
||||||
|
|
||||||
|
const origin = `http://localhost:${PORT}`;
|
||||||
|
|
||||||
|
module.exports = function() {
|
||||||
|
// Prep output directory
|
||||||
|
sander.rimrafSync(OUTPUT_DIR);
|
||||||
|
|
||||||
|
sander.copydirSync('assets').to(OUTPUT_DIR);
|
||||||
|
sander.copydirSync(`${dest}/client`).to(`${OUTPUT_DIR}/client`);
|
||||||
|
sander.copyFileSync(`${dest}/service-worker.js`).to(`${OUTPUT_DIR}/service-worker.js`);
|
||||||
|
|
||||||
|
// Intercept server route fetches
|
||||||
|
function save(res) {
|
||||||
|
res = res.clone();
|
||||||
|
|
||||||
|
return res.text().then(body => {
|
||||||
|
const { pathname } = new URL(res.url);
|
||||||
|
let dest = OUTPUT_DIR + pathname;
|
||||||
|
|
||||||
|
const type = res.headers.get('Content-Type');
|
||||||
|
if (type.startsWith('text/html;')) dest += '/index.html';
|
||||||
|
|
||||||
|
sander.writeFileSync(dest, body);
|
||||||
|
|
||||||
|
return body;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
global.fetch = (url, opts) => {
|
||||||
|
if (url[0] === '/') {
|
||||||
|
url = `http://localhost:${PORT}${url}`;
|
||||||
|
|
||||||
|
return fetch(url, opts)
|
||||||
|
.then(r => {
|
||||||
|
save(r);
|
||||||
|
return r;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url, opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
app.use(sapper());
|
||||||
|
const server = app.listen(PORT);
|
||||||
|
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
function handle(url) {
|
||||||
|
if (url.origin !== origin) return;
|
||||||
|
|
||||||
|
if (seen.has(url.pathname)) return;
|
||||||
|
seen.add(url.pathname);
|
||||||
|
|
||||||
|
return fetch(url.href)
|
||||||
|
.then(r => {
|
||||||
|
save(r);
|
||||||
|
return r.text();
|
||||||
|
})
|
||||||
|
.then(body => {
|
||||||
|
const $ = cheerio.load(body);
|
||||||
|
const hrefs = [];
|
||||||
|
|
||||||
|
$('a[href]').each((i, $a) => {
|
||||||
|
hrefs.push($a.attribs.href);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hrefs.reduce((promise, href) => {
|
||||||
|
return promise.then(() => handle(new URL(href, url.href)));
|
||||||
|
}, Promise.resolve());
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(`Error rendering ${url.pathname}: ${err.message}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle(new URL(origin)) // TODO all static routes
|
||||||
|
.then(() => server.close());
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@ const path = require('path');
|
|||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const templates = require('../templates.js');
|
const templates = require('../templates.js');
|
||||||
const route_manager = require('../route_manager.js');
|
const route_manager = require('../route_manager.js');
|
||||||
const { dest, dev } = require('../config.js');
|
const { dest } = require('../config.js');
|
||||||
|
|
||||||
function ensure_array(thing) {
|
function ensure_array(thing) {
|
||||||
return Array.isArray(thing) ? thing : [thing]; // omg webpack what the HELL are you doing
|
return Array.isArray(thing) ? thing : [thing]; // omg webpack what the HELL are you doing
|
||||||
@@ -17,10 +17,8 @@ module.exports = function generate_asset_cache(clientInfo, serverInfo) {
|
|||||||
const service_worker = generate_service_worker(chunk_files);
|
const service_worker = generate_service_worker(chunk_files);
|
||||||
const index = generate_index(main_file);
|
const index = generate_index(main_file);
|
||||||
|
|
||||||
if (dev) {
|
fs.writeFileSync(path.join(dest, 'service-worker.js'), service_worker);
|
||||||
fs.writeFileSync(path.join(dest, 'service-worker.js'), service_worker);
|
fs.writeFileSync(path.join(dest, 'index.html'), index);
|
||||||
fs.writeFileSync(path.join(dest, 'index.html'), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
client: {
|
client: {
|
||||||
@@ -59,10 +57,10 @@ function generate_service_worker(chunk_files) {
|
|||||||
}]`;
|
}]`;
|
||||||
|
|
||||||
return read('templates/service-worker.js')
|
return read('templates/service-worker.js')
|
||||||
.replace('__timestamp__', Date.now())
|
.replace(/__timestamp__/g, Date.now())
|
||||||
.replace('__assets__', JSON.stringify(assets))
|
.replace(/__assets__/g, JSON.stringify(assets))
|
||||||
.replace('__shell__', JSON.stringify(chunk_files.concat('/index.html')))
|
.replace(/__shell__/g, JSON.stringify(chunk_files.concat('/index.html')))
|
||||||
.replace('__routes__', route_code);
|
.replace(/__routes__/g, route_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_index(main_file) {
|
function generate_index(main_file) {
|
||||||
|
|||||||
474
package-lock.json
generated
474
package-lock.json
generated
@@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.2.7",
|
"version": "0.4.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "7.0.51",
|
"version": "7.0.52",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.51.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.52.tgz",
|
||||||
"integrity": "sha512-h5u7FnEnG+Fn44HfknTTvu199FzFWVSo97ToSRWvXl1F11UfN6wGnE7exUy23pFfDn+CeluvEoCoe4l2eCVC3g==",
|
"integrity": "sha512-jjpyQsKGsOF/wUElNjfPULk+d8PKvJOIXk3IUeBYYmNCy5dMWfrI+JiixYNw8ppKOlcRwWTXFl0B+i5oGrf95Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"accepts": {
|
"accepts": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
@@ -21,9 +20,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "5.2.1",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz",
|
||||||
"integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w=="
|
"integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug=="
|
||||||
},
|
},
|
||||||
"acorn-dynamic-import": {
|
"acorn-dynamic-import": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
@@ -256,7 +255,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "1.7.7",
|
"browserslist": "1.7.7",
|
||||||
"caniuse-db": "1.0.30000784",
|
"caniuse-db": "1.0.30000791",
|
||||||
"normalize-range": "0.1.2",
|
"normalize-range": "0.1.2",
|
||||||
"num2fraction": "1.2.2",
|
"num2fraction": "1.2.2",
|
||||||
"postcss": "5.2.18",
|
"postcss": "5.2.18",
|
||||||
@@ -357,7 +356,7 @@
|
|||||||
"bytes": "3.0.0",
|
"bytes": "3.0.0",
|
||||||
"content-type": "1.0.4",
|
"content-type": "1.0.4",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "1.1.1",
|
"depd": "1.1.2",
|
||||||
"http-errors": "1.6.2",
|
"http-errors": "1.6.2",
|
||||||
"iconv-lite": "0.4.19",
|
"iconv-lite": "0.4.19",
|
||||||
"on-finished": "2.3.0",
|
"on-finished": "2.3.0",
|
||||||
@@ -377,6 +376,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"boolbase": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||||
|
},
|
||||||
"boom": {
|
"boom": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||||
@@ -455,7 +459,7 @@
|
|||||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "4.11.8",
|
"bn.js": "4.11.8",
|
||||||
"randombytes": "2.0.5"
|
"randombytes": "2.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserify-sign": {
|
"browserify-sign": {
|
||||||
@@ -486,7 +490,7 @@
|
|||||||
"integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
|
"integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-db": "1.0.30000784",
|
"caniuse-db": "1.0.30000791",
|
||||||
"electron-to-chromium": "1.3.30"
|
"electron-to-chromium": "1.3.30"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -566,15 +570,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "1.7.7",
|
"browserslist": "1.7.7",
|
||||||
"caniuse-db": "1.0.30000784",
|
"caniuse-db": "1.0.30000791",
|
||||||
"lodash.memoize": "4.1.2",
|
"lodash.memoize": "4.1.2",
|
||||||
"lodash.uniq": "4.5.0"
|
"lodash.uniq": "4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-db": {
|
"caniuse-db": {
|
||||||
"version": "1.0.30000784",
|
"version": "1.0.30000791",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000784.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000791.tgz",
|
||||||
"integrity": "sha1-G+lQEtlInHcZB0+BruV9vf/mNhs=",
|
"integrity": "sha1-Bnh/VsrvQwChfjXRN0RxI731Nvk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"caseless": {
|
"caseless": {
|
||||||
@@ -608,6 +612,19 @@
|
|||||||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
|
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"cheerio": {
|
||||||
|
"version": "1.0.0-rc.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz",
|
||||||
|
"integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=",
|
||||||
|
"requires": {
|
||||||
|
"css-select": "1.2.0",
|
||||||
|
"dom-serializer": "0.1.0",
|
||||||
|
"entities": "1.1.1",
|
||||||
|
"htmlparser2": "3.9.2",
|
||||||
|
"lodash": "4.17.4",
|
||||||
|
"parse5": "3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
|
||||||
@@ -720,6 +737,14 @@
|
|||||||
"q": "1.5.1"
|
"q": "1.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"code-frame": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/code-frame/-/code-frame-5.0.0.tgz",
|
||||||
|
"integrity": "sha1-QAMHB+xG4dmdXlLcnzV/ytkNmT0=",
|
||||||
|
"requires": {
|
||||||
|
"left-pad": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
@@ -790,6 +815,12 @@
|
|||||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"compare-versions": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-Htwfk2h/2XoyXFn1XkWgfbEGrKY=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@@ -937,7 +968,7 @@
|
|||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"pbkdf2": "3.0.14",
|
"pbkdf2": "3.0.14",
|
||||||
"public-encrypt": "4.0.0",
|
"public-encrypt": "4.0.0",
|
||||||
"randombytes": "2.0.5",
|
"randombytes": "2.0.6",
|
||||||
"randomfill": "1.0.3"
|
"randomfill": "1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -948,9 +979,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"css-loader": {
|
"css-loader": {
|
||||||
"version": "0.28.7",
|
"version": "0.28.8",
|
||||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz",
|
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.8.tgz",
|
||||||
"integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==",
|
"integrity": "sha512-4jGj7Ag6WUZ5lQyE4te9sJLn0lgkz6HI3WDE4aw98AkW1IAKXPP4blTpPeorlLDpNsYvojo0SYgRJOdz2KbuAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-code-frame": "6.26.0",
|
"babel-code-frame": "6.26.0",
|
||||||
@@ -969,6 +1000,17 @@
|
|||||||
"source-list-map": "2.0.0"
|
"source-list-map": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-select": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||||
|
"requires": {
|
||||||
|
"boolbase": "1.0.0",
|
||||||
|
"css-what": "2.1.0",
|
||||||
|
"domutils": "1.5.1",
|
||||||
|
"nth-check": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"css-selector-tokenizer": {
|
"css-selector-tokenizer": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
|
||||||
@@ -980,6 +1022,11 @@
|
|||||||
"regexpu-core": "1.0.0"
|
"regexpu-core": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-what": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
|
||||||
|
"integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
|
||||||
|
},
|
||||||
"cssesc": {
|
"cssesc": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
|
||||||
@@ -1165,9 +1212,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"depd": {
|
"depd": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
|
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"des.js": {
|
"des.js": {
|
||||||
@@ -1198,23 +1245,61 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "4.11.8",
|
"bn.js": "4.11.8",
|
||||||
"miller-rabin": "4.0.1",
|
"miller-rabin": "4.0.1",
|
||||||
"randombytes": "2.0.5"
|
"randombytes": "2.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"doctrine": {
|
"doctrine": {
|
||||||
"version": "2.0.2",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||||
"integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==",
|
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esutils": "2.0.2"
|
"esutils": "2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
|
||||||
|
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "1.1.3",
|
||||||
|
"entities": "1.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
|
||||||
|
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain-browser": {
|
"domain-browser": {
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
|
||||||
"integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw="
|
"integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw="
|
||||||
},
|
},
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
|
||||||
|
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
|
||||||
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
|
||||||
|
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||||
|
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "0.1.0",
|
||||||
|
"domelementtype": "1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||||
@@ -1243,7 +1328,7 @@
|
|||||||
"integrity": "sha1-Oj6D2WX9f6/kc76N349HJWG2JT0=",
|
"integrity": "sha1-Oj6D2WX9f6/kc76N349HJWG2JT0=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "7.0.51",
|
"@types/node": "7.0.52",
|
||||||
"electron-download": "3.3.0",
|
"electron-download": "3.3.0",
|
||||||
"extract-zip": "1.6.6"
|
"extract-zip": "1.6.6"
|
||||||
}
|
}
|
||||||
@@ -1260,7 +1345,7 @@
|
|||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"nugget": "2.0.1",
|
"nugget": "2.0.1",
|
||||||
"path-exists": "2.1.0",
|
"path-exists": "2.1.0",
|
||||||
"rc": "1.2.2",
|
"rc": "1.2.3",
|
||||||
"semver": "5.4.1",
|
"semver": "5.4.1",
|
||||||
"sumchecker": "1.3.1"
|
"sumchecker": "1.3.1"
|
||||||
},
|
},
|
||||||
@@ -1368,6 +1453,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ensure-posix-path": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI="
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
|
||||||
|
},
|
||||||
"errno": {
|
"errno": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz",
|
||||||
@@ -1500,9 +1595,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eslint": {
|
"eslint": {
|
||||||
"version": "4.13.1",
|
"version": "4.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.15.0.tgz",
|
||||||
"integrity": "sha512-UCJVV50RtLHYzBp1DZ8CMPtRSg4iVZvjgO9IJHIKyWU/AnJVjtdRikoUPLB29n5pzMB7TnsLQWf0V6VUJfoPfw==",
|
"integrity": "sha512-zEO/Z1ZUxIQ+MhDVKkVTUYpIPDTEJLXGMrkID+5v1NeQHtCz6FZikWuFRgxE1Q/RV2V4zVl1u3xmpPADHhMZ6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "5.5.2",
|
"ajv": "5.5.2",
|
||||||
@@ -1511,11 +1606,11 @@
|
|||||||
"concat-stream": "1.6.0",
|
"concat-stream": "1.6.0",
|
||||||
"cross-spawn": "5.1.0",
|
"cross-spawn": "5.1.0",
|
||||||
"debug": "3.1.0",
|
"debug": "3.1.0",
|
||||||
"doctrine": "2.0.2",
|
"doctrine": "2.1.0",
|
||||||
"eslint-scope": "3.7.1",
|
"eslint-scope": "3.7.1",
|
||||||
|
"eslint-visitor-keys": "1.0.0",
|
||||||
"espree": "3.5.2",
|
"espree": "3.5.2",
|
||||||
"esquery": "1.0.0",
|
"esquery": "1.0.0",
|
||||||
"estraverse": "4.2.0",
|
|
||||||
"esutils": "2.0.2",
|
"esutils": "2.0.2",
|
||||||
"file-entry-cache": "2.0.0",
|
"file-entry-cache": "2.0.0",
|
||||||
"functional-red-black-tree": "1.0.1",
|
"functional-red-black-tree": "1.0.1",
|
||||||
@@ -1578,9 +1673,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eslint-import-resolver-node": {
|
"eslint-import-resolver-node": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz",
|
||||||
"integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==",
|
"integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
@@ -1629,7 +1724,7 @@
|
|||||||
"contains-path": "0.1.0",
|
"contains-path": "0.1.0",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"doctrine": "1.5.0",
|
"doctrine": "1.5.0",
|
||||||
"eslint-import-resolver-node": "0.3.1",
|
"eslint-import-resolver-node": "0.3.2",
|
||||||
"eslint-module-utils": "2.1.1",
|
"eslint-module-utils": "2.1.1",
|
||||||
"has": "1.0.1",
|
"has": "1.0.1",
|
||||||
"lodash.cond": "4.5.2",
|
"lodash.cond": "4.5.2",
|
||||||
@@ -1668,13 +1763,19 @@
|
|||||||
"estraverse": "4.2.0"
|
"estraverse": "4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-visitor-keys": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"espree": {
|
"espree": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
|
||||||
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
|
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"acorn": "5.2.1",
|
"acorn": "5.3.0",
|
||||||
"acorn-jsx": "3.0.1"
|
"acorn-jsx": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1707,6 +1808,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
|
||||||
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
|
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
|
||||||
},
|
},
|
||||||
|
"estree-walker": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz",
|
||||||
|
"integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"esutils": {
|
"esutils": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||||
@@ -1801,7 +1908,7 @@
|
|||||||
"cookie": "0.3.1",
|
"cookie": "0.3.1",
|
||||||
"cookie-signature": "1.0.6",
|
"cookie-signature": "1.0.6",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "1.1.1",
|
"depd": "1.1.2",
|
||||||
"encodeurl": "1.0.1",
|
"encodeurl": "1.0.1",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
"etag": "1.8.1",
|
"etag": "1.8.1",
|
||||||
@@ -3101,6 +3208,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
|
||||||
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
|
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
|
||||||
},
|
},
|
||||||
|
"htmlparser2": {
|
||||||
|
"version": "3.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
|
||||||
|
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "1.3.0",
|
||||||
|
"domhandler": "2.4.1",
|
||||||
|
"domutils": "1.5.1",
|
||||||
|
"entities": "1.1.1",
|
||||||
|
"inherits": "2.0.3",
|
||||||
|
"readable-stream": "2.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"http-errors": {
|
"http-errors": {
|
||||||
"version": "1.6.2",
|
"version": "1.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
|
||||||
@@ -3113,6 +3233,12 @@
|
|||||||
"statuses": "1.3.1"
|
"statuses": "1.3.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"depd": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"setprototypeof": {
|
"setprototypeof": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
|
||||||
@@ -3155,18 +3281,18 @@
|
|||||||
"integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
|
"integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss": "6.0.14"
|
"postcss": "6.0.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.16.tgz",
|
||||||
"integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==",
|
"integrity": "sha512-m758RWPmSjFH/2MyyG3UOW1fgYbR9rtdzz5UNJnlm7OLtu4B2h9C6gi+bE4qFKghsBRFfZT8NzoQBs6JhLotoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "2.3.0",
|
"chalk": "2.3.0",
|
||||||
"source-map": "0.6.1",
|
"source-map": "0.6.1",
|
||||||
"supports-color": "4.5.0"
|
"supports-color": "5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -3174,6 +3300,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -3668,6 +3803,11 @@
|
|||||||
"invert-kv": "1.0.0"
|
"invert-kv": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"left-pad": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4="
|
||||||
|
},
|
||||||
"levn": {
|
"levn": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||||
@@ -3704,6 +3844,11 @@
|
|||||||
"json5": "0.5.1"
|
"json5": "0.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"locate-character": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-n2GmejDXtOPBAZdIiEFy5dJ5N38xBCXLNOtw2WpB9kGh6pnrEuKlwYI+Tkpofc4wDtVXHtoAOJaMRlYG/oYaxg=="
|
||||||
|
},
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
||||||
@@ -3784,6 +3929,14 @@
|
|||||||
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
|
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"matcher-collection": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA==",
|
||||||
|
"requires": {
|
||||||
|
"minimatch": "3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"math-expression-evaluator": {
|
"math-expression-evaluator": {
|
||||||
"version": "1.2.17",
|
"version": "1.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
|
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
|
||||||
@@ -4057,9 +4210,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mocha": {
|
"mocha": {
|
||||||
"version": "4.0.1",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
|
||||||
"integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==",
|
"integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browser-stdout": "1.3.0",
|
"browser-stdout": "1.3.0",
|
||||||
@@ -4305,6 +4458,14 @@
|
|||||||
"path-key": "2.0.1"
|
"path-key": "2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nth-check": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
|
||||||
|
"requires": {
|
||||||
|
"boolbase": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nugget": {
|
"nugget": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
|
||||||
@@ -4449,18 +4610,26 @@
|
|||||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||||
},
|
},
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",
|
||||||
"integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw="
|
"integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "1.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"p-locate": {
|
"p-locate": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
||||||
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"p-limit": "1.1.0"
|
"p-limit": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
|
||||||
|
},
|
||||||
"pako": {
|
"pako": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
|
||||||
@@ -4497,6 +4666,14 @@
|
|||||||
"error-ex": "1.3.1"
|
"error-ex": "1.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"parse5": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "7.0.52"
|
||||||
|
}
|
||||||
|
},
|
||||||
"parseurl": {
|
"parseurl": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
|
||||||
@@ -4872,18 +5049,18 @@
|
|||||||
"integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
|
"integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss": "6.0.14"
|
"postcss": "6.0.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.16.tgz",
|
||||||
"integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==",
|
"integrity": "sha512-m758RWPmSjFH/2MyyG3UOW1fgYbR9rtdzz5UNJnlm7OLtu4B2h9C6gi+bE4qFKghsBRFfZT8NzoQBs6JhLotoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "2.3.0",
|
"chalk": "2.3.0",
|
||||||
"source-map": "0.6.1",
|
"source-map": "0.6.1",
|
||||||
"supports-color": "4.5.0"
|
"supports-color": "5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -4891,6 +5068,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -4901,18 +5087,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"css-selector-tokenizer": "0.7.0",
|
"css-selector-tokenizer": "0.7.0",
|
||||||
"postcss": "6.0.14"
|
"postcss": "6.0.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.16.tgz",
|
||||||
"integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==",
|
"integrity": "sha512-m758RWPmSjFH/2MyyG3UOW1fgYbR9rtdzz5UNJnlm7OLtu4B2h9C6gi+bE4qFKghsBRFfZT8NzoQBs6JhLotoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "2.3.0",
|
"chalk": "2.3.0",
|
||||||
"source-map": "0.6.1",
|
"source-map": "0.6.1",
|
||||||
"supports-color": "4.5.0"
|
"supports-color": "5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -4920,6 +5106,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -4930,18 +5125,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"css-selector-tokenizer": "0.7.0",
|
"css-selector-tokenizer": "0.7.0",
|
||||||
"postcss": "6.0.14"
|
"postcss": "6.0.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.16.tgz",
|
||||||
"integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==",
|
"integrity": "sha512-m758RWPmSjFH/2MyyG3UOW1fgYbR9rtdzz5UNJnlm7OLtu4B2h9C6gi+bE4qFKghsBRFfZT8NzoQBs6JhLotoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "2.3.0",
|
"chalk": "2.3.0",
|
||||||
"source-map": "0.6.1",
|
"source-map": "0.6.1",
|
||||||
"supports-color": "4.5.0"
|
"supports-color": "5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -4949,6 +5144,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -4959,18 +5163,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"icss-replace-symbols": "1.1.0",
|
"icss-replace-symbols": "1.1.0",
|
||||||
"postcss": "6.0.14"
|
"postcss": "6.0.16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.16.tgz",
|
||||||
"integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==",
|
"integrity": "sha512-m758RWPmSjFH/2MyyG3UOW1fgYbR9rtdzz5UNJnlm7OLtu4B2h9C6gi+bE4qFKghsBRFfZT8NzoQBs6JhLotoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "2.3.0",
|
"chalk": "2.3.0",
|
||||||
"source-map": "0.6.1",
|
"source-map": "0.6.1",
|
||||||
"supports-color": "4.5.0"
|
"supports-color": "5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
@@ -4978,6 +5182,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5184,7 +5397,7 @@
|
|||||||
"browserify-rsa": "4.0.1",
|
"browserify-rsa": "4.0.1",
|
||||||
"create-hash": "1.1.3",
|
"create-hash": "1.1.3",
|
||||||
"parse-asn1": "5.1.0",
|
"parse-asn1": "5.1.0",
|
||||||
"randombytes": "2.0.5"
|
"randombytes": "2.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
@@ -5262,9 +5475,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"randombytes": {
|
"randombytes": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
|
||||||
"integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
|
"integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
@@ -5274,7 +5487,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz",
|
||||||
"integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==",
|
"integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"randombytes": "2.0.5",
|
"randombytes": "2.0.6",
|
||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5297,9 +5510,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rc": {
|
"rc": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.3.tgz",
|
||||||
"integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=",
|
"integrity": "sha1-UVdakA+N1oOBxxC0cSwhVMPiA1s=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"deep-extend": "0.4.2",
|
"deep-extend": "0.4.2",
|
||||||
@@ -5583,6 +5796,43 @@
|
|||||||
"inherits": "2.0.3"
|
"inherits": "2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rollup": {
|
||||||
|
"version": "0.53.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-0.53.4.tgz",
|
||||||
|
"integrity": "sha512-ErW5cFw5KY/qiyUlPDJ7iBhw51Iro/oyvxETupO85bMg5T7MLlFj3lEDzwjLTOxJAyzWQanUYj/LZHm6aLLm5w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"rollup-plugin-typescript": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup-plugin-typescript/-/rollup-plugin-typescript-0.8.1.tgz",
|
||||||
|
"integrity": "sha1-L/fuzCHPa7K0P8J+W2iJUs5xkko=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"compare-versions": "2.0.1",
|
||||||
|
"object-assign": "4.1.1",
|
||||||
|
"rollup-pluginutils": "1.5.2",
|
||||||
|
"tippex": "2.3.1",
|
||||||
|
"typescript": "1.8.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"typescript": {
|
||||||
|
"version": "1.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz",
|
||||||
|
"integrity": "sha1-tHXW4N/wv1DyluXKbvn7tccyDx4=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rollup-pluginutils": {
|
||||||
|
"version": "1.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz",
|
||||||
|
"integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"estree-walker": "0.2.1",
|
||||||
|
"minimatch": "3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"run-async": {
|
"run-async": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
||||||
@@ -5618,6 +5868,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||||
},
|
},
|
||||||
|
"sander": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sander/-/sander-0.6.0.tgz",
|
||||||
|
"integrity": "sha1-rxYkzX+2362Y6+9WUxn5IAeNqSU=",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.11",
|
||||||
|
"mkdirp": "0.5.1",
|
||||||
|
"rimraf": "2.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sax": {
|
"sax": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
@@ -5645,7 +5905,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "1.1.1",
|
"depd": "1.1.2",
|
||||||
"destroy": "1.0.4",
|
"destroy": "1.0.4",
|
||||||
"encodeurl": "1.0.1",
|
"encodeurl": "1.0.1",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
@@ -5670,6 +5930,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"serialize-javascript": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU="
|
||||||
|
},
|
||||||
"serve-static": {
|
"serve-static": {
|
||||||
"version": "1.13.1",
|
"version": "1.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
|
||||||
@@ -6060,15 +6325,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "1.49.1",
|
"version": "1.51.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-1.49.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-1.51.1.tgz",
|
||||||
"integrity": "sha512-oiB4nF19AAQsD+lvJ1ycb58Iqc1NoZjNvyf0dG+i/RjFU3CLQtCO7pdiJN72IwPYtHAqMRFra/Qkayg8VSFH4A==",
|
"integrity": "sha512-Uf9huHmtXLzdmkfuEYQeXMvFE9dt8M9/jzujX3/Q2Ek2dzvVz1ARTLP76hlnGqUf4q28w8wfkQxFEx4LgDV5MQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"svelte-loader": {
|
"svelte-loader": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-2.3.3.tgz",
|
||||||
"integrity": "sha512-0lIt2GGqHtLETRl8rixXW8Vkij/GnukU+3gZ3Yvww1c2XwVjaucVXQgui5J7bStAtdAmOq+DHjGbwLPsgg47cg==",
|
"integrity": "sha512-OdBoANPvNdP1G3DVzHXdjMetv2kFrv7+R5lhKhcp+E6ew3Gna20+Ja+Sq3gVN9O4vwfhTfrWBhWMFtbfJr1kug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loader-utils": "1.1.0",
|
"loader-utils": "1.1.0",
|
||||||
@@ -6191,6 +6456,12 @@
|
|||||||
"setimmediate": "1.0.5"
|
"setimmediate": "1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tippex": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tippex/-/tippex-2.3.1.tgz",
|
||||||
|
"integrity": "sha1-ov1bcIfXy/sgyYBqbBYQjCwPr9o=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"tmp": {
|
"tmp": {
|
||||||
"version": "0.0.33",
|
"version": "0.0.33",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
@@ -6229,6 +6500,12 @@
|
|||||||
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
|
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz",
|
||||||
|
"integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"tty-browserify": {
|
"tty-browserify": {
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||||
@@ -6275,6 +6552,12 @@
|
|||||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
|
||||||
|
"integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "2.8.29",
|
"version": "2.8.29",
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
||||||
@@ -6430,9 +6713,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wait-on": {
|
"wait-on": {
|
||||||
"version": "2.0.2",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.1.0.tgz",
|
||||||
"integrity": "sha1-CoT9BwJMb8Joyw6r5YW+IXqvK6o=",
|
"integrity": "sha512-hDwJ674+7dfiiK/cxtYCwPxlnjXDjto/pCz1PF02sXUhqCqCWsgvxZln0699PReWqXXgkxqkF6DDo5Rj9sjNvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js": "2.5.3",
|
"core-js": "2.5.3",
|
||||||
@@ -6450,6 +6733,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"walk-sync": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==",
|
||||||
|
"requires": {
|
||||||
|
"ensure-posix-path": "1.0.2",
|
||||||
|
"matcher-collection": "1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"watchpack": {
|
"watchpack": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",
|
||||||
@@ -6465,7 +6757,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",
|
||||||
"integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==",
|
"integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"acorn": "5.2.1",
|
"acorn": "5.3.0",
|
||||||
"acorn-dynamic-import": "2.0.2",
|
"acorn-dynamic-import": "2.0.2",
|
||||||
"ajv": "5.5.2",
|
"ajv": "5.5.2",
|
||||||
"ajv-keywords": "2.1.1",
|
"ajv-keywords": "2.1.1",
|
||||||
|
|||||||
25
package.json
25
package.json
@@ -1,22 +1,36 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.2.10",
|
"version": "0.5.0",
|
||||||
"description": "Military-grade apps, engineered by Svelte",
|
"description": "Military-grade apps, engineered by Svelte",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"sapper": "cli/index.js"
|
"sapper": "cli/index.js"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"cli",
|
||||||
|
"lib",
|
||||||
|
"runtime",
|
||||||
|
"runtime.js",
|
||||||
|
"webpack"
|
||||||
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^2.3.0",
|
"chalk": "^2.3.0",
|
||||||
|
"cheerio": "^1.0.0-rc.2",
|
||||||
"chokidar": "^1.7.0",
|
"chokidar": "^1.7.0",
|
||||||
|
"code-frame": "^5.0.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
|
"locate-character": "^2.0.5",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"relative": "^3.0.2",
|
"relative": "^3.0.2",
|
||||||
"require-relative": "^0.8.7",
|
"require-relative": "^0.8.7",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
|
"sander": "^0.6.0",
|
||||||
|
"serialize-javascript": "^1.4.0",
|
||||||
|
"url-parse": "^1.2.0",
|
||||||
|
"walk-sync": "^0.3.2",
|
||||||
"webpack": "^3.10.0",
|
"webpack": "^3.10.0",
|
||||||
"webpack-hot-middleware": "^2.21.0"
|
"webpack-hot-middleware": "^2.21.0"
|
||||||
},
|
},
|
||||||
@@ -30,14 +44,21 @@
|
|||||||
"nightmare": "^2.10.0",
|
"nightmare": "^2.10.0",
|
||||||
"node-fetch": "^1.7.3",
|
"node-fetch": "^1.7.3",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
|
"rollup": "^0.53.0",
|
||||||
|
"rollup-plugin-typescript": "^0.8.1",
|
||||||
"style-loader": "^0.19.1",
|
"style-loader": "^0.19.1",
|
||||||
"svelte": "^1.49.1",
|
"svelte": "^1.49.1",
|
||||||
"svelte-loader": "^2.3.2",
|
"svelte-loader": "^2.3.2",
|
||||||
|
"tslib": "^1.8.1",
|
||||||
|
"typescript": "^2.6.2",
|
||||||
"wait-on": "^2.0.2"
|
"wait-on": "^2.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cy:open": "cypress open",
|
"cy:open": "cypress open",
|
||||||
"test": "mocha --opts mocha.opts"
|
"test": "mocha --opts mocha.opts",
|
||||||
|
"pretest": "npm run build",
|
||||||
|
"build": "rollup -c",
|
||||||
|
"dev": "rollup -cw"
|
||||||
},
|
},
|
||||||
"repository": "https://github.com/sveltejs/sapper",
|
"repository": "https://github.com/sveltejs/sapper",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
17
rollup.config.js
Normal file
17
rollup.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import typescript from 'rollup-plugin-typescript';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// runtime.js
|
||||||
|
{
|
||||||
|
input: 'src/runtime/index.ts',
|
||||||
|
output: {
|
||||||
|
file: 'runtime.js',
|
||||||
|
format: 'es'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
typescript({
|
||||||
|
typescript: require('typescript')
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
213
runtime/app.js
213
runtime/app.js
@@ -1,211 +1,2 @@
|
|||||||
const detach = node => {
|
console.error('sapper/runtime/app.js has been deprecated in favour of sapper/runtime.js');
|
||||||
node.parentNode.removeChild(node);
|
export * from '../runtime.js';
|
||||||
};
|
|
||||||
|
|
||||||
export let component;
|
|
||||||
let target;
|
|
||||||
let routes;
|
|
||||||
|
|
||||||
const history = typeof window !== 'undefined' ? window.history : {
|
|
||||||
pushState: () => {},
|
|
||||||
replaceState: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const scroll_history = {};
|
|
||||||
let uid = 1;
|
|
||||||
let cid;
|
|
||||||
|
|
||||||
if ('scrollRestoration' in history) {
|
|
||||||
history.scrollRestoration = 'manual';
|
|
||||||
}
|
|
||||||
|
|
||||||
function select_route(url) {
|
|
||||||
if (url.origin !== window.location.origin) return null;
|
|
||||||
|
|
||||||
for (const route of routes) {
|
|
||||||
const match = route.pattern.exec(url.pathname);
|
|
||||||
if (match) {
|
|
||||||
const params = route.params(match);
|
|
||||||
|
|
||||||
const query = {};
|
|
||||||
for (const [key, value] of url.searchParams) query[key] = value || true;
|
|
||||||
|
|
||||||
return { route, data: { params, query } };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function render(Component, data, scroll) {
|
|
||||||
Promise.resolve(
|
|
||||||
Component.preload ? Component.preload(data) : {}
|
|
||||||
).then(preloaded => {
|
|
||||||
if (component) {
|
|
||||||
component.destroy();
|
|
||||||
} else {
|
|
||||||
// first load — remove SSR'd <head> contents
|
|
||||||
const start = document.querySelector('#sapper-head-start');
|
|
||||||
const end = document.querySelector('#sapper-head-end');
|
|
||||||
|
|
||||||
if (start && end) {
|
|
||||||
while (start.nextSibling !== end) detach(start.nextSibling);
|
|
||||||
detach(start);
|
|
||||||
detach(end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// preload additional routes
|
|
||||||
routes.reduce((promise, route) => promise.then(route.load), Promise.resolve());
|
|
||||||
}
|
|
||||||
|
|
||||||
component = new Component({
|
|
||||||
target,
|
|
||||||
data: Object.assign(data, preloaded),
|
|
||||||
hydrate: !!component
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scroll) {
|
|
||||||
window.scrollTo(scroll.x, scroll.y);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigate(url, id) {
|
|
||||||
const selected = select_route(url);
|
|
||||||
if (selected) {
|
|
||||||
if (id) {
|
|
||||||
// popstate or initial navigation
|
|
||||||
cid = id;
|
|
||||||
} else {
|
|
||||||
// clicked on a link. preserve scroll state
|
|
||||||
scroll_history[cid] = scroll_state();
|
|
||||||
|
|
||||||
id = cid = ++uid;
|
|
||||||
scroll_history[cid] = { x: 0, y: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
selected.route.load().then(mod => {
|
|
||||||
render(mod.default, selected.data, scroll_history[id]);
|
|
||||||
});
|
|
||||||
|
|
||||||
cid = id;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_click(event) {
|
|
||||||
// Adapted from https://github.com/visionmedia/page.js
|
|
||||||
// MIT license https://github.com/visionmedia/page.js#license
|
|
||||||
if (which(event) !== 1) return;
|
|
||||||
if (event.metaKey || event.ctrlKey || event.shiftKey) return;
|
|
||||||
if (event.defaultPrevented) return;
|
|
||||||
|
|
||||||
const a = findAnchor(event.target);
|
|
||||||
if (!a) return;
|
|
||||||
|
|
||||||
// check if link is inside an svg
|
|
||||||
// in this case, both href and target are always inside an object
|
|
||||||
const svg = typeof a.href === 'object' && a.href.constructor.name === 'SVGAnimatedString';
|
|
||||||
const href = svg ? a.href.baseVal : a.href;
|
|
||||||
|
|
||||||
if (href === window.location.href) {
|
|
||||||
event.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore if tag has
|
|
||||||
// 1. 'download' attribute
|
|
||||||
// 2. rel='external' attribute
|
|
||||||
if (a.hasAttribute('download') || a.getAttribute('rel') === 'external') return;
|
|
||||||
|
|
||||||
// Ignore if <a> has a target
|
|
||||||
if (svg ? a.target.baseVal : a.target) return;
|
|
||||||
|
|
||||||
const url = new URL(href);
|
|
||||||
|
|
||||||
// Don't handle hash changes
|
|
||||||
if (url.pathname === window.location.pathname && url.search === window.location.search) return;
|
|
||||||
|
|
||||||
if (navigate(url, null)) {
|
|
||||||
event.preventDefault();
|
|
||||||
history.pushState({ id: cid }, '', url.href);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_popstate(event) {
|
|
||||||
scroll_history[cid] = scroll_state();
|
|
||||||
|
|
||||||
if (event.state) {
|
|
||||||
navigate(new URL(window.location), event.state.id);
|
|
||||||
} else {
|
|
||||||
// hashchange
|
|
||||||
cid = ++uid;
|
|
||||||
history.replaceState({ id: cid }, '', window.location.href);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function prefetch(event) {
|
|
||||||
const a = findAnchor(event.target);
|
|
||||||
if (!a || a.rel !== 'prefetch') return;
|
|
||||||
|
|
||||||
const selected = select_route(new URL(a.href));
|
|
||||||
|
|
||||||
if (selected) {
|
|
||||||
selected.route.load().then(mod => {
|
|
||||||
if (mod.default.preload) mod.default.preload(selected.data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findAnchor(node) {
|
|
||||||
while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG <a> elements have a lowercase name
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
let inited;
|
|
||||||
|
|
||||||
export function init(_target, _routes) {
|
|
||||||
target = _target;
|
|
||||||
routes = _routes;
|
|
||||||
|
|
||||||
if (!inited) { // this check makes HMR possible
|
|
||||||
window.addEventListener('click', handle_click);
|
|
||||||
window.addEventListener('popstate', handle_popstate);
|
|
||||||
|
|
||||||
// prefetch
|
|
||||||
window.addEventListener('touchstart', prefetch);
|
|
||||||
window.addEventListener('mouseover', prefetch);
|
|
||||||
|
|
||||||
inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const { hash, href } = window.location;
|
|
||||||
|
|
||||||
const deep_linked = hash && document.querySelector(hash);
|
|
||||||
scroll_history[uid] = deep_linked ?
|
|
||||||
{ x: 0, y: deep_linked.getBoundingClientRect().top } :
|
|
||||||
scroll_state();
|
|
||||||
|
|
||||||
history.replaceState({ id: uid }, '', href);
|
|
||||||
navigate(new URL(window.location), uid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function which(event) {
|
|
||||||
event = event || window.event;
|
|
||||||
return event.which === null ? event.button : event.which;
|
|
||||||
}
|
|
||||||
|
|
||||||
function scroll_state() {
|
|
||||||
return {
|
|
||||||
x: window.scrollX,
|
|
||||||
y: window.scrollY
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function goto(href, opts = {}) {
|
|
||||||
if (navigate(new URL(href, window.location.href))) {
|
|
||||||
if (history) history[opts.replaceState ? 'replaceState' : 'pushState']({ id: cid }, '', href);
|
|
||||||
} else {
|
|
||||||
window.location.href = href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
227
src/runtime/index.ts
Normal file
227
src/runtime/index.ts
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import { detach, findAnchor, scroll_state, which } from './utils';
|
||||||
|
import { Component, ComponentConstructor, Params, Query, Route, RouteData, ScrollPosition } from './interfaces';
|
||||||
|
|
||||||
|
export let component: Component;
|
||||||
|
let target: Node;
|
||||||
|
let routes: Route[];
|
||||||
|
|
||||||
|
const history = typeof window !== 'undefined' ? window.history : {
|
||||||
|
pushState: (state: any, title: string, href: string) => {},
|
||||||
|
replaceState: (state: any, title: string, href: string) => {},
|
||||||
|
scrollRestoration: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
const scroll_history: Record<string, ScrollPosition> = {};
|
||||||
|
let uid = 1;
|
||||||
|
let cid: number;
|
||||||
|
|
||||||
|
if ('scrollRestoration' in history) {
|
||||||
|
history.scrollRestoration = 'manual';
|
||||||
|
}
|
||||||
|
|
||||||
|
function select_route(url: URL): { route: Route, data: RouteData } {
|
||||||
|
if (url.origin !== window.location.origin) return null;
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
const match = route.pattern.exec(url.pathname);
|
||||||
|
if (match) {
|
||||||
|
const params = route.params(match);
|
||||||
|
|
||||||
|
const query: Record<string, string | true> = {};
|
||||||
|
for (const [key, value] of url.searchParams) query[key] = value || true;
|
||||||
|
|
||||||
|
return { route, data: { params, query } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_token: {};
|
||||||
|
|
||||||
|
function render(Component: ComponentConstructor, data: any, scroll: ScrollPosition, token: {}) {
|
||||||
|
if (current_token !== token) return;
|
||||||
|
|
||||||
|
if (component) {
|
||||||
|
component.destroy();
|
||||||
|
} else {
|
||||||
|
// first load — remove SSR'd <head> contents
|
||||||
|
const start = document.querySelector('#sapper-head-start');
|
||||||
|
const end = document.querySelector('#sapper-head-end');
|
||||||
|
|
||||||
|
if (start && end) {
|
||||||
|
while (start.nextSibling !== end) detach(start.nextSibling);
|
||||||
|
detach(start);
|
||||||
|
detach(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// preload additional routes
|
||||||
|
routes.reduce((promise: Promise<any>, route) => promise.then(route.load), Promise.resolve());
|
||||||
|
}
|
||||||
|
|
||||||
|
component = new Component({
|
||||||
|
target,
|
||||||
|
data,
|
||||||
|
hydrate: !!component
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scroll) {
|
||||||
|
window.scrollTo(scroll.x, scroll.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepare_route(Component: ComponentConstructor, data: RouteData) {
|
||||||
|
if (!Component.preload) {
|
||||||
|
return { Component, data };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!component && window.__SAPPER__ && window.__SAPPER__.preloaded) {
|
||||||
|
return { Component, data: Object.assign(data, window.__SAPPER__.preloaded) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(Component.preload(data)).then(preloaded => {
|
||||||
|
Object.assign(data, preloaded)
|
||||||
|
return { Component, data };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigate(url: URL, id: number) {
|
||||||
|
const selected = select_route(url);
|
||||||
|
if (selected) {
|
||||||
|
if (id) {
|
||||||
|
// popstate or initial navigation
|
||||||
|
cid = id;
|
||||||
|
} else {
|
||||||
|
// clicked on a link. preserve scroll state
|
||||||
|
scroll_history[cid] = scroll_state();
|
||||||
|
|
||||||
|
id = cid = ++uid;
|
||||||
|
scroll_history[cid] = { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const loaded = prefetching && prefetching.href === url.href ?
|
||||||
|
prefetching.promise :
|
||||||
|
selected.route.load().then(mod => prepare_route(mod.default, selected.data));
|
||||||
|
|
||||||
|
prefetching = null;
|
||||||
|
|
||||||
|
const token = current_token = {};
|
||||||
|
|
||||||
|
loaded.then(({ Component, data }) => {
|
||||||
|
render(Component, data, scroll_history[id], token);
|
||||||
|
});
|
||||||
|
|
||||||
|
cid = id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_click(event: MouseEvent) {
|
||||||
|
// Adapted from https://github.com/visionmedia/page.js
|
||||||
|
// MIT license https://github.com/visionmedia/page.js#license
|
||||||
|
if (which(event) !== 1) return;
|
||||||
|
if (event.metaKey || event.ctrlKey || event.shiftKey) return;
|
||||||
|
if (event.defaultPrevented) return;
|
||||||
|
|
||||||
|
const a: HTMLAnchorElement | SVGAElement = <HTMLAnchorElement | SVGAElement>findAnchor(<Node>event.target);
|
||||||
|
if (!a) return;
|
||||||
|
|
||||||
|
// check if link is inside an svg
|
||||||
|
// in this case, both href and target are always inside an object
|
||||||
|
const svg = typeof a.href === 'object' && a.href.constructor.name === 'SVGAnimatedString';
|
||||||
|
const href = String(svg ? (<SVGAElement>a).href.baseVal : a.href);
|
||||||
|
|
||||||
|
if (href === window.location.href) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if tag has
|
||||||
|
// 1. 'download' attribute
|
||||||
|
// 2. rel='external' attribute
|
||||||
|
if (a.hasAttribute('download') || a.getAttribute('rel') === 'external') return;
|
||||||
|
|
||||||
|
// Ignore if <a> has a target
|
||||||
|
if (svg ? (<SVGAElement>a).target.baseVal : a.target) return;
|
||||||
|
|
||||||
|
const url = new URL(href);
|
||||||
|
|
||||||
|
// Don't handle hash changes
|
||||||
|
if (url.pathname === window.location.pathname && url.search === window.location.search) return;
|
||||||
|
|
||||||
|
if (navigate(url, null)) {
|
||||||
|
event.preventDefault();
|
||||||
|
history.pushState({ id: cid }, '', url.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_popstate(event: PopStateEvent) {
|
||||||
|
scroll_history[cid] = scroll_state();
|
||||||
|
|
||||||
|
if (event.state) {
|
||||||
|
navigate(new URL(window.location.href), event.state.id);
|
||||||
|
} else {
|
||||||
|
// hashchange
|
||||||
|
cid = ++uid;
|
||||||
|
history.replaceState({ id: cid }, '', window.location.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefetching: {
|
||||||
|
href: string;
|
||||||
|
promise: Promise<{ Component: ComponentConstructor, data: any }>;
|
||||||
|
} = null;
|
||||||
|
|
||||||
|
export function prefetch(href: string) {
|
||||||
|
const selected = select_route(new URL(href));
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
prefetching = {
|
||||||
|
href,
|
||||||
|
promise: selected.route.load().then(mod => prepare_route(mod.default, selected.data))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_touchstart_mouseover(event: MouseEvent | TouchEvent) {
|
||||||
|
const a: HTMLAnchorElement = <HTMLAnchorElement>findAnchor(<Node>event.target);
|
||||||
|
if (!a || a.rel !== 'prefetch') return;
|
||||||
|
|
||||||
|
prefetch(a.href);
|
||||||
|
}
|
||||||
|
|
||||||
|
let inited: boolean;
|
||||||
|
|
||||||
|
export function init(_target: Node, _routes: Route[]) {
|
||||||
|
target = _target;
|
||||||
|
routes = _routes;
|
||||||
|
|
||||||
|
if (!inited) { // this check makes HMR possible
|
||||||
|
window.addEventListener('click', handle_click);
|
||||||
|
window.addEventListener('popstate', handle_popstate);
|
||||||
|
|
||||||
|
// prefetch
|
||||||
|
window.addEventListener('touchstart', handle_touchstart_mouseover);
|
||||||
|
window.addEventListener('mouseover', handle_touchstart_mouseover);
|
||||||
|
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const { hash, href } = window.location;
|
||||||
|
|
||||||
|
const deep_linked = hash && document.querySelector(hash);
|
||||||
|
scroll_history[uid] = deep_linked ?
|
||||||
|
{ x: 0, y: deep_linked.getBoundingClientRect().top } :
|
||||||
|
scroll_state();
|
||||||
|
|
||||||
|
history.replaceState({ id: uid }, '', href);
|
||||||
|
navigate(new URL(window.location.href), uid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goto(href: string, opts = { replaceState: false }) {
|
||||||
|
if (navigate(new URL(href, window.location.href), null)) {
|
||||||
|
if (history) history[opts.replaceState ? 'replaceState' : 'pushState']({ id: cid }, '', href);
|
||||||
|
} else {
|
||||||
|
window.location.href = href;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/runtime/interfaces.ts
Normal file
23
src/runtime/interfaces.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export type Params = Record<string, string>;
|
||||||
|
export type Query = Record<string, string | true>;
|
||||||
|
export type RouteData = { params: Params, query: Query };
|
||||||
|
|
||||||
|
export interface ComponentConstructor {
|
||||||
|
new (options: { target: Node, data: any, hydrate: boolean }): Component;
|
||||||
|
preload: (data: { params: Params, query: Query }) => Promise<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface Component {
|
||||||
|
destroy: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Route = {
|
||||||
|
pattern: RegExp;
|
||||||
|
params: (match: RegExpExecArray) => Record<string, string>;
|
||||||
|
load: () => Promise<{ default: ComponentConstructor }>
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ScrollPosition = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
19
src/runtime/utils.ts
Normal file
19
src/runtime/utils.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export function detach(node: Node) {
|
||||||
|
node.parentNode.removeChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findAnchor(node: Node) {
|
||||||
|
while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG <a> elements have a lowercase name
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function which(event: MouseEvent) {
|
||||||
|
return event.which === null ? event.button : event.which;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scroll_state() {
|
||||||
|
return {
|
||||||
|
x: window.scrollX,
|
||||||
|
y: window.scrollY
|
||||||
|
};
|
||||||
|
}
|
||||||
1
test/app/.gitignore
vendored
1
test/app/.gitignore
vendored
@@ -4,3 +4,4 @@ node_modules
|
|||||||
yarn.lock
|
yarn.lock
|
||||||
cypress/screenshots
|
cypress/screenshots
|
||||||
templates/.*
|
templates/.*
|
||||||
|
dist
|
||||||
|
|||||||
6
test/app/package-lock.json
generated
6
test/app/package-lock.json
generated
@@ -2722,9 +2722,9 @@
|
|||||||
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
|
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
|
||||||
},
|
},
|
||||||
"marked": {
|
"marked": {
|
||||||
"version": "0.3.7",
|
"version": "0.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.9.tgz",
|
||||||
"integrity": "sha512-zBEP4qO1YQp5aXHt8S5wTiOv9i2X74V/LQL0zhUNvVaklt6Ywa6lChxIvS+ibYlCGgADwKwZFhjC3+XfpsvQvQ=="
|
"integrity": "sha512-nW5u0dxpXxHfkHzzrveY45gCbi+R4PaO4WRZYqZNl+vB0hVGeqlFn0aOg1c8AKL63TrNFn9Bm2UP4AdiZ9TPLw=="
|
||||||
},
|
},
|
||||||
"math-expression-evaluator": {
|
"math-expression-evaluator": {
|
||||||
"version": "1.2.17",
|
"version": "1.2.17",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"express": "^4.16.2",
|
"express": "^4.16.2",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"marked": "^0.3.7",
|
"marked": "^0.3.9",
|
||||||
"node-fetch": "^1.7.3",
|
"node-fetch": "^1.7.3",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"serve-static": "^1.13.1",
|
"serve-static": "^1.13.1",
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class='{{page === "home" ? "selected" : ""}}' href='/'>home</a></li>
|
<li><a href='/'>home</a></li>
|
||||||
<li><a class='{{page === "about" ? "selected" : ""}}' href='/about'>about</a></li>
|
<li><a href='/about'>about</a></li>
|
||||||
|
<li><a href='/slow-preload'>slow preload</a></li>
|
||||||
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
|
|
||||||
the blog data when we hover over the link or tap it on a touchscreen -->
|
|
||||||
<li><a rel=prefetch class='{{page === "blog" ? "selected" : ""}}' href='/blog'>blog</a></li>
|
<li><a rel=prefetch class='{{page === "blog" ? "selected" : ""}}' href='/blog'>blog</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
|
|
||||||
<p>This is the 'about' page. There's not much here.</p>
|
<p>This is the 'about' page. There's not much here.</p>
|
||||||
|
|
||||||
<button on:click='goto("/blog/what-is-sapper")'>What is Sapper?</button>
|
<button class='goto' on:click='goto("/blog/what-is-sapper")'>What is Sapper?</button>
|
||||||
|
<button class='prefetch' on:click='goto("/blog/why-the-name")'>Why the name?</button>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Layout from './_components/Layout.html';
|
import Layout from './_components/Layout.html';
|
||||||
import { goto } from '../../../runtime/app.js';
|
import { goto, prefetch } from '../../../runtime.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -20,7 +21,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
goto
|
goto,
|
||||||
|
prefetch
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -13,7 +13,7 @@ export function get(req, res, next) {
|
|||||||
if (slug in lookup) {
|
if (slug in lookup) {
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Cache-Control': `max-age=${30 * 60 * 1e3}` // cache for 30 minutes
|
'Cache-Control': `no-cache`
|
||||||
});
|
});
|
||||||
|
|
||||||
res.end(lookup[slug]);
|
res.end(lookup[slug]);
|
||||||
|
|||||||
9
test/app/routes/api/delete/[id].js
Normal file
9
test/app/routes/api/delete/[id].js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function del(req, res) {
|
||||||
|
res.set({
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
id: req.params.id
|
||||||
|
}));
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
preload({ params, query }) {
|
preload({ params, query }) {
|
||||||
return fetch(`/api/blog`).then(r => r.json()).then(posts => {
|
return fetch(`/api/blog/contents`).then(r => r.json()).then(posts => {
|
||||||
return { posts };
|
return { posts };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
15
test/app/routes/delete-test.html
Normal file
15
test/app/routes/delete-test.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<button class='del' on:click='del()'>delete</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
del() {
|
||||||
|
fetch(`/api/delete/42`, { method: 'DELETE' })
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
window.deleted = data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
9
test/app/routes/show-url.html
Normal file
9
test/app/routes/show-url.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<p>URL is {{url}}</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
preload({ url }) {
|
||||||
|
if (url) return { url };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
11
test/app/routes/slow-preload.html
Normal file
11
test/app/routes/slow-preload.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<h1>This page should never render</h1>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
preload() {
|
||||||
|
return new Promise(fulfil => {
|
||||||
|
window.fulfil = fulfil;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -32,6 +32,6 @@
|
|||||||
<!-- Sapper creates a <script> tag containing `templates/main.js`
|
<!-- Sapper creates a <script> tag containing `templates/main.js`
|
||||||
and anything else it needs to hydrate the app and
|
and anything else it needs to hydrate the app and
|
||||||
initialise the router -->
|
initialise the router -->
|
||||||
<script src='%sapper.main%'></script>
|
%sapper.scripts%
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { init } from '../../../runtime/app.js';
|
import { init } from '../../../runtime.js';
|
||||||
|
|
||||||
// `routes` is an array of route objects injected by Sapper
|
// `routes` is an array of route objects injected by Sapper
|
||||||
init(document.querySelector('#sapper'), __routes__);
|
init(document.querySelector('#sapper'), __routes__);
|
||||||
|
|||||||
@@ -5,13 +5,20 @@ const serve = require('serve-static');
|
|||||||
const Nightmare = require('nightmare');
|
const Nightmare = require('nightmare');
|
||||||
const getPort = require('get-port');
|
const getPort = require('get-port');
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
|
const walkSync = require('walk-sync');
|
||||||
|
|
||||||
run('production');
|
run('production');
|
||||||
run('development');
|
run('development');
|
||||||
|
|
||||||
|
Nightmare.action('page', {
|
||||||
|
title(done) {
|
||||||
|
this.evaluate_now(() => document.querySelector('h1').textContent, done);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function run(env) {
|
function run(env) {
|
||||||
describe(`env=${env}`, function () {
|
describe(`env=${env}`, function () {
|
||||||
this.timeout(5000);
|
this.timeout(20000);
|
||||||
|
|
||||||
let PORT;
|
let PORT;
|
||||||
let server;
|
let server;
|
||||||
@@ -62,52 +69,60 @@ function run(env) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async () => {
|
before(() => {
|
||||||
process.chdir(path.resolve(__dirname, '../app'));
|
process.chdir(path.resolve(__dirname, '../app'));
|
||||||
|
|
||||||
process.env.NODE_ENV = env;
|
process.env.NODE_ENV = env;
|
||||||
|
|
||||||
|
let exec_promise = Promise.resolve();
|
||||||
|
let sapper;
|
||||||
|
|
||||||
if (env === 'production') {
|
if (env === 'production') {
|
||||||
const cli = path.resolve(__dirname, '../../cli/index.js');
|
const cli = path.resolve(__dirname, '../../cli/index.js');
|
||||||
await exec(`${cli} build`);
|
exec_promise = exec(`${cli} build`).then(() => exec(`${cli} export`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolved = require.resolve('../..');
|
return exec_promise.then(() => {
|
||||||
delete require.cache[resolved];
|
const resolved = require.resolve('../..');
|
||||||
const sapper = require(resolved);
|
delete require.cache[resolved];
|
||||||
|
sapper = require(resolved);
|
||||||
|
|
||||||
PORT = await getPort();
|
return getPort();
|
||||||
base = `http://localhost:${PORT}`;
|
}).then(port => {
|
||||||
|
PORT = port;
|
||||||
|
base = `http://localhost:${PORT}`;
|
||||||
|
|
||||||
global.fetch = (url, opts) => {
|
global.fetch = (url, opts) => {
|
||||||
if (url[0] === '/') url = `${base}${url}`;
|
if (url[0] === '/') url = `${base}${url}`;
|
||||||
return fetch(url, opts);
|
return fetch(url, opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
let captured;
|
let captured;
|
||||||
capture = async fn => {
|
capture = fn => {
|
||||||
const result = captured = [];
|
const result = captured = [];
|
||||||
await fn();
|
return fn().then(() => {
|
||||||
captured = null;
|
captured = null;
|
||||||
return result;
|
return result;
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(serve('assets'));
|
app.use(serve('assets'));
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
if (captured) captured.push(req);
|
if (captured) captured.push(req);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
middleware = sapper();
|
middleware = sapper();
|
||||||
app.use(middleware);
|
app.use(middleware);
|
||||||
|
|
||||||
return new Promise((fulfil, reject) => {
|
return new Promise((fulfil, reject) => {
|
||||||
server = app.listen(PORT, err => {
|
server = app.listen(PORT, err => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
else fulfil();
|
else fulfil();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -137,108 +152,265 @@ function run(env) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(() => {
|
||||||
await nightmare.end();
|
return nightmare.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serves /', async () => {
|
it('serves /', () => {
|
||||||
const title = await nightmare
|
return nightmare.goto(base).page.title().then(title => {
|
||||||
.goto(base)
|
assert.equal(title, 'Great success!');
|
||||||
.evaluate(() => document.querySelector('h1').textContent);
|
|
||||||
|
|
||||||
assert.equal(title, 'Great success!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('serves static route', async () => {
|
|
||||||
const title = await nightmare
|
|
||||||
.goto(`${base}/about`)
|
|
||||||
.evaluate(() => document.querySelector('h1').textContent);
|
|
||||||
|
|
||||||
assert.equal(title, 'About this site');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('serves dynamic route', async () => {
|
|
||||||
const title = await nightmare
|
|
||||||
.goto(`${base}/blog/what-is-sapper`)
|
|
||||||
.evaluate(() => document.querySelector('h1').textContent);
|
|
||||||
|
|
||||||
assert.equal(title, 'What is Sapper?');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('navigates to a new page without reloading', async () => {
|
|
||||||
await nightmare.goto(base).wait(() => window.READY).wait(100);
|
|
||||||
|
|
||||||
const requests = await capture(async () => {
|
|
||||||
await nightmare.click('a[href="/about"]');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
await nightmare.path(),
|
|
||||||
'/about'
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
await nightmare.evaluate(() => document.title),
|
|
||||||
'About'
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(requests.map(r => r.url), []);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates programmatically', async () => {
|
it('serves static route', () => {
|
||||||
await nightmare
|
return nightmare.goto(`${base}/about`).page.title().then(title => {
|
||||||
|
assert.equal(title, 'About this site');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serves dynamic route', () => {
|
||||||
|
return nightmare.goto(`${base}/blog/what-is-sapper`).page.title().then(title => {
|
||||||
|
assert.equal(title, 'What is Sapper?');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('navigates to a new page without reloading', () => {
|
||||||
|
return nightmare.goto(base).wait(() => window.READY).wait(200)
|
||||||
|
.then(() => {
|
||||||
|
return capture(() => nightmare.click('a[href="/about"]'));
|
||||||
|
})
|
||||||
|
.then(requests => {
|
||||||
|
assert.deepEqual(requests.map(r => r.url), []);
|
||||||
|
return nightmare.path();
|
||||||
|
})
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, '/about');
|
||||||
|
return nightmare.title();
|
||||||
|
})
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'About');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('navigates programmatically', () => {
|
||||||
|
return nightmare
|
||||||
.goto(`${base}/about`)
|
.goto(`${base}/about`)
|
||||||
.wait(() => window.READY)
|
.wait(() => window.READY)
|
||||||
.click('button')
|
.click('.goto')
|
||||||
.wait(() => window.location.pathname === '/blog/what-is-sapper')
|
.wait(() => window.location.pathname === '/blog/what-is-sapper')
|
||||||
.wait(100);
|
.wait(100)
|
||||||
|
.title()
|
||||||
assert.equal(
|
.then(title => {
|
||||||
await nightmare.evaluate(() => document.title),
|
assert.equal(title, 'What is Sapper?');
|
||||||
'What is Sapper?'
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('scrolls to active deeplink', async () => {
|
it('prefetches programmatically', () => {
|
||||||
const scrollY = await nightmare
|
return nightmare
|
||||||
|
.goto(`${base}/about`)
|
||||||
|
.wait(() => window.READY)
|
||||||
|
.then(() => {
|
||||||
|
return capture(() => {
|
||||||
|
return nightmare
|
||||||
|
.click('.prefetch')
|
||||||
|
.wait(100);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(requests => {
|
||||||
|
assert.ok(!!requests.find(r => r.url === '/api/blog/why-the-name'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('scrolls to active deeplink', () => {
|
||||||
|
return nightmare
|
||||||
.goto(`${base}/blog/a-very-long-post#four`)
|
.goto(`${base}/blog/a-very-long-post#four`)
|
||||||
.wait(() => window.READY)
|
.wait(() => window.READY)
|
||||||
.wait(100)
|
.wait(100)
|
||||||
.evaluate(() => window.scrollY);
|
.evaluate(() => window.scrollY)
|
||||||
|
.then(scrollY => {
|
||||||
|
assert.ok(scrollY > 0, scrollY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
assert.ok(scrollY > 0, scrollY);
|
it('reuses prefetch promise', () => {
|
||||||
|
return nightmare
|
||||||
|
.goto(`${base}/blog`)
|
||||||
|
.wait(() => window.READY)
|
||||||
|
.wait(200)
|
||||||
|
.then(() => {
|
||||||
|
return capture(() => {
|
||||||
|
return nightmare
|
||||||
|
.mouseover('[href="/blog/what-is-sapper"]')
|
||||||
|
.wait(200);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(mouseover_requests => {
|
||||||
|
assert.deepEqual(mouseover_requests.map(r => r.url), [
|
||||||
|
'/api/blog/what-is-sapper'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return capture(() => {
|
||||||
|
return nightmare
|
||||||
|
.click('[href="/blog/what-is-sapper"]')
|
||||||
|
.wait(200);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(click_requests => {
|
||||||
|
assert.deepEqual(click_requests.map(r => r.url), []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cancels navigation if subsequent navigation occurs during preload', () => {
|
||||||
|
return nightmare
|
||||||
|
.goto(base)
|
||||||
|
.wait(() => window.READY)
|
||||||
|
.click('a[href="/slow-preload"]')
|
||||||
|
.wait(100)
|
||||||
|
.click('a[href="/about"]')
|
||||||
|
.wait(100)
|
||||||
|
.then(() => nightmare.path())
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, '/about');
|
||||||
|
return nightmare.title();
|
||||||
|
})
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'About');
|
||||||
|
return nightmare.evaluate(() => window.fulfil({})).wait(100);
|
||||||
|
})
|
||||||
|
.then(() => nightmare.path())
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, '/about');
|
||||||
|
return nightmare.title();
|
||||||
|
})
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'About');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes entire request object to preload', () => {
|
||||||
|
return nightmare
|
||||||
|
.goto(`${base}/show-url`)
|
||||||
|
.wait(() => window.READY)
|
||||||
|
.evaluate(() => document.querySelector('p').innerHTML)
|
||||||
|
.end().then(html => {
|
||||||
|
assert.equal(html, `URL is /show-url`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls a delete handler', () => {
|
||||||
|
return nightmare
|
||||||
|
.goto(`${base}/delete-test`)
|
||||||
|
.wait(() => window.READY)
|
||||||
|
.click('.del')
|
||||||
|
.wait(() => window.deleted)
|
||||||
|
.evaluate(() => window.deleted.id)
|
||||||
|
.then(id => {
|
||||||
|
assert.equal(id, 42);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('headers', () => {
|
describe('headers', () => {
|
||||||
it('sets Content-Type and Link...preload headers', async () => {
|
it('sets Content-Type and Link...preload headers', () => {
|
||||||
const { headers } = await get('/');
|
return get('/').then(({ headers }) => {
|
||||||
|
assert.equal(
|
||||||
|
headers['Content-Type'],
|
||||||
|
'text/html'
|
||||||
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.ok(
|
||||||
headers['Content-Type'],
|
/<\/client\/main.\w+\.js>;rel="preload";as="script", <\/client\/_.\d+.\w+.js>;rel="preload";as="script"/.test(headers['Link']),
|
||||||
'text/html'
|
headers['Link']
|
||||||
);
|
);
|
||||||
|
});
|
||||||
assert.ok(
|
|
||||||
/<\/client\/main.\w+\.js>;rel="preload";as="script", <\/client\/_.\d+.\w+.js>;rel="preload";as="script"/.test(headers['Link']),
|
|
||||||
headers['Link']
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (env === 'production') {
|
||||||
|
describe('export', () => {
|
||||||
|
it('export all pages', () => {
|
||||||
|
const dest = path.resolve(__dirname, '../app/dist');
|
||||||
|
|
||||||
|
// Pages that should show up in the extraction directory.
|
||||||
|
const expectedPages = [
|
||||||
|
'index.html',
|
||||||
|
'about/index.html',
|
||||||
|
'slow-preload/index.html',
|
||||||
|
|
||||||
|
'blog/index.html',
|
||||||
|
'blog/a-very-long-post/index.html',
|
||||||
|
'blog/how-can-i-get-involved/index.html',
|
||||||
|
'blog/how-is-sapper-different-from-next/index.html',
|
||||||
|
'blog/how-to-use-sapper/index.html',
|
||||||
|
'blog/what-is-sapper/index.html',
|
||||||
|
'blog/why-the-name/index.html',
|
||||||
|
|
||||||
|
'api/blog/contents',
|
||||||
|
'api/blog/a-very-long-post',
|
||||||
|
'api/blog/how-can-i-get-involved',
|
||||||
|
'api/blog/how-is-sapper-different-from-next',
|
||||||
|
'api/blog/how-to-use-sapper',
|
||||||
|
'api/blog/what-is-sapper',
|
||||||
|
'api/blog/why-the-name',
|
||||||
|
|
||||||
|
'favicon.png',
|
||||||
|
'global.css',
|
||||||
|
'great-success.png',
|
||||||
|
'manifest.json',
|
||||||
|
'service-worker.js',
|
||||||
|
'svelte-logo-192.png',
|
||||||
|
'svelte-logo-512.png',
|
||||||
|
];
|
||||||
|
// Client scripts that should show up in the extraction directory.
|
||||||
|
const expectedClientRegexes = [
|
||||||
|
/client\/_\..*?\.js/,
|
||||||
|
/client\/about\..*?\.js/,
|
||||||
|
/client\/blog_\$slug\$\..*?\.js/,
|
||||||
|
/client\/blog\..*?\.js/,
|
||||||
|
/client\/main\..*?\.js/,
|
||||||
|
/client\/show_url\..*?\.js/,
|
||||||
|
/client\/slow_preload\..*?\.js/,
|
||||||
|
];
|
||||||
|
const allPages = walkSync(dest);
|
||||||
|
|
||||||
|
expectedPages.forEach((expectedPage) => {
|
||||||
|
assert.ok(allPages.includes(expectedPage),
|
||||||
|
`Could not find page matching ${expectedPage}`);
|
||||||
|
});
|
||||||
|
expectedClientRegexes.forEach((expectedRegex) => {
|
||||||
|
// Ensure each client page regular expression matches at least one
|
||||||
|
// generated page.
|
||||||
|
let matched = false;
|
||||||
|
for (const page of allPages) {
|
||||||
|
if (expectedRegex.test(page)) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.ok(matched,
|
||||||
|
`Could not find client page matching ${expectedRegex}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exec(cmd) {
|
function exec(cmd) {
|
||||||
return new Promise((fulfil, reject) => {
|
return new Promise((fulfil, reject) => {
|
||||||
require('child_process').exec(cmd, (err, stdout, stderr) => {
|
const parts = cmd.split(' ');
|
||||||
if (err) {
|
const proc = require('child_process').spawn(parts.shift(), parts);
|
||||||
process.stdout.write(stdout);
|
|
||||||
process.stderr.write(stderr);
|
|
||||||
|
|
||||||
return reject(err);
|
proc.stdout.on('data', data => {
|
||||||
}
|
process.stdout.write(data);
|
||||||
|
|
||||||
fulfil();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
proc.stderr.on('data', data => {
|
||||||
|
process.stderr.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
proc.on('error', reject);
|
||||||
|
|
||||||
|
proc.on('close', () => fulfil());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -10,12 +10,12 @@ describe('create_routes', () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
routes.map(r => r.file),
|
routes.map(r => r.file),
|
||||||
[
|
[
|
||||||
|
'index.html',
|
||||||
|
'about.html',
|
||||||
'post/foo.html',
|
'post/foo.html',
|
||||||
'post/bar.html',
|
'post/bar.html',
|
||||||
'post/[id].html',
|
'post/[id].html',
|
||||||
'about.html',
|
'[wildcard].html'
|
||||||
'[wildcard].html',
|
|
||||||
'index.html'
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -45,8 +45,8 @@ describe('create_routes', () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
routes.map(r => r.file),
|
routes.map(r => r.file),
|
||||||
[
|
[
|
||||||
'e/f/g/h.html',
|
'index.html',
|
||||||
'index.html'
|
'e/f/g/h.html'
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -71,4 +71,44 @@ describe('create_routes', () => {
|
|||||||
create_routes(['[foo].html', '[bar]/index.html']);
|
create_routes(['[foo].html', '[bar]/index.html']);
|
||||||
}, /The \[foo\].html and \[bar\]\/index.html routes clash/);
|
}, /The \[foo\].html and \[bar\]\/index.html routes clash/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('matches nested routes', () => {
|
||||||
|
const route = create_routes(['settings/[submenu].html'])[0];
|
||||||
|
|
||||||
|
assert.deepEqual(route.exec('/settings/foo'), {
|
||||||
|
submenu: 'foo'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(route.exec('/settings'), {
|
||||||
|
submenu: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('prefers index routes to nested routes', () => {
|
||||||
|
const routes = create_routes(['settings/[submenu].html', 'settings.html']);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
routes.map(r => r.file),
|
||||||
|
['settings.html', 'settings/[submenu].html']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('matches deeply nested routes', () => {
|
||||||
|
const route = create_routes(['settings/[a]/[b]/index.html'])[0];
|
||||||
|
|
||||||
|
assert.deepEqual(route.exec('/settings/foo/bar'), {
|
||||||
|
a: 'foo',
|
||||||
|
b: 'bar'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(route.exec('/settings/foo'), {
|
||||||
|
a: 'foo',
|
||||||
|
b: null
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(route.exec('/settings'), {
|
||||||
|
a: null,
|
||||||
|
b: null
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"diagnostics": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"lib": ["es5", "es6", "dom"],
|
||||||
|
"importHelpers": true
|
||||||
|
},
|
||||||
|
"target": "ES5",
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
const path = require('path');
|
const { dest, dev, entry } = require('../lib/config.js');
|
||||||
const { src, dest, dev, entry } = require('../lib/config.js');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
dev,
|
dev,
|
||||||
@@ -7,7 +6,12 @@ module.exports = {
|
|||||||
client: {
|
client: {
|
||||||
entry: () => {
|
entry: () => {
|
||||||
return {
|
return {
|
||||||
main: entry.client
|
main: [
|
||||||
|
entry.client,
|
||||||
|
// workaround for https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/456
|
||||||
|
'style-loader/lib/addStyles',
|
||||||
|
'css-loader/lib/css-base'
|
||||||
|
]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ module.exports = {
|
|||||||
entry: () => {
|
entry: () => {
|
||||||
return {
|
return {
|
||||||
main: entry.server
|
main: entry.server
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
output: () => {
|
output: () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user