create build API

This commit is contained in:
Rich Harris
2018-05-22 11:32:06 -04:00
parent 86f71e1faf
commit 4f49fd8d5c
7 changed files with 146 additions and 80 deletions

110
src/api/build.ts Normal file
View File

@@ -0,0 +1,110 @@
import * as fs from 'fs';
import * as path from 'path';
import mkdirp from 'mkdirp';
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 { locations } from '../config';
export default function build(opts: {}) {
const emitter = new EventEmitter();
execute(emitter, opts).then(
() => {
emitter.emit('done', {}); // TODO do we need to pass back any info?
},
error => {
emitter.emit('error', {
error
});
}
);
return emitter;
}
async function execute(emitter: EventEmitter, {
dest = 'build',
app = 'app',
webpack = 'webpack',
routes = 'routes'
} = {}) {
mkdirp.sync(dest);
rimraf.sync(path.join(dest, '**/*'));
// minify app/template.html
// TODO compile this to a function? could be quicker than str.replace(...).replace(...).replace(...)
const template = fs.readFileSync(`${app}/template.html`, 'utf-8');
// remove this in a future version
if (template.indexOf('%sapper.base%') === -1) {
const error = new Error(`As of Sapper v0.10, your template.html file must include %sapper.base% in the <head>`);
error.code = `missing-sapper-base`;
throw error;
}
fs.writeFileSync(`${dest}/template.html`, minify_html(template));
const route_objects = create_routes();
// create app/manifest/client.js and app/manifest/server.js
create_main_manifests({ routes: route_objects });
const { client, server, serviceworker } = create_compilers({ webpack });
const client_stats = await compile(client);
emitter.emit('build', {
type: 'client',
// TODO duration/warnings
webpack_stats: client_stats
});
fs.writeFileSync(path.join(dest, 'client_info.json'), JSON.stringify({
assets: client_stats.toJson().assetsByChunkName
}));
const server_stats = await compile(server);
emitter.emit('build', {
type: 'server',
// TODO duration/warnings
webpack_stats: server_stats
});
let serviceworker_stats;
if (serviceworker) {
create_serviceworker_manifest({
routes: route_objects,
client_files: client_stats.toJson().assets.map((chunk: { name: string }) => `client/${chunk.name}`)
});
serviceworker_stats = await compile(serviceworker);
emitter.emit('build', {
type: 'serviceworker',
// TODO duration/warnings
webpack_stats: serviceworker_stats
});
}
}
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);
}
});
});
}

0
src/api/dev.ts Normal file
View File

0
src/api/export.ts Normal file
View File

View File

@@ -0,0 +1,21 @@
import { minify } from 'html-minifier';
export function minify_html(html: string) {
return minify(html, {
collapseBooleanAttributes: true,
collapseWhitespace: true,
conservativeCollapse: true,
decodeEntities: true,
html5: true,
minifyCSS: true,
minifyJS: true,
removeAttributeQuotes: true,
removeComments: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true
});
}