mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-13 19:45:26 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
2b3472b1b1 | ||
|
|
ee94f355d5 | ||
|
|
bea9b7965a | ||
|
|
1312aede1f | ||
|
|
50e307e0c0 | ||
|
|
e87ac1f367 | ||
|
|
5da9d0926a |
@@ -3,6 +3,7 @@ sudo: false
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "6"
|
||||
- "stable"
|
||||
|
||||
env:
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,5 +1,17 @@
|
||||
# sapper changelog
|
||||
|
||||
## 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`
|
||||
|
||||
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
|
||||
|
||||
Combat-ready apps, engineered by Svelte.
|
||||
|
||||
## 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
|
||||
[Military-grade progressive web apps, powered by Svelte.](https://sapper.svelte.technology)
|
||||
|
||||
|
||||
## 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;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`listening on port ${PORT}`);
|
||||
});
|
||||
Clone the [starter project template](https://github.com/sveltejs/sapper-template) with [degit](https://github.com/rich-harris/degit)...
|
||||
|
||||
```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...
|
||||
|
||||
|
||||
## Routing
|
||||
|
||||
Like Next, routes are defined by the project directory structure, but with some crucial differences:
|
||||
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
```bash
|
||||
cd my-app
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
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
|
||||
// routes/api/post/[id].js
|
||||
export async function get(req) {
|
||||
return await getPostFromDatabase(req.params.id);
|
||||
}
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
```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.
|
||||
[LIL](LICENSE)
|
||||
163
lib/index.js
163
lib/index.js
@@ -1,5 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const serialize = require('serialize-javascript');
|
||||
const route_manager = require('./route_manager.js');
|
||||
const templates = require('./templates.js');
|
||||
const create_app = require('./utils/create_app.js');
|
||||
@@ -23,9 +24,11 @@ function connect_dev() {
|
||||
heartbeat: 10 * 1000
|
||||
}),
|
||||
|
||||
async (req, res, next) => {
|
||||
asset_cache = await watcher.ready;
|
||||
next();
|
||||
(req, res, next) => {
|
||||
watcher.ready.then(cache => {
|
||||
asset_cache = cache;
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
set_req_pathname,
|
||||
@@ -125,76 +128,98 @@ function get_asset_handler(opts) {
|
||||
};
|
||||
}
|
||||
|
||||
function get_route_handler(fn) {
|
||||
return async function handle_route(req, res, next) {
|
||||
const url = req.pathname;
|
||||
const resolved = Promise.resolve();
|
||||
|
||||
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
|
||||
res.set({
|
||||
'Content-Type': 'text/html'
|
||||
});
|
||||
|
||||
try {
|
||||
for (const route of route_manager.routes) {
|
||||
if (route.test(url)) {
|
||||
req.params = route.exec(url);
|
||||
|
||||
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 => {
|
||||
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;
|
||||
resolved
|
||||
.then(() => {
|
||||
for (const route of route_manager.routes) {
|
||||
if (route.test(url)) return handle_route(route, req, res, next, fn());
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
} catch(err) {
|
||||
res.status(500);
|
||||
res.end(templates.render(500, {
|
||||
title: (err && err.name) || 'Internal server error',
|
||||
url,
|
||||
error: escape_html(err && (err.details || err.message || err) || 'Unknown error'),
|
||||
stack: err && err.stack.split('\n').slice(1).join('\n')
|
||||
}));
|
||||
}
|
||||
// no matching route — 404
|
||||
next();
|
||||
})
|
||||
.catch(err => {
|
||||
res.status(500);
|
||||
res.end(templates.render(500, {
|
||||
title: (err && err.name) || 'Internal server error',
|
||||
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',
|
||||
status: 404,
|
||||
method: req.method,
|
||||
main: asset_cache.client.main_file,
|
||||
scripts: `<script src='${asset_cache.client.main_file}'></script>`,
|
||||
url: req.url
|
||||
}));
|
||||
};
|
||||
@@ -235,4 +260,12 @@ function compose_handlers(handlers) {
|
||||
|
||||
function read_json(file) {
|
||||
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
||||
}
|
||||
|
||||
function try_serialize(data) {
|
||||
try {
|
||||
return serialize(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,22 @@
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
const chalk = require('chalk');
|
||||
const chokidar = require('chokidar');
|
||||
const framer = require('code-frame');
|
||||
const { locate } = require('locate-character');
|
||||
const { dev } = require('./config.js');
|
||||
|
||||
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() {
|
||||
templates = glob.sync('*.html', { cwd: 'templates' })
|
||||
.map(file => {
|
||||
@@ -12,7 +24,24 @@ function create_templates() {
|
||||
const status = file.replace('.html', '').toLowerCase();
|
||||
|
||||
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 = (
|
||||
@@ -31,10 +60,14 @@ function create_templates() {
|
||||
return key in data ? data[key] : '';
|
||||
});
|
||||
},
|
||||
stream: async (res, data) => {
|
||||
stream: (res, data) => {
|
||||
let i = 0;
|
||||
|
||||
do {
|
||||
function stream_inner() {
|
||||
if (i >= template.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const start = template.indexOf('%sapper', i);
|
||||
|
||||
if (start === -1) {
|
||||
@@ -53,9 +86,14 @@ function create_templates() {
|
||||
const match = /sapper\.(\w+)/.exec(tag);
|
||||
if (!match || !(match[1] in data)) throw new Error(`Bad template`); // TODO ditto
|
||||
|
||||
res.write(await data[match[1]]);
|
||||
i = end + 1;
|
||||
} while (i < template.length);
|
||||
return Promise.resolve(data[match[1]]).then(datamatch => {
|
||||
res.write(datamatch);
|
||||
i = end + 1;
|
||||
return stream_inner();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve().then(stream_inner);
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
344
package-lock.json
generated
344
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sapper",
|
||||
"version": "0.2.10",
|
||||
"version": "0.3.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -2114,12 +2114,14 @@
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
|
||||
"integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=",
|
||||
"optional": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "4.11.8",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
|
||||
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"co": "4.6.0",
|
||||
@@ -2128,16 +2130,19 @@
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz",
|
||||
"integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=",
|
||||
"optional": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
|
||||
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"delegates": "1.0.0",
|
||||
@@ -2146,36 +2151,43 @@
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
|
||||
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
|
||||
"optional": true
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "0.2.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
|
||||
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
|
||||
"optional": true
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"optional": true
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
|
||||
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
|
||||
"optional": true
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.6.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
|
||||
"optional": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||
"integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
|
||||
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tweetnacl": "0.14.5"
|
||||
@@ -2183,21 +2195,24 @@
|
||||
},
|
||||
"block-stream": {
|
||||
"version": "0.0.9",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
|
||||
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
|
||||
"requires": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.7",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz",
|
||||
"integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=",
|
||||
"requires": {
|
||||
"balanced-match": "0.4.2",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -2205,51 +2220,61 @@
|
||||
},
|
||||
"buffer-shims": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
|
||||
"integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||
"optional": true
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
|
||||
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
|
||||
"requires": {
|
||||
"delayed-stream": "1.0.0"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"requires": {
|
||||
"boom": "2.10.1"
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
@@ -2257,14 +2282,16 @@
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.8",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
|
||||
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -2272,26 +2299,31 @@
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.4.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
|
||||
"integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=",
|
||||
"optional": true
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"optional": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.2.tgz",
|
||||
"integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE=",
|
||||
"optional": true
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "0.1.1"
|
||||
@@ -2299,21 +2331,25 @@
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
|
||||
"optional": true
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
|
||||
"integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA="
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
|
||||
"optional": true
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.1.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
|
||||
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"asynckit": "0.4.0",
|
||||
@@ -2323,11 +2359,13 @@
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"fstream": {
|
||||
"version": "1.0.11",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
||||
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"inherits": "2.0.3",
|
||||
@@ -2337,7 +2375,8 @@
|
||||
},
|
||||
"fstream-ignore": {
|
||||
"version": "1.0.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
|
||||
"integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"fstream": "1.0.11",
|
||||
@@ -2347,7 +2386,8 @@
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"aproba": "1.1.1",
|
||||
@@ -2362,7 +2402,8 @@
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
@@ -2370,14 +2411,16 @@
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
@@ -2389,16 +2432,19 @@
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "1.0.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
|
||||
"integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
|
||||
"optional": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "4.2.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
|
||||
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ajv": "4.11.8",
|
||||
@@ -2407,12 +2453,14 @@
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"optional": true
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
@@ -2422,11 +2470,13 @@
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
|
||||
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"assert-plus": "0.2.0",
|
||||
@@ -2436,7 +2486,8 @@
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"requires": {
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
@@ -2444,37 +2495,44 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
|
||||
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"requires": {
|
||||
"number-is-nan": "1.0.1"
|
||||
}
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
|
||||
"optional": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"optional": true
|
||||
},
|
||||
"jodid25519": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
|
||||
"integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "0.1.1"
|
||||
@@ -2482,17 +2540,20 @@
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"optional": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
|
||||
"optional": true
|
||||
},
|
||||
"json-stable-stringify": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
|
||||
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsonify": "0.0.0"
|
||||
@@ -2500,17 +2561,20 @@
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
|
||||
"optional": true
|
||||
},
|
||||
"jsonify": {
|
||||
"version": "0.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
||||
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
|
||||
"optional": true
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
|
||||
"integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
@@ -2521,48 +2585,56 @@
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.27.0",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
|
||||
"integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.15",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
|
||||
"integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
|
||||
"requires": {
|
||||
"mime-db": "1.27.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"optional": true
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.6.39",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz",
|
||||
"integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"detect-libc": "1.0.2",
|
||||
@@ -2580,7 +2652,8 @@
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
||||
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"abbrev": "1.1.0",
|
||||
@@ -2589,7 +2662,8 @@
|
||||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz",
|
||||
"integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"are-we-there-yet": "1.1.4",
|
||||
@@ -2600,38 +2674,45 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"optional": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"optional": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"optional": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.4",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz",
|
||||
"integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"os-homedir": "1.0.2",
|
||||
@@ -2640,30 +2721,36 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "0.2.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
|
||||
"integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"optional": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
|
||||
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
|
||||
"optional": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz",
|
||||
"integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"deep-extend": "0.4.2",
|
||||
@@ -2674,14 +2761,16 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.2.9",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz",
|
||||
"integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=",
|
||||
"requires": {
|
||||
"buffer-shims": "1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
@@ -2694,7 +2783,8 @@
|
||||
},
|
||||
"request": {
|
||||
"version": "2.81.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
|
||||
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"aws-sign2": "0.6.0",
|
||||
@@ -2723,40 +2813,47 @@
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
|
||||
"integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
|
||||
"requires": {
|
||||
"glob": "7.1.2"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.0.1",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
||||
"integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.3.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
||||
"optional": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"optional": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"optional": true
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.13.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
|
||||
"integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"asn1": "0.2.3",
|
||||
@@ -2772,14 +2869,16 @@
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"requires": {
|
||||
"code-point-at": "1.1.0",
|
||||
"is-fullwidth-code-point": "1.0.0",
|
||||
@@ -2788,31 +2887,36 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz",
|
||||
"integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=",
|
||||
"requires": {
|
||||
"safe-buffer": "5.0.1"
|
||||
}
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
|
||||
"optional": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "2.2.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
|
||||
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
|
||||
"requires": {
|
||||
"block-stream": "0.0.9",
|
||||
"fstream": "1.0.11",
|
||||
@@ -2821,7 +2925,8 @@
|
||||
},
|
||||
"tar-pack": {
|
||||
"version": "3.4.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz",
|
||||
"integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "2.6.8",
|
||||
@@ -2836,7 +2941,8 @@
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.3.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
|
||||
"integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"punycode": "1.4.1"
|
||||
@@ -2844,7 +2950,8 @@
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.0.1"
|
||||
@@ -2852,26 +2959,31 @@
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"optional": true
|
||||
},
|
||||
"uid-number": {
|
||||
"version": "0.0.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
|
||||
"integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=",
|
||||
"optional": true
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
|
||||
"integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=",
|
||||
"optional": true
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.3.6",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
|
||||
"integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"extsprintf": "1.0.2"
|
||||
@@ -2879,7 +2991,8 @@
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.2",
|
||||
"bundled": true,
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
|
||||
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"string-width": "1.0.2"
|
||||
@@ -2887,7 +3000,8 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sapper",
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"description": "Military-grade apps, engineered by Svelte",
|
||||
"main": "lib/index.js",
|
||||
"bin": {
|
||||
@@ -19,11 +19,14 @@
|
||||
"dependencies": {
|
||||
"chalk": "^2.3.0",
|
||||
"chokidar": "^1.7.0",
|
||||
"code-frame": "^5.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"locate-character": "^2.0.5",
|
||||
"mkdirp": "^0.5.1",
|
||||
"relative": "^3.0.2",
|
||||
"require-relative": "^0.8.7",
|
||||
"rimraf": "^2.6.2",
|
||||
"serialize-javascript": "^1.4.0",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-hot-middleware": "^2.21.0"
|
||||
},
|
||||
|
||||
@@ -68,10 +68,16 @@ function render(Component: ComponentConstructor, data: any, scroll: ScrollPositi
|
||||
}
|
||||
}
|
||||
|
||||
function prepare_route(Component, data) {
|
||||
return Promise.resolve(
|
||||
Component.preload ? Component.preload(data) : {}
|
||||
).then(preloaded => {
|
||||
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 };
|
||||
});
|
||||
@@ -164,20 +170,24 @@ let prefetching: {
|
||||
promise: Promise<{ Component: ComponentConstructor, data: any }>;
|
||||
} = null;
|
||||
|
||||
function prefetch(event: MouseEvent | TouchEvent) {
|
||||
const a: HTMLAnchorElement = <HTMLAnchorElement>findAnchor(<Node>event.target);
|
||||
if (!a || a.rel !== 'prefetch') return;
|
||||
|
||||
const selected = select_route(new URL(a.href));
|
||||
export function prefetch(href: string) {
|
||||
const selected = select_route(new URL(href));
|
||||
|
||||
if (selected) {
|
||||
prefetching = {
|
||||
href: a.href,
|
||||
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[]) {
|
||||
@@ -189,8 +199,8 @@ export function init(_target: Node, _routes: Route[]) {
|
||||
window.addEventListener('popstate', handle_popstate);
|
||||
|
||||
// prefetch
|
||||
window.addEventListener('touchstart', prefetch);
|
||||
window.addEventListener('mouseover', prefetch);
|
||||
window.addEventListener('touchstart', handle_touchstart_mouseover);
|
||||
window.addEventListener('mouseover', handle_touchstart_mouseover);
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
6
test/app/package-lock.json
generated
6
test/app/package-lock.json
generated
@@ -2722,9 +2722,9 @@
|
||||
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.7.tgz",
|
||||
"integrity": "sha512-zBEP4qO1YQp5aXHt8S5wTiOv9i2X74V/LQL0zhUNvVaklt6Ywa6lChxIvS+ibYlCGgADwKwZFhjC3+XfpsvQvQ=="
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.9.tgz",
|
||||
"integrity": "sha512-nW5u0dxpXxHfkHzzrveY45gCbi+R4PaO4WRZYqZNl+vB0hVGeqlFn0aOg1c8AKL63TrNFn9Bm2UP4AdiZ9TPLw=="
|
||||
},
|
||||
"math-expression-evaluator": {
|
||||
"version": "1.2.17",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"express": "^4.16.2",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"glob": "^7.1.2",
|
||||
"marked": "^0.3.7",
|
||||
"marked": "^0.3.9",
|
||||
"node-fetch": "^1.7.3",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"serve-static": "^1.13.1",
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
|
||||
<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>
|
||||
|
||||
<script>
|
||||
import Layout from './_components/Layout.html';
|
||||
import { goto } from '../../../runtime.js';
|
||||
import { goto, prefetch } from '../../../runtime.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -20,7 +21,8 @@
|
||||
},
|
||||
|
||||
methods: {
|
||||
goto
|
||||
goto,
|
||||
prefetch
|
||||
}
|
||||
};
|
||||
</script>
|
||||
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
|
||||
}));
|
||||
}
|
||||
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>
|
||||
@@ -3,7 +3,7 @@
|
||||
<script>
|
||||
export default {
|
||||
preload({ url }) {
|
||||
return { url };
|
||||
if (url) return { url };
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -32,6 +32,6 @@
|
||||
<!-- Sapper creates a <script> tag containing `templates/main.js`
|
||||
and anything else it needs to hydrate the app and
|
||||
initialise the router -->
|
||||
<script src='%sapper.main%'></script>
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,6 +9,12 @@ const fetch = require('node-fetch');
|
||||
run('production');
|
||||
run('development');
|
||||
|
||||
Nightmare.action('page', {
|
||||
title(done) {
|
||||
this.evaluate_now(() => document.querySelector('h1').textContent, done);
|
||||
}
|
||||
});
|
||||
|
||||
function run(env) {
|
||||
describe(`env=${env}`, function () {
|
||||
this.timeout(20000);
|
||||
@@ -62,52 +68,60 @@ function run(env) {
|
||||
});
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
before(() => {
|
||||
process.chdir(path.resolve(__dirname, '../app'));
|
||||
|
||||
process.env.NODE_ENV = env;
|
||||
|
||||
let exec_promise = Promise.resolve();
|
||||
let sapper;
|
||||
|
||||
if (env === 'production') {
|
||||
const cli = path.resolve(__dirname, '../../cli/index.js');
|
||||
await exec(`${cli} build`);
|
||||
exec_promise = exec(`${cli} build`);
|
||||
}
|
||||
|
||||
const resolved = require.resolve('../..');
|
||||
delete require.cache[resolved];
|
||||
const sapper = require(resolved);
|
||||
return exec_promise.then(() => {
|
||||
const resolved = require.resolve('../..');
|
||||
delete require.cache[resolved];
|
||||
sapper = require(resolved);
|
||||
|
||||
PORT = await getPort();
|
||||
base = `http://localhost:${PORT}`;
|
||||
return getPort();
|
||||
}).then(port => {
|
||||
PORT = port;
|
||||
base = `http://localhost:${PORT}`;
|
||||
|
||||
global.fetch = (url, opts) => {
|
||||
if (url[0] === '/') url = `${base}${url}`;
|
||||
return fetch(url, opts);
|
||||
};
|
||||
global.fetch = (url, opts) => {
|
||||
if (url[0] === '/') url = `${base}${url}`;
|
||||
return fetch(url, opts);
|
||||
};
|
||||
|
||||
let captured;
|
||||
capture = async fn => {
|
||||
const result = captured = [];
|
||||
await fn();
|
||||
captured = null;
|
||||
return result;
|
||||
};
|
||||
let captured;
|
||||
capture = fn => {
|
||||
const result = captured = [];
|
||||
return fn().then(() => {
|
||||
captured = null;
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
const app = express();
|
||||
const app = express();
|
||||
|
||||
app.use(serve('assets'));
|
||||
app.use(serve('assets'));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
if (captured) captured.push(req);
|
||||
next();
|
||||
});
|
||||
app.use((req, res, next) => {
|
||||
if (captured) captured.push(req);
|
||||
next();
|
||||
});
|
||||
|
||||
middleware = sapper();
|
||||
app.use(middleware);
|
||||
middleware = sapper();
|
||||
app.use(middleware);
|
||||
|
||||
return new Promise((fulfil, reject) => {
|
||||
server = app.listen(PORT, err => {
|
||||
if (err) reject(err);
|
||||
else fulfil();
|
||||
return new Promise((fulfil, reject) => {
|
||||
server = app.listen(PORT, err => {
|
||||
if (err) reject(err);
|
||||
else fulfil();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -137,159 +151,165 @@ function run(env) {
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await nightmare.end();
|
||||
afterEach(() => {
|
||||
return nightmare.end();
|
||||
});
|
||||
|
||||
it('serves /', async () => {
|
||||
const title = await nightmare
|
||||
.goto(base)
|
||||
.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"]');
|
||||
it('serves /', () => {
|
||||
return nightmare.goto(base).page.title().then(title => {
|
||||
assert.equal(title, 'Great success!');
|
||||
});
|
||||
|
||||
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 () => {
|
||||
await nightmare
|
||||
it('serves static route', () => {
|
||||
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`)
|
||||
.wait(() => window.READY)
|
||||
.click('button')
|
||||
.click('.goto')
|
||||
.wait(() => window.location.pathname === '/blog/what-is-sapper')
|
||||
.wait(100);
|
||||
|
||||
assert.equal(
|
||||
await nightmare.evaluate(() => document.title),
|
||||
'What is Sapper?'
|
||||
);
|
||||
.wait(100)
|
||||
.title()
|
||||
.then(title => {
|
||||
assert.equal(title, 'What is Sapper?');
|
||||
});
|
||||
});
|
||||
|
||||
it('scrolls to active deeplink', async () => {
|
||||
const scrollY = await nightmare
|
||||
it('prefetches programmatically', () => {
|
||||
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`)
|
||||
.wait(() => window.READY)
|
||||
.wait(100)
|
||||
.evaluate(() => window.scrollY);
|
||||
|
||||
assert.ok(scrollY > 0, scrollY);
|
||||
.evaluate(() => window.scrollY)
|
||||
.then(scrollY => {
|
||||
assert.ok(scrollY > 0, scrollY);
|
||||
});
|
||||
});
|
||||
|
||||
it('reuses prefetch promise', async () => {
|
||||
await nightmare
|
||||
it('reuses prefetch promise', () => {
|
||||
return nightmare
|
||||
.goto(`${base}/blog`)
|
||||
.wait(() => window.READY)
|
||||
.wait(200);
|
||||
.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'
|
||||
]);
|
||||
|
||||
const mouseover_requests = (await capture(async () => {
|
||||
await nightmare
|
||||
.mouseover('[href="/blog/what-is-sapper"]')
|
||||
.wait(200);
|
||||
})).map(r => r.url);
|
||||
|
||||
assert.deepEqual(mouseover_requests, [
|
||||
'/api/blog/what-is-sapper'
|
||||
]);
|
||||
|
||||
const click_requests = (await capture(async () => {
|
||||
await nightmare
|
||||
.click('[href="/blog/what-is-sapper"]')
|
||||
.wait(200);
|
||||
})).map(r => r.url);
|
||||
|
||||
assert.deepEqual(click_requests, []);
|
||||
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', async () => {
|
||||
await nightmare
|
||||
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);
|
||||
|
||||
assert.equal(
|
||||
await nightmare.path(),
|
||||
'/about'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
await nightmare.evaluate(() => document.querySelector('h1').textContent),
|
||||
'About this site'
|
||||
);
|
||||
|
||||
await nightmare
|
||||
.evaluate(() => window.fulfil({}))
|
||||
.wait(100);
|
||||
|
||||
assert.equal(
|
||||
await nightmare.path(),
|
||||
'/about'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
await nightmare.evaluate(() => document.querySelector('h1').textContent),
|
||||
'About this site'
|
||||
);
|
||||
.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', async () => {
|
||||
const html = await nightmare
|
||||
it('passes entire request object to preload', () => {
|
||||
return nightmare
|
||||
.goto(`${base}/show-url`)
|
||||
.evaluate(() => document.querySelector('p').innerHTML);
|
||||
|
||||
assert.equal(html, `URL is /show-url`);
|
||||
.wait(() => window.READY)
|
||||
.evaluate(() => document.querySelector('p').innerHTML)
|
||||
.end().then(html => {
|
||||
assert.equal(html, `URL is /show-url`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('headers', () => {
|
||||
it('sets Content-Type and Link...preload headers', async () => {
|
||||
const { headers } = await get('/');
|
||||
it('sets Content-Type and Link...preload headers', () => {
|
||||
return get('/').then(({ headers }) => {
|
||||
assert.equal(
|
||||
headers['Content-Type'],
|
||||
'text/html'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
headers['Content-Type'],
|
||||
'text/html'
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
/<\/client\/main.\w+\.js>;rel="preload";as="script", <\/client\/_.\d+.\w+.js>;rel="preload";as="script"/.test(headers['Link']),
|
||||
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']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -308,4 +328,4 @@ function exec(cmd) {
|
||||
fulfil();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,12 @@ module.exports = {
|
||||
client: {
|
||||
entry: () => {
|
||||
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'
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
@@ -36,4 +41,4 @@ module.exports = {
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user