csx/examples/cfg/rollup-build.js

167 lines
4.9 KiB
JavaScript

// @cerxes
import {host, Host} from "@cerxes/host";
// Observables
import {Observable} from "zen-observable/lib/Observable";
import {merge, combineLatest, zip} from "zen-observable/lib/extras";
// Rollup and plugins
import * as rollup from 'rollup';
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from "rollup-plugin-json";
import postcss from "rollup-plugin-postcss";
import { terser } from 'rollup-plugin-terser';
/** @type {Host} */
const srcDir = host.from("examples");
/** @type {Host} */
const distDir = host.from("public");
const assetsGlob = `**/*.@(${[
"html",
"otf",
'svg',
'ico',
'png',
'jpg',
'jpeg'
].join('|')})`;
const sourcesGlob = `**/index.@(js|jsx)`;
const args = process.argv.slice(2);
const entryConfig = (entry, output)=>({
input: srcDir.resolve(entry),
output: {
file: distDir.resolve(output),
format: 'esm',
sourcemap: true
},
plugins: [
// json
json(),
// PostCSS-style
postcss({
plugins: [],
inject: false,
minimize: !!args.includes('build')
}),
// babel
babel(),
// node_modules
resolve({
extensions: ['.mjs', '.js', '.jsx', '.json'],
}),
// CJS-modules
commonjs({
namedExports: {
// If there were any...
}
}),
// minify, but only in production
args.includes('build') && terser(),
]
});
function logBundle(output, duration){
let relativeOut = distDir.relative(output);
console.log(relativeOut + " built in " + (duration/1000)+"s");
}
/**
* Build the examples
* @returns {Promise<void>}
*/
async function build(){
// Clean host
await host.remove(distDir.workingDirectory, {recursive: true});
console.log("Dist cleaned!");
let assetsJob = srcDir.glob(assetsGlob).then(
matched=>Promise.all(
matched.map(asset=>host.copy(srcDir.resolve(asset), distDir.resolve(asset)).then(()=>asset))
)
).then((assets)=>{
console.log("Assets copied");
return assets;
});
let sourceJobs = srcDir.glob(sourcesGlob).then(
matched=>Promise.all(
matched.map(async (source)=>{
let sourceStart = new Date();
let entry = source;
let output = distDir.resolve(source,'..','index.js');
let rollupCfg = entryConfig(entry,output);
return await rollup.rollup(rollupCfg).then(async (bundle)=>{
let written = await bundle.write(rollupCfg.output);
logBundle(output, (new Date()).getTime()-sourceStart.getTime());
return {bundle, written};
});
})
)
);
// Wait for both to be done
let [app, assets] = await Promise.all([sourceJobs, assetsJob]);
}
/**
* Watch the app (watch asset files and automatically rebuild, this triggers development mode, as it should never be used on the server!)
*/
async function watch(){
let lastUpdate = new Date();
// Clean host
await host.remove(distDir.workingDirectory, { recursive: true });
console.log("Dist cleaned!");
// Configure a WebPackage (containing build-info)
// Watch sources and map them to an observable
let sourceJobs = await srcDir.glob(sourcesGlob).then(
matched=>matched.map((source)=>{
let entry = source;
let output = distDir.resolve(source,'..','index.js');
let rollupCfg = entryConfig(entry,output);
let sourceWatcher = rollup.watch(rollupCfg);
return new Observable(observer => {
sourceWatcher.on('event', event => {
if(event.code==='BUNDLE_END'){
logBundle(output, event.duration);
observer.next(event);
}else if(event.code==='FATAL'){
observer.complete();
}else if(event.code==='ERROR'){
console.error(event.error.toString());
}
});
return () =>{
// On unsubscription, do what?
};
});
})
);
let assetsObservable = srcDir.watch().glob(assetsGlob).sync(distDir.workingDirectory).map(event=>{
console.log("Assets synced!");
// console.log(event.files.join('\n'));
return event.files;
});
combineLatest(...sourceJobs, assetsObservable).subscribe(async (built)=>{
let newUpdate = new Date();
console.log(`Updated in ${(newUpdate.getTime()- lastUpdate.getTime())/1000}s`);
lastUpdate = newUpdate;
});
}
// Run!
if(args.includes('watch')){
watch();
}else{
build();
}