create a facade over webpack, to support alternative compilers

This commit is contained in:
Rich Harris
2018-08-25 09:11:45 -04:00
parent d5bf206d2a
commit 24f2855f89
4 changed files with 104 additions and 50 deletions

View File

@@ -5,6 +5,7 @@ import rimraf from 'rimraf';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import minify_html from './utils/minify_html'; import minify_html from './utils/minify_html';
import { create_compilers, create_main_manifests, create_routes, create_serviceworker_manifest } from '../core'; 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 * as events from './interfaces';
export function build(opts: {}) { export function build(opts: {}) {
@@ -28,6 +29,7 @@ async function execute(emitter: EventEmitter, {
dest = 'build', dest = 'build',
app = 'app', app = 'app',
webpack = 'webpack', webpack = 'webpack',
rollup = 'rollup',
routes = 'routes' routes = 'routes'
} = {}) { } = {}) {
mkdirp.sync(dest); mkdirp.sync(dest);
@@ -51,9 +53,9 @@ async function execute(emitter: EventEmitter, {
// create app/manifest/client.js and app/manifest/server.js // create app/manifest/client.js and app/manifest/server.js
create_main_manifests({ routes: route_objects }); create_main_manifests({ routes: route_objects });
const { client, server, serviceworker } = create_compilers({ webpack }); const { client, server, serviceworker } = create_compilers({ webpack, rollup });
const client_stats = await compile(client); const client_stats = await client.compile();
emitter.emit('build', <events.BuildEvent>{ emitter.emit('build', <events.BuildEvent>{
type: 'client', type: 'client',
// TODO duration/warnings // TODO duration/warnings
@@ -63,7 +65,7 @@ async function execute(emitter: EventEmitter, {
const client_info = client_stats.toJson(); const client_info = client_stats.toJson();
fs.writeFileSync(path.join(dest, 'client_assets.json'), JSON.stringify(client_info.assetsByChunkName)); fs.writeFileSync(path.join(dest, 'client_assets.json'), JSON.stringify(client_info.assetsByChunkName));
const server_stats = await compile(server); const server_stats = await server.compile();
emitter.emit('build', <events.BuildEvent>{ emitter.emit('build', <events.BuildEvent>{
type: 'server', type: 'server',
// TODO duration/warnings // TODO duration/warnings
@@ -78,7 +80,7 @@ async function execute(emitter: EventEmitter, {
client_files: client_stats.toJson().assets.map((chunk: { name: string }) => `client/${chunk.name}`) client_files: client_stats.toJson().assets.map((chunk: { name: string }) => `client/${chunk.name}`)
}); });
serviceworker_stats = await compile(serviceworker); serviceworker_stats = await serviceworker.compile();
emitter.emit('build', <events.BuildEvent>{ emitter.emit('build', <events.BuildEvent>{
type: 'serviceworker', type: 'serviceworker',
@@ -87,23 +89,3 @@ async function execute(emitter: EventEmitter, {
}); });
} }
} }
function compile(compiler: any) {
return new Promise((fulfil, reject) => {
compiler.run((err: Error, stats: any) => {
if (err) {
reject(err);
process.exit(1);
}
if (stats.hasErrors()) {
console.error(stats.toString({ colors: true }));
reject(new Error(`Encountered errors while building app`));
}
else {
fulfil(stats);
}
});
});
}

View File

@@ -9,6 +9,7 @@ import format_messages from 'webpack-format-messages';
import { locations } from '../config'; import { locations } from '../config';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { create_routes, create_main_manifests, create_compilers, create_serviceworker_manifest } from '../core'; import { create_routes, create_main_manifests, create_compilers, create_serviceworker_manifest } from '../core';
import { Compiler, Compilers } from '../core/create_compilers';
import Deferred from './utils/Deferred'; import Deferred from './utils/Deferred';
import * as events from './interfaces'; import * as events from './interfaces';
@@ -155,7 +156,10 @@ class Watcher extends EventEmitter {
}; };
// TODO watch the configs themselves? // TODO watch the configs themselves?
const compilers = create_compilers({ webpack: this.dirs.webpack }); const compilers: Compilers = create_compilers({
webpack: this.dirs.webpack,
rollup: this.dirs.rollup
});
let log = ''; let log = '';
@@ -332,16 +336,14 @@ class Watcher extends EventEmitter {
} }
} }
watch(compiler: any, { name, invalid = noop, result }: { watch(compiler: Compiler, { name, invalid = noop, result }: {
name: string, name: string,
invalid?: (filename: string) => void; invalid?: (filename: string) => void;
result: (stats: any) => void; result: (stats: any) => void;
}) { }) {
compiler.hooks.invalid.tap('sapper', (filename: string) => { compiler.oninvalid(invalid);
invalid(filename);
});
compiler.watch({}, (err: Error, stats: any) => { compiler.watch((err: Error, stats: any) => {
if (err) { if (err) {
this.emit('error', <events.ErrorEvent>{ this.emit('error', <events.ErrorEvent>{
type: name, type: name,

View File

@@ -9,7 +9,8 @@ export function build() {
dest: locations.dest(), dest: locations.dest(),
app: locations.app(), app: locations.app(),
routes: locations.routes(), routes: locations.routes(),
webpack: 'webpack' webpack: 'webpack',
rollup: 'rollup'
}); });
emitter.on('build', event => { emitter.on('build', event => {

View File

@@ -1,29 +1,98 @@
import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import relative from 'require-relative'; import relative from 'require-relative';
export default function create_compilers({ webpack }: { webpack: string }) { let r: any;
const wp = relative('webpack', process.cwd()); let wp: any;
const serviceworker_config = try_require(path.resolve(`${webpack}/service-worker.config.js`)); export class WebpackCompiler {
_: any;
constructor(config: any) {
this._ = wp(require(path.resolve(config)));
}
oninvalid(cb: (filename: string) => void) {
this._.hooks.invalid.tap('sapper', cb);
}
compile() {
return new Promise((fulfil, reject) => {
this._.run((err: Error, stats: any) => {
if (err) {
reject(err);
process.exit(1);
}
if (stats.hasErrors()) {
console.error(stats.toString({ colors: true }));
reject(new Error(`Encountered errors while building app`));
}
else {
fulfil(stats);
}
});
});
}
watch(cb: (err: Error, stats: any) => void) {
this._.watch({}, cb);
}
}
export class RollupCompiler {
constructor(config: any) {
}
oninvalid(cb: (filename: string) => void) {
}
compile() {
return new Promise((fulfil, reject) => {
});
}
watch(cb: (err: Error, stats: any) => void) {
}
}
export type Compiler = RollupCompiler | WebpackCompiler;
export type Compilers = {
client: Compiler;
server: Compiler;
serviceworker?: Compiler;
}
export default function create_compilers({ webpack, rollup }: { webpack: string, rollup: string }): Compilers {
if (fs.existsSync(rollup)) {
if (!r) r = relative('rollup', process.cwd());
const sw = `${rollup}/service-worker.config.js`;
return { return {
client: wp( client: new RollupCompiler(`${rollup}/client.config.js`),
require(path.resolve(`${webpack}/client.config.js`)) server: new RollupCompiler(`${rollup}/server.config.js`),
), serviceworker: fs.existsSync(sw) && new RollupCompiler(sw)
server: wp(
require(path.resolve(`${webpack}/server.config.js`))
),
serviceworker: serviceworker_config && wp(serviceworker_config)
}; };
} }
function try_require(specifier: string) { if (fs.existsSync(webpack)) {
try { if (!wp) wp = relative('webpack', process.cwd());
return require(specifier);
} catch (err) { const sw = `${webpack}/service-worker.config.js`;
if (err.code === 'MODULE_NOT_FOUND') return null;
throw err; return {
client: new WebpackCompiler(`${webpack}/client.config.js`),
server: new WebpackCompiler(`${webpack}/server.config.js`),
serviceworker: fs.existsSync(sw) && new WebpackCompiler(sw)
};
} }
throw new Error(`Could not find config files for rollup or webpack`);
} }