mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-16 21:04:34 +00:00
@@ -116,10 +116,15 @@ export async function build({
|
|||||||
let serviceworker_stats;
|
let serviceworker_stats;
|
||||||
|
|
||||||
if (serviceworker) {
|
if (serviceworker) {
|
||||||
|
|
||||||
|
const client_files = client_result.chunks
|
||||||
|
.filter(chunk => !chunk.file.endsWith('.map')) // SW does not need to cache sourcemap files
|
||||||
|
.map(chunk => `client/${chunk.file}`);
|
||||||
|
|
||||||
create_serviceworker_manifest({
|
create_serviceworker_manifest({
|
||||||
manifest_data,
|
manifest_data,
|
||||||
output,
|
output,
|
||||||
client_files: client_result.chunks.map(chunk => `client/${chunk.file}`),
|
client_files,
|
||||||
static_files
|
static_files
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
9
test/apps/with-sourcemaps-webpack/src/client.js
Normal file
9
test/apps/with-sourcemaps-webpack/src/client.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import * as sapper from '../__sapper__/client.js';
|
||||||
|
|
||||||
|
window.start = () => sapper.start({
|
||||||
|
target: document.querySelector('#sapper')
|
||||||
|
});
|
||||||
|
|
||||||
|
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
||||||
|
window.prefetch = href => sapper.prefetch(href);
|
||||||
|
window.goto = href => sapper.goto(href);
|
||||||
3
test/apps/with-sourcemaps-webpack/src/routes/_error.html
Normal file
3
test/apps/with-sourcemaps-webpack/src/routes/_error.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<h1>{status}</h1>
|
||||||
|
|
||||||
|
<p>{error.message}</p>
|
||||||
3
test/apps/with-sourcemaps-webpack/src/routes/index.html
Normal file
3
test/apps/with-sourcemaps-webpack/src/routes/index.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<h1>Great success!</h1>
|
||||||
|
|
||||||
|
<p>Woot!</p>
|
||||||
8
test/apps/with-sourcemaps-webpack/src/server.js
Normal file
8
test/apps/with-sourcemaps-webpack/src/server.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import polka from 'polka';
|
||||||
|
import * as sapper from '../__sapper__/server.js';
|
||||||
|
|
||||||
|
const { PORT } = process.env;
|
||||||
|
|
||||||
|
polka()
|
||||||
|
.use(sapper.middleware())
|
||||||
|
.listen(PORT);
|
||||||
82
test/apps/with-sourcemaps-webpack/src/service-worker.js
Normal file
82
test/apps/with-sourcemaps-webpack/src/service-worker.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { timestamp, files, shell, routes } from '../__sapper__/service-worker.js';
|
||||||
|
|
||||||
|
const ASSETS = `cache${timestamp}`;
|
||||||
|
|
||||||
|
// `shell` is an array of all the files generated by webpack,
|
||||||
|
// `files` is an array of everything in the `static` directory
|
||||||
|
const to_cache = shell.concat(ASSETS);
|
||||||
|
const cached = new Set(to_cache);
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches
|
||||||
|
.open(ASSETS)
|
||||||
|
.then(cache => cache.addAll(to_cache))
|
||||||
|
.then(() => {
|
||||||
|
self.skipWaiting();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(async keys => {
|
||||||
|
// delete old caches
|
||||||
|
for (const key of keys) {
|
||||||
|
if (key !== ASSETS) await caches.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clients.claim();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
if (event.request.method !== 'GET') return;
|
||||||
|
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// don't try to handle e.g. data: URIs
|
||||||
|
if (!url.protocol.startsWith('http')) return;
|
||||||
|
|
||||||
|
// ignore dev server requests
|
||||||
|
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||||
|
|
||||||
|
// always serve assets and webpack-generated files from cache
|
||||||
|
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||||
|
event.respondWith(caches.match(event.request));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for pages, you might want to serve a shell `index.html` file,
|
||||||
|
// which Sapper has generated for you. It's not right for every
|
||||||
|
// app, but if it's right for yours then uncomment this section
|
||||||
|
/*
|
||||||
|
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||||
|
event.respondWith(caches.match('/index.html'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event.request.cache === 'only-if-cached') return;
|
||||||
|
|
||||||
|
// for everything else, try the network first, falling back to
|
||||||
|
// cache if the user is offline. (If the pages never change, you
|
||||||
|
// might prefer a cache-first approach to a network-first one.)
|
||||||
|
event.respondWith(
|
||||||
|
caches
|
||||||
|
.open(`offline${timestamp}`)
|
||||||
|
.then(async cache => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(event.request);
|
||||||
|
cache.put(event.request, response.clone());
|
||||||
|
return response;
|
||||||
|
} catch(err) {
|
||||||
|
const response = await cache.match(event.request);
|
||||||
|
if (response) return response;
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
14
test/apps/with-sourcemaps-webpack/src/template.html
Normal file
14
test/apps/with-sourcemaps-webpack/src/template.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
|
||||||
|
%sapper.base%
|
||||||
|
%sapper.styles%
|
||||||
|
%sapper.head%
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id='sapper'>%sapper.html%</div>
|
||||||
|
%sapper.scripts%
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
test/apps/with-sourcemaps-webpack/test.ts
Normal file
43
test/apps/with-sourcemaps-webpack/test.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import * as puppeteer from 'puppeteer';
|
||||||
|
import { build } from '../../../api';
|
||||||
|
import * as assert from "assert";
|
||||||
|
import { AppRunner } from '../AppRunner';
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
describe('with-sourcemaps-webpack', function() {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
|
let runner: AppRunner;
|
||||||
|
let page: puppeteer.Page;
|
||||||
|
let base: string;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
let start: () => Promise<void>;
|
||||||
|
let prefetchRoutes: () => Promise<void>;
|
||||||
|
let prefetch: (href: string) => Promise<void>;
|
||||||
|
let goto: (href: string) => Promise<void>;
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
before(async () => {
|
||||||
|
await build({ cwd: __dirname, bundler: 'webpack' });
|
||||||
|
|
||||||
|
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
||||||
|
({ base, page, start, prefetchRoutes, prefetch, goto } = await runner.start());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not put sourcemap files in service worker shell', async () => {
|
||||||
|
const serviceWorker = await import(`${__dirname}/__sapper__/service-worker.js`);
|
||||||
|
const shell: string[] = serviceWorker.shell;
|
||||||
|
|
||||||
|
assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
|
||||||
|
'sourcemap files are not cached in SW');
|
||||||
|
|
||||||
|
const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
|
||||||
|
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||||
|
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => runner.end());
|
||||||
|
|
||||||
|
});
|
||||||
73
test/apps/with-sourcemaps-webpack/webpack.config.js
Normal file
73
test/apps/with-sourcemaps-webpack/webpack.config.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const webpack = require('webpack');
|
||||||
|
const config = require('../../../config/webpack.js');
|
||||||
|
|
||||||
|
const mode = process.env.NODE_ENV;
|
||||||
|
const dev = mode === 'development';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
client: {
|
||||||
|
entry: config.client.entry(),
|
||||||
|
output: config.client.output(),
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.json', '.html'],
|
||||||
|
mainFields: ['svelte', 'module', 'browser', 'main']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: {
|
||||||
|
loader: 'svelte-loader',
|
||||||
|
options: {
|
||||||
|
dev,
|
||||||
|
hydratable: true,
|
||||||
|
hotReload: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mode,
|
||||||
|
plugins: [
|
||||||
|
dev && new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
].filter(Boolean),
|
||||||
|
devtool: dev ? 'inline-source-map' : 'source-map'
|
||||||
|
},
|
||||||
|
|
||||||
|
server: {
|
||||||
|
entry: config.server.entry(),
|
||||||
|
output: config.server.output(),
|
||||||
|
target: 'node',
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.json', '.html'],
|
||||||
|
mainFields: ['svelte', 'module', 'browser', 'main']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: {
|
||||||
|
loader: 'svelte-loader',
|
||||||
|
options: {
|
||||||
|
css: false,
|
||||||
|
generate: 'ssr',
|
||||||
|
dev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mode: process.env.NODE_ENV
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceworker: {
|
||||||
|
entry: config.serviceworker.entry(),
|
||||||
|
output: config.serviceworker.output(),
|
||||||
|
mode: process.env.NODE_ENV,
|
||||||
|
devtool: 'sourcemap'
|
||||||
|
}
|
||||||
|
};
|
||||||
64
test/apps/with-sourcemaps/rollup.config.js
Normal file
64
test/apps/with-sourcemaps/rollup.config.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import resolve from 'rollup-plugin-node-resolve';
|
||||||
|
import replace from 'rollup-plugin-replace';
|
||||||
|
import svelte from 'rollup-plugin-svelte';
|
||||||
|
|
||||||
|
const mode = process.env.NODE_ENV;
|
||||||
|
const dev = mode === 'development';
|
||||||
|
|
||||||
|
const config = require('../../../config/rollup.js');
|
||||||
|
|
||||||
|
export default {
|
||||||
|
client: {
|
||||||
|
input: config.client.input(),
|
||||||
|
output: Object.assign({}, config.client.output(), { sourcemap: true }),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
dev,
|
||||||
|
hydratable: true,
|
||||||
|
emitCss: true
|
||||||
|
}),
|
||||||
|
resolve()
|
||||||
|
],
|
||||||
|
|
||||||
|
// temporary, pending Rollup 1.0
|
||||||
|
experimentalCodeSplitting: true
|
||||||
|
},
|
||||||
|
|
||||||
|
server: {
|
||||||
|
input: config.server.input(),
|
||||||
|
output: config.server.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': false,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
generate: 'ssr',
|
||||||
|
dev
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
preferBuiltins: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
external: ['sirv', 'polka'],
|
||||||
|
|
||||||
|
// temporary, pending Rollup 1.0
|
||||||
|
experimentalCodeSplitting: true
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceworker: {
|
||||||
|
input: config.serviceworker.input(),
|
||||||
|
output: config.serviceworker.output(),
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
9
test/apps/with-sourcemaps/src/client.js
Normal file
9
test/apps/with-sourcemaps/src/client.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import * as sapper from '../__sapper__/client.js';
|
||||||
|
|
||||||
|
window.start = () => sapper.start({
|
||||||
|
target: document.querySelector('#sapper')
|
||||||
|
});
|
||||||
|
|
||||||
|
window.prefetchRoutes = () => sapper.prefetchRoutes();
|
||||||
|
window.prefetch = href => sapper.prefetch(href);
|
||||||
|
window.goto = href => sapper.goto(href);
|
||||||
3
test/apps/with-sourcemaps/src/routes/_error.html
Normal file
3
test/apps/with-sourcemaps/src/routes/_error.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<h1>{status}</h1>
|
||||||
|
|
||||||
|
<p>{error.message}</p>
|
||||||
3
test/apps/with-sourcemaps/src/routes/index.html
Normal file
3
test/apps/with-sourcemaps/src/routes/index.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<h1>Great success!</h1>
|
||||||
|
|
||||||
|
<p>Woot!</p>
|
||||||
8
test/apps/with-sourcemaps/src/server.js
Normal file
8
test/apps/with-sourcemaps/src/server.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import polka from 'polka';
|
||||||
|
import * as sapper from '../__sapper__/server.js';
|
||||||
|
|
||||||
|
const { PORT } = process.env;
|
||||||
|
|
||||||
|
polka()
|
||||||
|
.use(sapper.middleware())
|
||||||
|
.listen(PORT);
|
||||||
82
test/apps/with-sourcemaps/src/service-worker.js
Normal file
82
test/apps/with-sourcemaps/src/service-worker.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { timestamp, files, shell, routes } from '../__sapper__/service-worker.js';
|
||||||
|
|
||||||
|
const ASSETS = `cache${timestamp}`;
|
||||||
|
|
||||||
|
// `shell` is an array of all the files generated by webpack,
|
||||||
|
// `files` is an array of everything in the `static` directory
|
||||||
|
const to_cache = shell.concat(ASSETS);
|
||||||
|
const cached = new Set(to_cache);
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches
|
||||||
|
.open(ASSETS)
|
||||||
|
.then(cache => cache.addAll(to_cache))
|
||||||
|
.then(() => {
|
||||||
|
self.skipWaiting();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(async keys => {
|
||||||
|
// delete old caches
|
||||||
|
for (const key of keys) {
|
||||||
|
if (key !== ASSETS) await caches.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clients.claim();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
if (event.request.method !== 'GET') return;
|
||||||
|
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// don't try to handle e.g. data: URIs
|
||||||
|
if (!url.protocol.startsWith('http')) return;
|
||||||
|
|
||||||
|
// ignore dev server requests
|
||||||
|
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||||
|
|
||||||
|
// always serve assets and webpack-generated files from cache
|
||||||
|
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||||
|
event.respondWith(caches.match(event.request));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for pages, you might want to serve a shell `index.html` file,
|
||||||
|
// which Sapper has generated for you. It's not right for every
|
||||||
|
// app, but if it's right for yours then uncomment this section
|
||||||
|
/*
|
||||||
|
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||||
|
event.respondWith(caches.match('/index.html'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event.request.cache === 'only-if-cached') return;
|
||||||
|
|
||||||
|
// for everything else, try the network first, falling back to
|
||||||
|
// cache if the user is offline. (If the pages never change, you
|
||||||
|
// might prefer a cache-first approach to a network-first one.)
|
||||||
|
event.respondWith(
|
||||||
|
caches
|
||||||
|
.open(`offline${timestamp}`)
|
||||||
|
.then(async cache => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(event.request);
|
||||||
|
cache.put(event.request, response.clone());
|
||||||
|
return response;
|
||||||
|
} catch(err) {
|
||||||
|
const response = await cache.match(event.request);
|
||||||
|
if (response) return response;
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
14
test/apps/with-sourcemaps/src/template.html
Normal file
14
test/apps/with-sourcemaps/src/template.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
|
||||||
|
%sapper.base%
|
||||||
|
%sapper.styles%
|
||||||
|
%sapper.head%
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id='sapper'>%sapper.html%</div>
|
||||||
|
%sapper.scripts%
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
test/apps/with-sourcemaps/test.ts
Normal file
43
test/apps/with-sourcemaps/test.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import * as puppeteer from 'puppeteer';
|
||||||
|
import { build } from '../../../api';
|
||||||
|
import * as assert from "assert";
|
||||||
|
import { AppRunner } from '../AppRunner';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
describe('with-sourcemaps', function() {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
|
let runner: AppRunner;
|
||||||
|
let page: puppeteer.Page;
|
||||||
|
let base: string;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
let start: () => Promise<void>;
|
||||||
|
let prefetchRoutes: () => Promise<void>;
|
||||||
|
let prefetch: (href: string) => Promise<void>;
|
||||||
|
let goto: (href: string) => Promise<void>;
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
before(async () => {
|
||||||
|
await build({ cwd: __dirname });
|
||||||
|
|
||||||
|
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
||||||
|
({ base, page, start, prefetchRoutes, prefetch, goto } = await runner.start());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not put sourcemap files in service worker shell', async () => {
|
||||||
|
const serviceWorker = await import(`${__dirname}/__sapper__/service-worker.js`);
|
||||||
|
const shell: string[] = serviceWorker.shell;
|
||||||
|
|
||||||
|
assert.equal(shell.filter(_ => _.endsWith('.map')).length, 0,
|
||||||
|
'sourcemap files are not cached in SW');
|
||||||
|
|
||||||
|
const clientShellDir = path.resolve(`${__dirname}/__sapper__/build`, path.dirname(shell[0]));
|
||||||
|
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||||
|
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => runner.end());
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user