mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-16 04:44:35 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1fcd07c92 | ||
|
|
47a6d6f662 | ||
|
|
4b2b6440d0 | ||
|
|
fc855f30f8 | ||
|
|
4a75fff4ec | ||
|
|
7b7b695938 | ||
|
|
2fca2e295f | ||
|
|
eae991d369 | ||
|
|
c2b393d3fd | ||
|
|
566addd406 | ||
|
|
3d77dacbd6 | ||
|
|
51b4f9cbbf | ||
|
|
1d611be83e | ||
|
|
1782904994 | ||
|
|
e3ddbfc181 | ||
|
|
8e3830b646 | ||
|
|
b28cdff233 | ||
|
|
7f586ff1a3 | ||
|
|
731d4f535c | ||
|
|
f8c731ca21 | ||
|
|
39eb3be01e |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,5 +1,22 @@
|
|||||||
# sapper changelog
|
# sapper changelog
|
||||||
|
|
||||||
|
## 0.15.4
|
||||||
|
|
||||||
|
* Add `ignore` option ([#326](https://github.com/sveltejs/sapper/pull/326))
|
||||||
|
|
||||||
|
## 0.15.3
|
||||||
|
|
||||||
|
* Crawl pages in parallel when exporting ([#329](https://github.com/sveltejs/sapper/pull/329))
|
||||||
|
* Don't minify inline JS when exporting ([#328](https://github.com/sveltejs/sapper/pull/328))
|
||||||
|
|
||||||
|
## 0.15.2
|
||||||
|
|
||||||
|
* Collapse component chains where no intermediate layout component is specified ([#312](https://github.com/sveltejs/sapper/issues/312))
|
||||||
|
|
||||||
|
## 0.15.1
|
||||||
|
|
||||||
|
* Prevent confusing error when no root layout is specified
|
||||||
|
|
||||||
## 0.15.0
|
## 0.15.0
|
||||||
|
|
||||||
* Nested routes (consult [migration guide](https://sapper.svelte.technology/guide#0-14-to-0-15) and docs on [layouts](https://sapper.svelte.technology/guide#layouts)) ([#262](https://github.com/sveltejs/sapper/issues/262))
|
* Nested routes (consult [migration guide](https://sapper.svelte.technology/guide#0-14-to-0-15) and docs on [layouts](https://sapper.svelte.technology/guide#layouts)) ([#262](https://github.com/sveltejs/sapper/issues/262))
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -31,6 +31,44 @@ npm run build
|
|||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Pull requests are encouraged and always welcome. [Pick an issue](https://github.com/sveltejs/sapper/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and help us out!
|
||||||
|
|
||||||
|
To install and work on Sapper locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:sveltejs/sapper.git
|
||||||
|
cd sapper
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linking to a Live Project
|
||||||
|
|
||||||
|
You can make changes locally to Sapper and test it against a local Sapper project. For a quick project that takes almost no setup, use the default [sapper-template](https://github.com/sveltejs/sapper-template) project. Instruction on setup are found in that project repository.
|
||||||
|
|
||||||
|
To link Sapper to your project, from the root of your local Sapper git checkout:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd sapper
|
||||||
|
npm link
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, to link from `sapper-template` (or any other given project):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd sapper-template
|
||||||
|
npm link sapper
|
||||||
|
```
|
||||||
|
|
||||||
|
You should be good to test changes locally.
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
4954
package-lock.json
generated
Normal file
4954
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.15.0",
|
"version": "0.15.4",
|
||||||
"description": "Military-grade apps, engineered by Svelte",
|
"description": "Military-grade apps, engineered by Svelte",
|
||||||
"main": "dist/middleware.ts.js",
|
"main": "dist/middleware.ts.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"cheerio": "^1.0.0-rc.2",
|
"cheerio": "^1.0.0-rc.2",
|
||||||
"chokidar": "^2.0.3",
|
"chokidar": "^2.0.3",
|
||||||
"cookie": "^0.3.1",
|
"cookie": "^0.3.1",
|
||||||
"devalue": "^1.0.1",
|
"devalue": "^1.0.4",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"html-minifier": "^3.5.16",
|
"html-minifier": "^3.5.16",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
|
|||||||
@@ -118,9 +118,7 @@ async function execute(emitter: EventEmitter, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const url of urls) {
|
await Promise.all(urls.map(handle));
|
||||||
await handle(url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function minify_html(html: string) {
|
|||||||
decodeEntities: true,
|
decodeEntities: true,
|
||||||
html5: true,
|
html5: true,
|
||||||
minifyCSS: true,
|
minifyCSS: true,
|
||||||
minifyJS: true,
|
minifyJS: false,
|
||||||
removeAttributeQuotes: true,
|
removeAttributeQuotes: true,
|
||||||
removeComments: true,
|
removeComments: true,
|
||||||
removeOptionalTags: true,
|
removeOptionalTags: true,
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function generate_client(
|
|||||||
|
|
||||||
let code = `
|
let code = `
|
||||||
// This file is generated by Sapper — do not edit it!
|
// This file is generated by Sapper — do not edit it!
|
||||||
import root from '${posixify(`${path_to_routes}/${routes.root.file}`)}';
|
import root from '${get_file(path_to_routes, routes.root)}';
|
||||||
import error from '${posixify(`${path_to_routes}/_error.html`)}';
|
import error from '${posixify(`${path_to_routes}/_error.html`)}';
|
||||||
|
|
||||||
${routes.components.map(component =>
|
${routes.components.map(component =>
|
||||||
@@ -79,6 +79,8 @@ function generate_client(
|
|||||||
pattern: ${page.pattern},
|
pattern: ${page.pattern},
|
||||||
parts: [
|
parts: [
|
||||||
${page.parts.map(part => {
|
${page.parts.map(part => {
|
||||||
|
if (part === null) return 'null';
|
||||||
|
|
||||||
if (part.params.length > 0) {
|
if (part.params.length > 0) {
|
||||||
const props = part.params.map((param, i) => `${param}: match[${i + 1}]`);
|
const props = part.params.map((param, i) => `${param}: match[${i + 1}]`);
|
||||||
return `{ component: ${part.component.name}, params: match => ({ ${props.join(', ')} }) }`;
|
return `{ component: ${part.component.name}, params: match => ({ ${props.join(', ')} }) }`;
|
||||||
@@ -124,7 +126,7 @@ function generate_server(
|
|||||||
`import * as ${route.name} from '${posixify(`${path_to_routes}/${route.file}`)}';`),
|
`import * as ${route.name} from '${posixify(`${path_to_routes}/${route.file}`)}';`),
|
||||||
routes.components.map(component =>
|
routes.components.map(component =>
|
||||||
`import ${component.name} from '${get_file(path_to_routes, component)}';`),
|
`import ${component.name} from '${get_file(path_to_routes, component)}';`),
|
||||||
`import root from '${posixify(`${path_to_routes}/${routes.root.file}`)}';`,
|
`import root from '${get_file(path_to_routes, routes.root)}';`,
|
||||||
`import error from '${posixify(`${path_to_routes}/_error.html`)}';`
|
`import error from '${posixify(`${path_to_routes}/_error.html`)}';`
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -150,6 +152,8 @@ function generate_server(
|
|||||||
pattern: ${page.pattern},
|
pattern: ${page.pattern},
|
||||||
parts: [
|
parts: [
|
||||||
${page.parts.map(part => {
|
${page.parts.map(part => {
|
||||||
|
if (part === null) return 'null';
|
||||||
|
|
||||||
const props = [
|
const props = [
|
||||||
`name: "${part.component.name}"`,
|
`name: "${part.component.name}"`,
|
||||||
`component: ${part.component.name}`
|
`component: ${part.component.name}`
|
||||||
|
|||||||
@@ -101,27 +101,21 @@ export default function create_routes(cwd = locations.routes()) {
|
|||||||
|
|
||||||
if (item.is_dir) {
|
if (item.is_dir) {
|
||||||
const index = path.join(dir, item.basename, '_layout.html');
|
const index = path.join(dir, item.basename, '_layout.html');
|
||||||
const layout = fs.existsSync(index)
|
|
||||||
? {
|
|
||||||
name: `${get_slug(item.file)}__layout`,
|
|
||||||
file: `${item.file}/_layout.html`
|
|
||||||
}
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (layout) {
|
const component = fs.existsSync(index) && {
|
||||||
components.push(layout);
|
name: `${get_slug(item.file)}__layout`,
|
||||||
} else if (components.indexOf(default_layout) === -1) {
|
file: `${item.file}/_layout.html`
|
||||||
components.push(default_layout);
|
};
|
||||||
}
|
|
||||||
|
if (component) components.push(component);
|
||||||
|
|
||||||
walk(
|
walk(
|
||||||
path.join(dir, item.basename),
|
path.join(dir, item.basename),
|
||||||
segments,
|
segments,
|
||||||
params,
|
params,
|
||||||
stack.concat({
|
component
|
||||||
component: layout || default_layout,
|
? stack.concat({ component, params })
|
||||||
params
|
: stack.concat(null)
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,9 +73,18 @@ interface Component {
|
|||||||
preload: (data: any) => any | Promise<any>
|
preload: (data: any) => any | Promise<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IGNORE = '__SAPPER__IGNORE__';
|
||||||
|
function toIgnore(uri: string, val: any) {
|
||||||
|
if (Array.isArray(val)) return val.some(x => toIgnore(uri, x));
|
||||||
|
if (val instanceof RegExp) return val.test(uri);
|
||||||
|
if (typeof val === 'function') return val(uri);
|
||||||
|
return uri.startsWith(val.charCodeAt(0) === 47 ? val : `/${val}`);
|
||||||
|
}
|
||||||
|
|
||||||
export default function middleware(opts: {
|
export default function middleware(opts: {
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
store: (req: Req) => Store,
|
store: (req: Req) => Store,
|
||||||
|
ignore?: any,
|
||||||
routes?: any // legacy
|
routes?: any // legacy
|
||||||
}) {
|
}) {
|
||||||
if (opts.routes) {
|
if (opts.routes) {
|
||||||
@@ -84,12 +93,19 @@ export default function middleware(opts: {
|
|||||||
|
|
||||||
const output = locations.dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const { manifest, store } = opts;
|
const { manifest, store, ignore } = opts;
|
||||||
|
|
||||||
let emitted_basepath = false;
|
let emitted_basepath = false;
|
||||||
|
|
||||||
const middleware = compose_handlers([
|
const middleware = compose_handlers([
|
||||||
|
ignore && ((req: Req, res: ServerResponse, next: () => void) => {
|
||||||
|
req[IGNORE] = toIgnore(req.path, ignore);
|
||||||
|
next();
|
||||||
|
}),
|
||||||
|
|
||||||
(req: Req, res: ServerResponse, next: () => void) => {
|
(req: Req, res: ServerResponse, next: () => void) => {
|
||||||
|
if (req[IGNORE]) return next();
|
||||||
|
|
||||||
if (req.baseUrl === undefined) {
|
if (req.baseUrl === undefined) {
|
||||||
let { originalUrl } = req;
|
let { originalUrl } = req;
|
||||||
if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') {
|
if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') {
|
||||||
@@ -163,6 +179,8 @@ function serve({ prefix, pathname, cache_control }: {
|
|||||||
: (file: string) => (cache.has(file) ? cache : cache.set(file, fs.readFileSync(path.resolve(output, file)))).get(file)
|
: (file: string) => (cache.has(file) ? cache : cache.set(file, fs.readFileSync(path.resolve(output, file)))).get(file)
|
||||||
|
|
||||||
return (req: Req, res: ServerResponse, next: () => void) => {
|
return (req: Req, res: ServerResponse, next: () => void) => {
|
||||||
|
if (req[IGNORE]) return next();
|
||||||
|
|
||||||
if (filter(req)) {
|
if (filter(req)) {
|
||||||
const type = lookup(req.path);
|
const type = lookup(req.path);
|
||||||
|
|
||||||
@@ -245,6 +263,8 @@ function get_server_route_handler(routes: ServerRoute[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function find_route(req: Req, res: ServerResponse, next: () => void) {
|
return function find_route(req: Req, res: ServerResponse, next: () => void) {
|
||||||
|
if (req[IGNORE]) return next();
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if (route.pattern.test(req.path)) {
|
if (route.pattern.test(req.path)) {
|
||||||
handle_route(route, req, res, next);
|
handle_route(route, req, res, next);
|
||||||
@@ -292,6 +312,8 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
let preloaded_chunks = Array.isArray(chunks.main) ? chunks.main : [chunks.main];
|
let preloaded_chunks = Array.isArray(chunks.main) ? chunks.main : [chunks.main];
|
||||||
if (!error) {
|
if (!error) {
|
||||||
page.parts.forEach(part => {
|
page.parts.forEach(part => {
|
||||||
|
if (!part) return;
|
||||||
|
|
||||||
// using concat because it could be a string or an array. thanks webpack!
|
// using concat because it could be a string or an array. thanks webpack!
|
||||||
preloaded_chunks = preloaded_chunks.concat(chunks[part.name]);
|
preloaded_chunks = preloaded_chunks.concat(chunks[part.name]);
|
||||||
});
|
});
|
||||||
@@ -366,6 +388,8 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
: {};
|
: {};
|
||||||
|
|
||||||
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
||||||
|
if (!part) return null;
|
||||||
|
|
||||||
return part.component.preload
|
return part.component.preload
|
||||||
? part.component.preload.call(preload_context, {
|
? part.component.preload.call(preload_context, {
|
||||||
path: req.path,
|
path: req.path,
|
||||||
@@ -411,23 +435,28 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
|
|
||||||
const data = Object.assign({}, props, preloaded[0], {
|
const data = Object.assign({}, props, preloaded[0], {
|
||||||
params: {},
|
params: {},
|
||||||
child: {}
|
child: {
|
||||||
|
segment: segments[0]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let level = data.child;
|
let level = data.child;
|
||||||
for (let i = 0; i < page.parts.length; i += 1) {
|
for (let i = 0; i < page.parts.length; i += 1) {
|
||||||
const part = page.parts[i];
|
const part = page.parts[i];
|
||||||
|
if (!part) continue;
|
||||||
|
|
||||||
const get_params = part.params || (() => ({}));
|
const get_params = part.params || (() => ({}));
|
||||||
|
|
||||||
Object.assign(level, {
|
Object.assign(level, {
|
||||||
segment: segments[i],
|
|
||||||
component: part.component,
|
component: part.component,
|
||||||
props: Object.assign({}, props, {
|
props: Object.assign({}, props, {
|
||||||
params: get_params(match)
|
params: get_params(match)
|
||||||
}, preloaded[i + 1])
|
}, preloaded[i + 1])
|
||||||
});
|
});
|
||||||
|
|
||||||
level.props.child = <Props["child"]>{};
|
level.props.child = <Props["child"]>{
|
||||||
|
segment: segments[i + 1]
|
||||||
|
};
|
||||||
level = level.props.child;
|
level = level.props.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,9 +472,9 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
|
|
||||||
let inline_script = `__SAPPER__={${[
|
let inline_script = `__SAPPER__={${[
|
||||||
error && `error:1`,
|
error && `error:1`,
|
||||||
`baseUrl: "${req.baseUrl}"`,
|
`baseUrl:"${req.baseUrl}"`,
|
||||||
serialized.preloaded && `preloaded: ${serialized.preloaded}`,
|
serialized.preloaded && `preloaded:${serialized.preloaded}`,
|
||||||
serialized.store && `store: ${serialized.store}`
|
serialized.store && `store:${serialized.store}`
|
||||||
].filter(Boolean).join(',')}};`;
|
].filter(Boolean).join(',')}};`;
|
||||||
|
|
||||||
const has_service_worker = fs.existsSync(path.join(locations.dest(), 'service-worker.js'));
|
const has_service_worker = fs.existsSync(path.join(locations.dest(), 'service-worker.js'));
|
||||||
@@ -485,7 +514,9 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return function find_route(req: Req, res: ServerResponse) {
|
return function find_route(req: Req, res: ServerResponse, next: () => void) {
|
||||||
|
if (req[IGNORE]) return next();
|
||||||
|
|
||||||
if (!server_routes.some(route => route.pattern.test(req.path))) {
|
if (!server_routes.some(route => route.pattern.test(req.path))) {
|
||||||
for (const page of pages) {
|
for (const page of pages) {
|
||||||
if (page.pattern.test(req.path)) {
|
if (page.pattern.test(req.path)) {
|
||||||
|
|||||||
@@ -77,14 +77,14 @@ function select_route(url: URL): Target {
|
|||||||
|
|
||||||
let current_token: {};
|
let current_token: {};
|
||||||
|
|
||||||
function render(data: any, changed_from: number, scroll: ScrollPosition, token: {}) {
|
function render(data: any, nullable_depth: number, scroll: ScrollPosition, token: {}) {
|
||||||
if (current_token !== token) return;
|
if (current_token !== token) return;
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
// first, clear out highest-level root component
|
// first, clear out highest-level root component
|
||||||
let level = data.child;
|
let level = data.child;
|
||||||
for (let i = 0; i < changed_from; i += 1) {
|
for (let i = 0; i < nullable_depth; i += 1) {
|
||||||
if (i === changed_from) break;
|
if (i === nullable_depth) break;
|
||||||
level = level.props.child;
|
level = level.props.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ let root_data: any;
|
|||||||
function prepare_page(target: Target): Promise<{
|
function prepare_page(target: Target): Promise<{
|
||||||
redirect?: Redirect;
|
redirect?: Redirect;
|
||||||
data?: any;
|
data?: any;
|
||||||
changed_from?: number;
|
nullable_depth?: number;
|
||||||
}> {
|
}> {
|
||||||
if (root) {
|
if (root) {
|
||||||
root.set({ preloading: true });
|
root.set({ preloading: true });
|
||||||
@@ -179,6 +179,7 @@ function prepare_page(target: Target): Promise<{
|
|||||||
|
|
||||||
return Promise.all(page.parts.map(async (part, i) => {
|
return Promise.all(page.parts.map(async (part, i) => {
|
||||||
if (i < changed_from) return null;
|
if (i < changed_from) return null;
|
||||||
|
if (!part) return null;
|
||||||
|
|
||||||
const { default: Component } = await part.component();
|
const { default: Component } = await part.component();
|
||||||
const req = {
|
const req = {
|
||||||
@@ -231,33 +232,42 @@ function prepare_page(target: Target): Promise<{
|
|||||||
const data = {
|
const data = {
|
||||||
path,
|
path,
|
||||||
preloading: false,
|
preloading: false,
|
||||||
child: Object.assign({}, root_props.child)
|
child: Object.assign({}, root_props.child, {
|
||||||
|
segment: segments[0]
|
||||||
|
})
|
||||||
};
|
};
|
||||||
if (changed(query, root_props.query)) data.query = query;
|
if (changed(query, root_props.query)) data.query = query;
|
||||||
if (changed(params, root_props.params)) data.params = params;
|
if (changed(params, root_props.params)) data.params = params;
|
||||||
|
|
||||||
let level = data.child;
|
let level = data.child;
|
||||||
|
let nullable_depth = 0;
|
||||||
|
|
||||||
for (let i = 0; i < page.parts.length; i += 1) {
|
for (let i = 0; i < page.parts.length; i += 1) {
|
||||||
const part = page.parts[i];
|
const part = page.parts[i];
|
||||||
|
if (!part) continue;
|
||||||
|
|
||||||
const get_params = part.params || (() => ({}));
|
const get_params = part.params || (() => ({}));
|
||||||
|
|
||||||
if (i < changed_from) {
|
if (i < changed_from) {
|
||||||
level.props.path = path;
|
level.props.path = path;
|
||||||
level.props.query = query;
|
level.props.query = query;
|
||||||
level.props.child = Object.assign({}, level.props.child);
|
level.props.child = Object.assign({}, level.props.child);
|
||||||
|
|
||||||
|
nullable_depth += 1;
|
||||||
} else {
|
} else {
|
||||||
level.segment = new_segments[i];
|
|
||||||
level.component = results[i].Component;
|
level.component = results[i].Component;
|
||||||
level.props = Object.assign({}, level.props, props, {
|
level.props = Object.assign({}, level.props, props, {
|
||||||
params: get_params(target.match),
|
params: get_params(target.match),
|
||||||
}, results[i].preloaded);
|
}, results[i].preloaded);
|
||||||
|
|
||||||
level.props.child = {};
|
level.props.child = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
level = level.props.child;
|
level = level.props.child;
|
||||||
|
level.segment = segments[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data, changed_from };
|
return { data, nullable_depth };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,12 +292,12 @@ async function navigate(target: Target, id: number): Promise<any> {
|
|||||||
prefetching = null;
|
prefetching = null;
|
||||||
|
|
||||||
const token = current_token = {};
|
const token = current_token = {};
|
||||||
const { redirect, data, changed_from } = await loaded;
|
const { redirect, data, nullable_depth } = await loaded;
|
||||||
|
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
await goto(redirect.location, { replaceState: true });
|
await goto(redirect.location, { replaceState: true });
|
||||||
} else {
|
} else {
|
||||||
render(data, changed_from, scroll_history[id], token);
|
render(data, nullable_depth, scroll_history[id], token);
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,7 +363,7 @@ function handle_popstate(event: PopStateEvent) {
|
|||||||
|
|
||||||
let prefetching: {
|
let prefetching: {
|
||||||
href: string;
|
href: string;
|
||||||
promise: Promise<{ redirect?: Redirect, data?: any, changed_from?: number }>;
|
promise: Promise<{ redirect?: Redirect, data?: any, nullable_depth?: number }>;
|
||||||
} = null;
|
} = null;
|
||||||
|
|
||||||
export function prefetch(href: string) {
|
export function prefetch(href: string) {
|
||||||
|
|||||||
@@ -91,8 +91,14 @@ const middlewares = [
|
|||||||
return new Store({
|
return new Store({
|
||||||
title: 'Stored title'
|
title: 'Stored title'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
})
|
ignore: [
|
||||||
|
/foobar/i,
|
||||||
|
'/buzz',
|
||||||
|
'fizz',
|
||||||
|
x => x === '/hello'
|
||||||
|
]
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (BASEPATH) {
|
if (BASEPATH) {
|
||||||
@@ -101,4 +107,8 @@ if (BASEPATH) {
|
|||||||
app.use(...middlewares);
|
app.use(...middlewares);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.listen(PORT);
|
['foobar', 'buzz', 'fizzer', 'hello'].forEach(uri => {
|
||||||
|
app.get('/'+uri, (req, res) => res.end(uri));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<span>y: {segment} {count}</span>
|
<span>y: {segment} {count}</span>
|
||||||
<svelte:component this={child.component} {...child.props}/>
|
<svelte:component this={child.component} {...child.props}/>
|
||||||
|
|
||||||
|
<span>child segment: {child.segment}</span>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import counts from '../_counts.js';
|
import counts from '../_counts.js';
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
<span>x: {segment} {count}</span>
|
|
||||||
<svelte:component this={child.component} {...child.props}/>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import counts from './_counts.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
preload() {
|
|
||||||
return {
|
|
||||||
count: counts.x += 1
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
oncreate() {
|
|
||||||
this.set({
|
|
||||||
segment: this.get().params.x
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -477,6 +477,42 @@ function run({ mode, basepath = '' }) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ignores are meant for top-level escape.
|
||||||
|
// ~> Sapper **should** own the entire {basepath} when designated.
|
||||||
|
if (!basepath) {
|
||||||
|
it('respects `options.ignore` values (RegExp)', () => {
|
||||||
|
return nightmare.goto(`${base}/foobar`)
|
||||||
|
.evaluate(() => document.documentElement.textContent)
|
||||||
|
.then(text => {
|
||||||
|
assert.equal(text, 'foobar');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects `options.ignore` values (String #1)', () => {
|
||||||
|
return nightmare.goto(`${base}/buzz`)
|
||||||
|
.evaluate(() => document.documentElement.textContent)
|
||||||
|
.then(text => {
|
||||||
|
assert.equal(text, 'buzz');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects `options.ignore` values (String #2)', () => {
|
||||||
|
return nightmare.goto(`${base}/fizzer`)
|
||||||
|
.evaluate(() => document.documentElement.textContent)
|
||||||
|
.then(text => {
|
||||||
|
assert.equal(text, 'fizzer');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects `options.ignore` values (Function)', () => {
|
||||||
|
return nightmare.goto(`${base}/hello`)
|
||||||
|
.evaluate(() => document.documentElement.textContent)
|
||||||
|
.then(text => {
|
||||||
|
assert.equal(text, 'hello');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it('does not attempt client-side navigation to server routes', () => {
|
it('does not attempt client-side navigation to server routes', () => {
|
||||||
return nightmare.goto(`${base}/blog/how-is-sapper-different-from-next`)
|
return nightmare.goto(`${base}/blog/how-is-sapper-different-from-next`)
|
||||||
.init()
|
.init()
|
||||||
@@ -629,9 +665,9 @@ function run({ mode, basepath = '' }) {
|
|||||||
.evaluate(() => document.querySelector('#sapper').textContent)
|
.evaluate(() => document.querySelector('#sapper').textContent)
|
||||||
.then(text => {
|
.then(text => {
|
||||||
assert.deepEqual(text.split('\n').filter(Boolean), [
|
assert.deepEqual(text.split('\n').filter(Boolean), [
|
||||||
'x: foo 1',
|
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1'
|
'z: baz 1',
|
||||||
|
'child segment: baz'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return nightmare.click(`a`)
|
return nightmare.click(`a`)
|
||||||
@@ -642,9 +678,9 @@ function run({ mode, basepath = '' }) {
|
|||||||
})
|
})
|
||||||
.then(text => {
|
.then(text => {
|
||||||
assert.deepEqual(text.split('\n').filter(Boolean), [
|
assert.deepEqual(text.split('\n').filter(Boolean), [
|
||||||
'x: foo 1',
|
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: qux 2'
|
'z: qux 2',
|
||||||
|
'child segment: qux'
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,13 +2,6 @@ const path = require('path');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { create_routes } = require('../../../dist/core.ts.js');
|
const { create_routes } = require('../../../dist/core.ts.js');
|
||||||
|
|
||||||
|
|
||||||
const _default_layout = {
|
|
||||||
default: true,
|
|
||||||
name: '_default_layout',
|
|
||||||
file: null
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('create_routes', () => {
|
describe('create_routes', () => {
|
||||||
it('creates routes', () => {
|
it('creates routes', () => {
|
||||||
const { components, pages, server_routes } = create_routes(path.join(__dirname, 'samples/basic'));
|
const { components, pages, server_routes } = create_routes(path.join(__dirname, 'samples/basic'));
|
||||||
@@ -21,7 +14,6 @@ describe('create_routes', () => {
|
|||||||
assert.deepEqual(components, [
|
assert.deepEqual(components, [
|
||||||
index,
|
index,
|
||||||
about,
|
about,
|
||||||
_default_layout,
|
|
||||||
blog,
|
blog,
|
||||||
blog_$slug
|
blog_$slug
|
||||||
]);
|
]);
|
||||||
@@ -44,7 +36,7 @@ describe('create_routes', () => {
|
|||||||
{
|
{
|
||||||
pattern: /^\/blog\/?$/,
|
pattern: /^\/blog\/?$/,
|
||||||
parts: [
|
parts: [
|
||||||
{ component: _default_layout, params: [] },
|
null,
|
||||||
{ component: blog, params: [] }
|
{ component: blog, params: [] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -52,7 +44,7 @@ describe('create_routes', () => {
|
|||||||
{
|
{
|
||||||
pattern: /^\/blog\/([^\/]+?)\/?$/,
|
pattern: /^\/blog\/([^\/]+?)\/?$/,
|
||||||
parts: [
|
parts: [
|
||||||
{ component: _default_layout, params: [] },
|
null,
|
||||||
{ component: blog_$slug, params: ['slug'] }
|
{ component: blog_$slug, params: ['slug'] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -110,15 +102,15 @@ describe('create_routes', () => {
|
|||||||
it('sorts routes correctly', () => {
|
it('sorts routes correctly', () => {
|
||||||
const { pages } = create_routes(path.join(__dirname, 'samples/sorting'));
|
const { pages } = create_routes(path.join(__dirname, 'samples/sorting'));
|
||||||
|
|
||||||
assert.deepEqual(pages.map(p => p.parts.map(part => part.component.file)), [
|
assert.deepEqual(pages.map(p => p.parts.map(part => part && part.component.file)), [
|
||||||
['index.html'],
|
['index.html'],
|
||||||
['about.html'],
|
['about.html'],
|
||||||
[_default_layout.file, 'post/index.html'],
|
[null, 'post/index.html'],
|
||||||
[_default_layout.file, 'post/bar.html'],
|
[null, 'post/bar.html'],
|
||||||
[_default_layout.file, 'post/foo.html'],
|
[null, 'post/foo.html'],
|
||||||
[_default_layout.file, 'post/f[xx].html'],
|
[null, 'post/f[xx].html'],
|
||||||
[_default_layout.file, 'post/[id([0-9-a-z]{3,})].html'],
|
[null, 'post/[id([0-9-a-z]{3,})].html'],
|
||||||
[_default_layout.file, 'post/[id].html'],
|
[null, 'post/[id].html'],
|
||||||
['[wildcard].html']
|
['[wildcard].html']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user