Merge pull request #397 from sveltejs/gh-280

Implement differential bundling
This commit is contained in:
Rich Harris
2018-08-31 16:39:20 -04:00
committed by GitHub
7 changed files with 90 additions and 45 deletions

View File

@@ -5,9 +5,7 @@ import rimraf from 'rimraf';
import { EventEmitter } from 'events';
import minify_html from './utils/minify_html';
import { create_compilers, create_main_manifests, create_routes, create_serviceworker_manifest } from '../core';
import { Compilers, Compiler } from '../core/create_compilers';
import * as events from './interfaces';
import validate_bundler from '../cli/utils/validate_bundler';
import { copy_shimport } from './utils/copy_shimport';
export function build(opts: {}) {
@@ -30,6 +28,7 @@ export function build(opts: {}) {
async function execute(emitter: EventEmitter, {
dest = 'build',
app = 'app',
legacy,
bundler,
webpack = 'webpack',
rollup = 'rollup',
@@ -57,7 +56,7 @@ async function execute(emitter: EventEmitter, {
// create app/manifest/client.js and app/manifest/server.js
create_main_manifests({ bundler, routes: route_objects });
const { client, server, serviceworker } = create_compilers(validate_bundler(bundler), { webpack, rollup });
const { client, server, serviceworker } = create_compilers(bundler, { webpack, rollup });
const client_result = await client.compile();
emitter.emit('build', <events.BuildEvent>{
@@ -66,11 +65,34 @@ async function execute(emitter: EventEmitter, {
result: client_result
});
fs.writeFileSync(path.join(dest, 'build.json'), JSON.stringify({
const build_info: {
bundler: string;
shimport: string;
assets: Record<string, string>;
legacy_assets?: Record<string, string>;
} = {
bundler,
shimport: bundler === 'rollup' && require('shimport/package.json').version,
assets: client_result.assets
}));
};
if (legacy) {
process.env.SAPPER_LEGACY_BUILD = 'true';
const { client } = create_compilers(bundler, { webpack, rollup });
const client_result = await client.compile();
emitter.emit('build', <events.BuildEvent>{
type: 'client (legacy)',
// TODO duration/warnings
result: client_result
});
build_info.legacy_assets = client_result.assets;
delete process.env.SAPPER_LEGACY_BUILD;
}
fs.writeFileSync(path.join(dest, 'build.json'), JSON.stringify(build_info));
const server_stats = await server.compile();
emitter.emit('build', <events.BuildEvent>{

View File

@@ -31,8 +31,13 @@ prog.command('build [dest]')
.describe('Create a production-ready version of your app')
.option('-p, --port', 'Default of process.env.PORT', '3000')
.option('--bundler', 'Specify a bundler (rollup or webpack, blank for auto)')
.option('--legacy', 'Create separate legacy build')
.example(`build custom-dir -p 4567`)
.action(async (dest = 'build', opts: { port: string, bundler?: string }) => {
.action(async (dest = 'build', opts: {
port: string,
legacy: boolean,
bundler?: string
}) => {
console.log(`> Building...`);
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
@@ -78,9 +83,11 @@ prog.command('export [dest]')
.option('--build-dir', 'Specify a custom temporary build directory', '.sapper/prod')
.option('--basepath', 'Specify a base path')
.option('--timeout', 'Milliseconds to wait for a page (--no-timeout to disable)', 5000)
.option('--legacy', 'Create separate legacy build')
.option('--bundler', 'Specify a bundler (rollup or webpack, blank for auto)')
.action(async (dest = 'export', opts: {
build: boolean,
legacy: boolean,
bundler?: string,
'build-dir': string,
basepath?: string,

View File

@@ -4,15 +4,20 @@ import { locations } from '../config';
import validate_bundler from './utils/validate_bundler';
import { repeat } from '../utils';
export function build(opts: { bundler?: string }) {
export function build(opts: { bundler?: string, legacy?: boolean }) {
const bundler = validate_bundler(opts.bundler);
if (opts.legacy && bundler === 'webpack') {
throw new Error(`Legacy builds are not supported for projects using webpack`);
}
return new Promise((fulfil, reject) => {
try {
const emitter = _build({
dest: locations.dest(),
app: locations.app(),
routes: locations.routes(),
legacy: opts.legacy,
bundler,
webpack: 'webpack',
rollup: 'rollup'

View File

@@ -306,7 +306,8 @@ function get_page_handler(
const build_info: {
bundler: 'rollup' | 'webpack',
shimport: string | null,
assets: Record<string, string | string[]>
assets: Record<string, string | string[]>,
legacy_assets?: Record<string, string>
} = get_build_info();
res.setHeader('Content-Type', 'text/html');
@@ -472,14 +473,7 @@ function get_page_handler(
store
});
const file = [].concat(build_info.assets.main).filter(file => file && /\.js$/.test(file))[0];
const main = `${req.baseUrl}/client/${file}`;
const script = build_info.bundler === 'rollup'
? `<script>try{new Function("import('${main}')")();}catch(e){var s=document.createElement("script");s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main","${main}");document.head.appendChild(s);}</script>`
: `<script src="${main}"></script>`;
let inline_script = `__SAPPER__={${[
let script = `__SAPPER__={${[
error && `error:1`,
`baseUrl:"${req.baseUrl}"`,
serialized.preloaded && `preloaded:${serialized.preloaded}`,
@@ -488,12 +482,26 @@ function get_page_handler(
const has_service_worker = fs.existsSync(path.join(locations.dest(), 'service-worker.js'));
if (has_service_worker) {
inline_script += `if ('serviceWorker' in navigator) navigator.serviceWorker.register('${req.baseUrl}/service-worker.js');`;
script += `if('serviceWorker' in navigator)navigator.serviceWorker.register('${req.baseUrl}/service-worker.js');`;
}
const file = [].concat(build_info.assets.main).filter(file => file && /\.js$/.test(file))[0];
const main = `${req.baseUrl}/client/${file}`;
if (build_info.bundler === 'rollup') {
if (build_info.legacy_assets) {
const legacy_main = `${req.baseUrl}/client/legacy/${build_info.legacy_assets.main}`;
script += `(function(){try{eval("async function x(){}");var main="${main}"}catch(e){main="${legacy_main}"};try{new Function("import('"+main+"')")();}catch(e){var s=document.createElement("script");s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main",main);document.head.appendChild(s);}}());`;
} else {
script += `try{new Function("import('${main}')")();}catch(e){var s=document.createElement("script");s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main","${main}");document.head.appendChild(s);}`;
}
} else {
script += `</script><script src="${main}">`;
}
const body = template()
.replace('%sapper.base%', () => `<base href="${req.baseUrl}/">`)
.replace('%sapper.scripts%', () => `<script>${inline_script}</script>${script}`)
.replace('%sapper.scripts%', () => `<script>${script}</script>`)
.replace('%sapper.html%', () => html)
.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>` : ''));

View File

@@ -9,8 +9,11 @@ export default {
},
output: () => {
let dir = `${locations.dest()}/client`;
if (process.env.SAPPER_LEGACY_BUILD) dir += `/legacy`;
return {
dir: `${locations.dest()}/client`,
dir,
entryFileNames: '[name].[hash].js',
chunkFileNames: '[name].[hash].js',
format: 'esm'