mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-14 03:54:46 +00:00
Compare commits
24 Commits
proxy-data
...
v0.15.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbbf4a95db | ||
|
|
55b7ffd2ed | ||
|
|
9f4d4e70de | ||
|
|
deef1bbfcf | ||
|
|
17b0fc0d0c | ||
|
|
3c44c511e4 | ||
|
|
7cf1b9613a | ||
|
|
99e5a9601c | ||
|
|
4c9c1dccf5 | ||
|
|
2cddd5afa0 | ||
|
|
8c6a0c4773 | ||
|
|
af5063552d | ||
|
|
419d154794 | ||
|
|
abda059be5 | ||
|
|
444908cac5 | ||
|
|
c6da26e1a0 | ||
|
|
aad87857ce | ||
|
|
666c113297 | ||
|
|
84a58f34a0 | ||
|
|
75f5b5c721 | ||
|
|
a176a3b79b | ||
|
|
1627a5767a | ||
|
|
6ff3a9e9ab | ||
|
|
3ce2bd30f9 |
@@ -18,4 +18,4 @@ addons:
|
|||||||
install:
|
install:
|
||||||
- export DISPLAY=':99.0'
|
- export DISPLAY=':99.0'
|
||||||
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
||||||
- npm install
|
- npm ci || npm i
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
|||||||
# sapper changelog
|
# sapper changelog
|
||||||
|
|
||||||
|
## 0.15.8
|
||||||
|
|
||||||
|
* Only set `preloading: true` on navigation, not prefetch ([#352](https://github.com/sveltejs/sapper/issues/352))
|
||||||
|
* Provide fallback for missing preload errors ([#361](https://github.com/sveltejs/sapper/pull/361))
|
||||||
|
|
||||||
|
## 0.15.7
|
||||||
|
|
||||||
|
* Strip leading slash from redirects ([#291](https://github.com/sveltejs/sapper/issues/291))
|
||||||
|
* Pass `(req, res)` to store getter ([#344](https://github.com/sveltejs/sapper/issues/344))
|
||||||
|
|
||||||
|
## 0.15.6
|
||||||
|
|
||||||
|
* Fix exporting with custom basepath ([#342](https://github.com/sveltejs/sapper/pull/342))
|
||||||
|
|
||||||
## 0.15.5
|
## 0.15.5
|
||||||
|
|
||||||
* Faster `export` with more explanatory output ([#335](https://github.com/sveltejs/sapper/pull/335))
|
* Faster `export` with more explanatory output ([#335](https://github.com/sveltejs/sapper/pull/335))
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ environment:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: Install-Product node $env:nodejs_version
|
- ps: Install-Product node $env:nodejs_version
|
||||||
- npm install
|
- npm ci
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- node --version && npm --version
|
- node --version && npm --version
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.15.4",
|
"version": "0.15.8",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ async function execute(emitter: EventEmitter, {
|
|||||||
const port = await ports.find(3000);
|
const port = await ports.find(3000);
|
||||||
|
|
||||||
const origin = `http://localhost:${port}`;
|
const origin = `http://localhost:${port}`;
|
||||||
|
const root = new URL(basepath || '', origin);
|
||||||
|
|
||||||
emitter.emit('info', {
|
emitter.emit('info', {
|
||||||
message: `Crawling ${origin}`
|
message: `Crawling ${root.href}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const proc = child_process.fork(path.resolve(`${build}/server.js`), [], {
|
const proc = child_process.fork(path.resolve(`${build}/server.js`), [], {
|
||||||
@@ -71,8 +72,10 @@ async function execute(emitter: EventEmitter, {
|
|||||||
const deferreds = new Map();
|
const deferreds = new Map();
|
||||||
|
|
||||||
function get_deferred(pathname: string) {
|
function get_deferred(pathname: string) {
|
||||||
|
pathname = pathname.replace(root.pathname, '');
|
||||||
|
|
||||||
if (!deferreds.has(pathname)) {
|
if (!deferreds.has(pathname)) {
|
||||||
deferreds.set(pathname, new Deferred()) ;
|
deferreds.set(pathname, new Deferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
return deferreds.get(pathname);
|
return deferreds.get(pathname);
|
||||||
@@ -107,7 +110,7 @@ async function execute(emitter: EventEmitter, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function handle(url: URL) {
|
async function handle(url: URL) {
|
||||||
const pathname = url.pathname || '/';
|
const pathname = (url.pathname.replace(root.pathname, '') || '/');
|
||||||
|
|
||||||
if (seen.has(pathname)) return;
|
if (seen.has(pathname)) return;
|
||||||
seen.add(pathname);
|
seen.add(pathname);
|
||||||
@@ -138,6 +141,9 @@ async function execute(emitter: EventEmitter, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ports.wait(port)
|
return ports.wait(port)
|
||||||
.then(() => handle(new URL(`/${basepath}`, origin))) // TODO all static routes
|
.then(() => {
|
||||||
|
// TODO all static routes
|
||||||
|
return handle(root);
|
||||||
|
})
|
||||||
.then(() => proc.kill());
|
.then(() => proc.kill());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ function toIgnore(uri: string, val: any) {
|
|||||||
|
|
||||||
export default function middleware(opts: {
|
export default function middleware(opts: {
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
store: (req: Req) => Store,
|
store: (req: Req, res: ServerResponse) => Store,
|
||||||
ignore?: any,
|
ignore?: any,
|
||||||
routes?: any // legacy
|
routes?: any // legacy
|
||||||
}) {
|
}) {
|
||||||
@@ -276,7 +276,10 @@ function get_server_route_handler(routes: ServerRoute[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store) {
|
function get_page_handler(
|
||||||
|
manifest: Manifest,
|
||||||
|
store_getter: (req: Req, res: ServerResponse) => Store
|
||||||
|
) {
|
||||||
const output = locations.dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const get_chunks = dev()
|
const get_chunks = dev()
|
||||||
@@ -296,13 +299,10 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
parts: [
|
parts: [
|
||||||
{ name: null, component: error_route }
|
{ name: null, component: error_route }
|
||||||
]
|
]
|
||||||
}, req, res, statusCode, error);
|
}, req, res, statusCode, error || new Error('Unknown error in preload function'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_page(page: Page, req: Req, res: ServerResponse, status = 200, error: Error | string = null) {
|
function handle_page(page: Page, req: Req, res: ServerResponse, status = 200, error: Error | string = null) {
|
||||||
const get_params = page.parts[page.parts.length - 1].params || (() => ({}));
|
|
||||||
const match = error ? null : page.pattern.exec(req.path);
|
|
||||||
|
|
||||||
const chunks: Record<string, string | string[]> = get_chunks();
|
const chunks: Record<string, string | string[]> = get_chunks();
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
res.setHeader('Content-Type', 'text/html');
|
||||||
@@ -326,7 +326,7 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
|
|
||||||
res.setHeader('Link', link);
|
res.setHeader('Link', link);
|
||||||
|
|
||||||
const store = store_getter ? store_getter(req) : null;
|
const store = store_getter ? store_getter(req, res) : null;
|
||||||
|
|
||||||
let redirect: { statusCode: number, location: string };
|
let redirect: { statusCode: number, location: string };
|
||||||
let preload_error: { statusCode: number, message: Error | string };
|
let preload_error: { statusCode: number, message: Error | string };
|
||||||
@@ -336,6 +336,7 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
||||||
throw new Error(`Conflicting redirects`);
|
throw new Error(`Conflicting redirects`);
|
||||||
}
|
}
|
||||||
|
location = location.replace(/^\//g, ''); // leading slash (only)
|
||||||
redirect = { statusCode, location };
|
redirect = { statusCode, location };
|
||||||
},
|
},
|
||||||
error: (statusCode: number, message: Error | string) => {
|
error: (statusCode: number, message: Error | string) => {
|
||||||
@@ -387,6 +388,8 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
})
|
})
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
|
const match = error ? null : page.pattern.exec(req.path);
|
||||||
|
|
||||||
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -136,10 +136,6 @@ function prepare_page(target: Target): Promise<{
|
|||||||
data?: any;
|
data?: any;
|
||||||
nullable_depth?: number;
|
nullable_depth?: number;
|
||||||
}> {
|
}> {
|
||||||
if (root) {
|
|
||||||
root.set({ preloading: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { page, path, query } = target;
|
const { page, path, query } = target;
|
||||||
const new_segments = path.split('/').filter(Boolean);
|
const new_segments = path.split('/').filter(Boolean);
|
||||||
let changed_from = 0;
|
let changed_from = 0;
|
||||||
@@ -285,6 +281,9 @@ async function navigate(target: Target, id: number): Promise<any> {
|
|||||||
|
|
||||||
cid = id;
|
cid = id;
|
||||||
|
|
||||||
|
if (root) {
|
||||||
|
root.set({ preloading: true });
|
||||||
|
}
|
||||||
const loaded = prefetching && prefetching.href === target.url.href ?
|
const loaded = prefetching && prefetching.href === target.url.href ?
|
||||||
prefetching.promise :
|
prefetching.promise :
|
||||||
prepare_page(target);
|
prepare_page(target);
|
||||||
|
|||||||
@@ -85,11 +85,18 @@ const middlewares = [
|
|||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// set up some values for the store
|
||||||
|
(req, res, next) => {
|
||||||
|
req.hello = 'hello';
|
||||||
|
res.locals = { name: 'world' };
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
sapper({
|
sapper({
|
||||||
manifest,
|
manifest,
|
||||||
store: () => {
|
store: (req, res) => {
|
||||||
return new Store({
|
return new Store({
|
||||||
title: 'Stored title'
|
title: `${req.hello} ${res.locals.name}`
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ignore: [
|
ignore: [
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<a href='about'>about</a>
|
<a href='about'>about</a>
|
||||||
<a href='slow-preload'>slow preload</a>
|
<a href='slow-preload'>slow preload</a>
|
||||||
<a href='redirect-from'>redirect</a>
|
<a href='redirect-from'>redirect</a>
|
||||||
|
<a href='redirect-root'>redirect (root)</a>
|
||||||
<a href='blog/nope'>broken link</a>
|
<a href='blog/nope'>broken link</a>
|
||||||
<a href='blog/throw-an-error'>error link</a>
|
<a href='blog/throw-an-error'>error link</a>
|
||||||
<a href='credentials?creds=include'>credentials</a>
|
<a href='credentials?creds=include'>credentials</a>
|
||||||
|
|||||||
7
test/app/routes/redirect-root.html
Normal file
7
test/app/routes/redirect-root.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
preload() {
|
||||||
|
this.redirect(301, '/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -59,9 +59,19 @@ describe('sapper', function() {
|
|||||||
basepath: '/custom-basepath'
|
basepath: '/custom-basepath'
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('export', () => {
|
testExport({});
|
||||||
|
|
||||||
|
testExport({ basepath: '/custom-basepath' });
|
||||||
|
});
|
||||||
|
|
||||||
|
function testExport({ basepath = '' }) {
|
||||||
|
describe(basepath ? `export --basepath ${basepath}` : 'export', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
return exec(`node ${cli} export`);
|
if (basepath) {
|
||||||
|
process.env.BASEPATH = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec(`node ${cli} export ${basepath ? `--basepath ${basepath}` : ''}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('export all pages', () => {
|
it('export all pages', () => {
|
||||||
@@ -96,7 +106,10 @@ describe('sapper', function() {
|
|||||||
'service-worker.js',
|
'service-worker.js',
|
||||||
'svelte-logo-192.png',
|
'svelte-logo-192.png',
|
||||||
'svelte-logo-512.png',
|
'svelte-logo-512.png',
|
||||||
];
|
].map(file => {
|
||||||
|
return basepath ? `${basepath.replace(/^[\/\\]/, '')}/${file}` : file;
|
||||||
|
});
|
||||||
|
|
||||||
// Client scripts that should show up in the extraction directory.
|
// Client scripts that should show up in the extraction directory.
|
||||||
const expectedClientRegexes = [
|
const expectedClientRegexes = [
|
||||||
/client\/[^/]+\/main(\.\d+)?\.js/,
|
/client\/[^/]+\/main(\.\d+)?\.js/,
|
||||||
@@ -126,7 +139,7 @@ describe('sapper', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
function run({ mode, basepath = '' }) {
|
function run({ mode, basepath = '' }) {
|
||||||
describe(`mode=${mode}`, function () {
|
describe(`mode=${mode}`, function () {
|
||||||
@@ -423,6 +436,33 @@ function run({ mode, basepath = '' }) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects on server (root)', () => {
|
||||||
|
return nightmare.goto(`${base}/redirect-root`)
|
||||||
|
.path()
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, `${basepath}/`);
|
||||||
|
})
|
||||||
|
.then(() => nightmare.page.title())
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'Great success!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('redirects in client (root)', () => {
|
||||||
|
return nightmare.goto(base)
|
||||||
|
.wait('[href="redirect-root"]')
|
||||||
|
.click('[href="redirect-root"]')
|
||||||
|
.wait(200)
|
||||||
|
.path()
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, `${basepath}/`);
|
||||||
|
})
|
||||||
|
.then(() => nightmare.page.title())
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'Great success!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('handles 4xx error on server', () => {
|
it('handles 4xx error on server', () => {
|
||||||
return nightmare.goto(`${base}/blog/nope`)
|
return nightmare.goto(`${base}/blog/nope`)
|
||||||
.path()
|
.path()
|
||||||
@@ -568,11 +608,11 @@ function run({ mode, basepath = '' }) {
|
|||||||
return nightmare.goto(`${base}/store`)
|
return nightmare.goto(`${base}/store`)
|
||||||
.page.title()
|
.page.title()
|
||||||
.then(title => {
|
.then(title => {
|
||||||
assert.equal(title, 'Stored title');
|
assert.equal(title, 'hello world');
|
||||||
return nightmare.init().page.title();
|
return nightmare.init().page.title();
|
||||||
})
|
})
|
||||||
.then(title => {
|
.then(title => {
|
||||||
assert.equal(title, 'Stored title');
|
assert.equal(title, 'hello world');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user