mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-15 12:24:47 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31110a5326 | ||
|
|
667a68768c | ||
|
|
5075981a90 | ||
|
|
611dc4f6be | ||
|
|
0b43eaa992 | ||
|
|
47cdc1c4c8 | ||
|
|
31c071ad72 | ||
|
|
e91edaee12 | ||
|
|
34c1fee5db | ||
|
|
5375422633 | ||
|
|
1dafe934b0 | ||
|
|
e1a33c6a9b | ||
|
|
0800fa016b | ||
|
|
8f3454c3b1 | ||
|
|
f0d7a1aaab |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,5 +1,22 @@
|
|||||||
# sapper changelog
|
# sapper changelog
|
||||||
|
|
||||||
|
## 0.13.5
|
||||||
|
|
||||||
|
* Fix handling of fatal errors ([#289](https://github.com/sveltejs/sapper/issues/289))
|
||||||
|
|
||||||
|
## 0.13.4
|
||||||
|
|
||||||
|
* Focus `<body>` after navigation ([#287](https://github.com/sveltejs/sapper/issues/287))
|
||||||
|
* Fix timing of hot reload updates
|
||||||
|
* Emit `fatal` event if server crashes ([#285](https://github.com/sveltejs/sapper/pull/285))
|
||||||
|
* Emit `stdout` and `stderr` events on dev watcher ([#285](https://github.com/sveltejs/sapper/pull/285))
|
||||||
|
* Always refresh client assets in dev ([#286](https://github.com/sveltejs/sapper/pull/286))
|
||||||
|
* Correctly initialise rebuild stats
|
||||||
|
|
||||||
|
## 0.13.3
|
||||||
|
|
||||||
|
* Make `fatal` events clonable for IPC purposes
|
||||||
|
|
||||||
## 0.13.2
|
## 0.13.2
|
||||||
|
|
||||||
* Emit a `basepath` event ([#284](https://github.com/sveltejs/sapper/pull/284))
|
* Emit a `basepath` event ([#284](https://github.com/sveltejs/sapper/pull/284))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.13.2",
|
"version": "0.13.5",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class Watcher extends EventEmitter {
|
|||||||
server: Deferred;
|
server: Deferred;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
crashed: boolean;
|
||||||
restarting: boolean;
|
restarting: boolean;
|
||||||
current_build: {
|
current_build: {
|
||||||
changed: Set<string>;
|
changed: Set<string>;
|
||||||
@@ -90,7 +91,7 @@ class Watcher extends EventEmitter {
|
|||||||
if (this.port) {
|
if (this.port) {
|
||||||
if (!await ports.check(this.port)) {
|
if (!await ports.check(this.port)) {
|
||||||
this.emit('fatal', <events.FatalEvent>{
|
this.emit('fatal', <events.FatalEvent>{
|
||||||
error: new Error(`Port ${this.port} is unavailable`)
|
message: `Port ${this.port} is unavailable`
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -130,6 +131,18 @@ class Watcher extends EventEmitter {
|
|||||||
// TODO watch the configs themselves?
|
// TODO watch the configs themselves?
|
||||||
const compilers = create_compilers({ webpack: this.dirs.webpack });
|
const compilers = create_compilers({ webpack: this.dirs.webpack });
|
||||||
|
|
||||||
|
let log = '';
|
||||||
|
|
||||||
|
const emitFatal = () => {
|
||||||
|
this.emit('fatal', <events.FatalEvent>{
|
||||||
|
message: `Server crashed`,
|
||||||
|
log
|
||||||
|
});
|
||||||
|
|
||||||
|
this.crashed = true;
|
||||||
|
this.proc = null;
|
||||||
|
};
|
||||||
|
|
||||||
this.watch(compilers.server, {
|
this.watch(compilers.server, {
|
||||||
name: 'server',
|
name: 'server',
|
||||||
|
|
||||||
@@ -142,22 +155,35 @@ class Watcher extends EventEmitter {
|
|||||||
fs.writeFileSync(path.join(dest, 'server_info.json'), JSON.stringify(info, null, ' '));
|
fs.writeFileSync(path.join(dest, 'server_info.json'), JSON.stringify(info, null, ' '));
|
||||||
|
|
||||||
this.deferreds.client.promise.then(() => {
|
this.deferreds.client.promise.then(() => {
|
||||||
this.dev_server.send({
|
|
||||||
status: 'completed'
|
|
||||||
});
|
|
||||||
|
|
||||||
const restart = () => {
|
const restart = () => {
|
||||||
ports.wait(this.port).then((() => {
|
log = '';
|
||||||
this.emit('ready', <events.ReadyEvent>{
|
this.crashed = false;
|
||||||
port: this.port,
|
|
||||||
process: this.proc
|
|
||||||
});
|
|
||||||
|
|
||||||
this.deferreds.server.fulfil();
|
ports.wait(this.port)
|
||||||
}));
|
.then((() => {
|
||||||
|
this.emit('ready', <events.ReadyEvent>{
|
||||||
|
port: this.port,
|
||||||
|
process: this.proc
|
||||||
|
});
|
||||||
|
|
||||||
|
this.deferreds.server.fulfil();
|
||||||
|
|
||||||
|
this.dev_server.send({
|
||||||
|
status: 'completed'
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
.catch(err => {
|
||||||
|
if (this.crashed) return;
|
||||||
|
|
||||||
|
this.emit('fatal', <events.FatalEvent>{
|
||||||
|
message: `Server is not listening on port ${this.port}`,
|
||||||
|
log
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.proc) {
|
if (this.proc) {
|
||||||
|
this.proc.removeListener('exit', emitFatal);
|
||||||
this.proc.kill();
|
this.proc.kill();
|
||||||
this.proc.on('exit', restart);
|
this.proc.on('exit', restart);
|
||||||
} else {
|
} else {
|
||||||
@@ -172,6 +198,16 @@ class Watcher extends EventEmitter {
|
|||||||
stdio: ['ipc']
|
stdio: ['ipc']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.proc.stdout.on('data', chunk => {
|
||||||
|
log += chunk;
|
||||||
|
this.emit('stdout', chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.proc.stderr.on('data', chunk => {
|
||||||
|
log += chunk;
|
||||||
|
this.emit('stderr', chunk);
|
||||||
|
});
|
||||||
|
|
||||||
this.proc.on('message', message => {
|
this.proc.on('message', message => {
|
||||||
if (message.__sapper__ && message.event === 'basepath') {
|
if (message.__sapper__ && message.event === 'basepath') {
|
||||||
this.emit('basepath', {
|
this.emit('basepath', {
|
||||||
@@ -179,6 +215,8 @@ class Watcher extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.proc.on('exit', emitFatal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -250,8 +288,8 @@ class Watcher extends EventEmitter {
|
|||||||
this.restarting = true;
|
this.restarting = true;
|
||||||
|
|
||||||
this.current_build = {
|
this.current_build = {
|
||||||
changed: new Set(),
|
changed: new Set([filename]),
|
||||||
rebuilding: new Set(),
|
rebuilding: new Set([type]),
|
||||||
unique_warnings: new Set(),
|
unique_warnings: new Set(),
|
||||||
unique_errors: new Set()
|
unique_errors: new Set()
|
||||||
};
|
};
|
||||||
@@ -284,7 +322,7 @@ class Watcher extends EventEmitter {
|
|||||||
if (err) {
|
if (err) {
|
||||||
this.emit('error', <events.ErrorEvent>{
|
this.emit('error', <events.ErrorEvent>{
|
||||||
type: name,
|
type: name,
|
||||||
error: err
|
message: err.message
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const messages = format_messages(stats);
|
const messages = format_messages(stats);
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ export type ReadyEvent = {
|
|||||||
|
|
||||||
export type ErrorEvent = {
|
export type ErrorEvent = {
|
||||||
type: string;
|
type: string;
|
||||||
error: Error;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FatalEvent = {
|
export type FatalEvent = {
|
||||||
error: Error;
|
message: string;
|
||||||
|
log?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InvalidEvent = {
|
export type InvalidEvent = {
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ export function dev(opts: { port: number, open: boolean }) {
|
|||||||
|
|
||||||
watcher.on('error', (event: events.ErrorEvent) => {
|
watcher.on('error', (event: events.ErrorEvent) => {
|
||||||
console.log(`${colors.red(`✗ ${event.type}`)}`);
|
console.log(`${colors.red(`✗ ${event.type}`)}`);
|
||||||
console.log(`${colors.red(event.error.message)}`);
|
console.log(`${colors.red(event.message)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on('fatal', (event: events.FatalEvent) => {
|
watcher.on('fatal', (event: events.FatalEvent) => {
|
||||||
console.log(`${colors.bold.red(`> ${event.error.message}`)}`);
|
console.log(`${colors.bold.red(`> ${event.message}`)}`);
|
||||||
|
if (event.log) console.log(event.log);
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on('build', (event: events.BuildEvent) => {
|
watcher.on('build', (event: events.BuildEvent) => {
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ export default function middleware({ App, routes, store }: {
|
|||||||
|
|
||||||
const output = locations.dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const client_assets = JSON.parse(fs.readFileSync(path.join(output, 'client_assets.json'), 'utf-8'));
|
|
||||||
|
|
||||||
let emitted_basepath = false;
|
let emitted_basepath = false;
|
||||||
|
|
||||||
const middleware = compose_handlers([
|
const middleware = compose_handlers([
|
||||||
@@ -105,7 +103,7 @@ export default function middleware({ App, routes, store }: {
|
|||||||
cache_control: 'max-age=31536000'
|
cache_control: 'max-age=31536000'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
get_route_handler(client_assets, App, routes, store)
|
get_route_handler(App, routes, store)
|
||||||
].filter(Boolean));
|
].filter(Boolean));
|
||||||
|
|
||||||
return middleware;
|
return middleware;
|
||||||
@@ -148,7 +146,13 @@ function serve({ prefix, pathname, cache_control }: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_route_handler(chunks: Record<string, string>, App: Component, routes: RouteObject[], store_getter: (req: Req) => Store) {
|
function get_route_handler(App: Component, routes: RouteObject[], store_getter: (req: Req) => Store) {
|
||||||
|
const output = locations.dest();
|
||||||
|
|
||||||
|
const get_chunks = dev()
|
||||||
|
? () => JSON.parse(fs.readFileSync(path.join(output, 'client_assets.json'), 'utf-8'))
|
||||||
|
: (assets => () => assets)(JSON.parse(fs.readFileSync(path.join(output, 'client_assets.json'), 'utf-8')));
|
||||||
|
|
||||||
const template = dev()
|
const template = dev()
|
||||||
? () => fs.readFileSync(`${locations.app()}/template.html`, 'utf-8')
|
? () => fs.readFileSync(`${locations.app()}/template.html`, 'utf-8')
|
||||||
: (str => () => str)(fs.readFileSync(`${locations.dest()}/template.html`, 'utf-8'));
|
: (str => () => str)(fs.readFileSync(`${locations.dest()}/template.html`, 'utf-8'));
|
||||||
@@ -159,6 +163,8 @@ function get_route_handler(chunks: Record<string, string>, App: Component, route
|
|||||||
const handlers = route.handlers[Symbol.iterator]();
|
const handlers = route.handlers[Symbol.iterator]();
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
|
const chunks: Record<string, string> = get_chunks();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { value: handler, done } = handlers.next();
|
const { value: handler, done } = handlers.next();
|
||||||
|
|
||||||
@@ -384,7 +390,7 @@ function get_route_handler(chunks: Record<string, string>, App: Component, route
|
|||||||
function render_page({ head, css, html }) {
|
function render_page({ head, css, html }) {
|
||||||
const page = template()
|
const page = template()
|
||||||
.replace('%sapper.base%', `<base href="${req.baseUrl}/">`)
|
.replace('%sapper.base%', `<base href="${req.baseUrl}/">`)
|
||||||
.replace('%sapper.scripts%', `<script>__SAPPER__={baseUrl: "${req.baseUrl}"}</script><script src='${req.baseUrl}/client/${chunks.main}'></script>`)
|
.replace('%sapper.scripts%', `<script>__SAPPER__={baseUrl: "${req.baseUrl}"}</script><script src='${req.baseUrl}/client/${get_chunks().main}'></script>`)
|
||||||
.replace('%sapper.html%', html)
|
.replace('%sapper.html%', html)
|
||||||
.replace('%sapper.head%', `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`)
|
.replace('%sapper.head%', `<noscript id='sapper-head-start'></noscript>${head}<noscript id='sapper-head-end'></noscript>`)
|
||||||
.replace('%sapper.styles%', (css && css.code ? `<style>${css.code}</style>` : ''));
|
.replace('%sapper.styles%', (css && css.code ? `<style>${css.code}</style>` : ''));
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ function navigate(target: Target, id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(Page, props, scroll_history[id], token);
|
render(Page, props, scroll_history[id], token);
|
||||||
|
document.activeElement.blur();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -608,6 +608,19 @@ function run({ mode, basepath = '' }) {
|
|||||||
it('emits a basepath', () => {
|
it('emits a basepath', () => {
|
||||||
assert.equal(captured_basepath, basepath);
|
assert.equal(captured_basepath, basepath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// skipped because Nightmare doesn't seem to focus the <a> correctly
|
||||||
|
it.skip('resets the active element after navigation', () => {
|
||||||
|
return nightmare
|
||||||
|
.goto(base)
|
||||||
|
.init()
|
||||||
|
.click('a[href="about"]')
|
||||||
|
.wait(100)
|
||||||
|
.evaluate(() => document.activeElement.nodeName)
|
||||||
|
.then(name => {
|
||||||
|
assert.equal(name, 'BODY');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('headers', () => {
|
describe('headers', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user