zarbis
Version:
Configuration-less build tool
127 lines • 5.04 kB
JavaScript
import { walkDirArray } from '@meteor-it/fs';
import { isLeft, isRight } from 'fp-ts/lib/Either.js';
import { PathReporter } from 'io-ts/lib/PathReporter.js';
import { dirname, resolve, sep } from 'path';
import webpack from 'webpack';
import { Config } from './config.js';
import mkConfig from './webpackConfigGenerator.js';
import winston from 'winston';
export function asyncEach(iterable, cb) {
let waitings = [];
iterable.forEach(iter => {
waitings.push(cb(iter));
});
return Promise.all(waitings);
}
// Logger.addReceiver(new NodeReceiver(7));
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
format: winston.format.cli(),
})
]
});
logger.info('Zarbis-Build');
process.noDeprecation = true;
async function discoverTargets(srcDir) {
let files = await walkDirArray(srcDir);
files = files.map(file => file.split(sep)).filter(file => file[file.length - 1].startsWith('.target-')).map(file => file.join(sep));
logger.info(`Found ${files.length} possible targets:`);
logger.info(`Validating and getting info`);
const targets = (await asyncEach(files, async (path) => {
const split = path.split(sep);
const dir = dirname(path);
let targetName = split[split.length - 1].replace('.target-', '');
if (targetName.endsWith('.ts') || targetName.endsWith('.js')) {
targetName = targetName.replace(/\.[tj]s$/, '');
}
else {
throw new Error(`Plaintext configuration is deprecated`);
}
if (!/[a-zA-Z0-9а-яА-Я_]/.test(targetName))
throw new Error(`Target name contains not allowed characters! (At ${path})`);
const decoded = Config.decode((await import(path)).default);
if (isRight(decoded)) {
const config = decoded.right;
if (!config.entrypoints) {
config.entrypoints = {};
}
config.entrypoints['main'] = [resolve(dir, config.entrypoint)];
return {
targetName,
config: decoded.right
};
}
else if (isLeft(decoded)) {
const string = PathReporter.report(decoded);
throw new Error(string.join('\n'));
}
})).map(e => e);
const names = targets.map(target => target?.targetName);
if (names.some(function (value) {
return names.indexOf(value) !== names.lastIndexOf(value);
})) {
throw new Error(`Duplicate targets!`);
}
targets.forEach((target, id) => {
logger.info(`${(id + 1).toString().padStart(files.length.toString().length, ' ')}. ${target.targetName} for ${target.config.for}: ${Object.values(target.config.entrypoints).join(', ')}`);
});
return targets;
}
function initPaths() {
const projectDir = process.cwd();
const srcDir = resolve(projectDir, 'src');
const distDir = resolve(projectDir, 'dist');
logger.info(`Project dir is ${projectDir}`);
logger.info(`Source code dir is ${srcDir}`);
logger.info(`Output dir is ${distDir}`);
return { projectDir, srcDir, distDir };
}
async function createWebpack(type, preConfigs, projectDir, _srcDir, distDir) {
const webpackConfigs = [];
for (let preConfig of preConfigs) {
webpackConfigs.push(await mkConfig(logger.child({}), preConfig.targetName, type, projectDir, resolve(distDir, type, preConfig.targetName), preConfig.config));
}
const compiler = webpack(webpackConfigs);
return compiler;
}
async function startWebpack(type, preConfigs, projectDir, srcDir, distDir) {
const compiler = await createWebpack(type, preConfigs, projectDir, srcDir, distDir);
if (type === 'production') {
compiler.run(() => {
logger.info(`Finished production build!`);
process.exit(0);
});
}
else {
const ignored = ['**/node_modules/**', '/snapshot/**', '**/.git/**', '**/.gtm/**'];
compiler.watch(process.env.POLL ? { poll: true, ignored } : {
poll: false,
aggregateTimeout: 300,
ignored
}, () => logger.info(`Finished development build!`));
}
}
if (process.argv.length != 3) {
logger.error('Wrong number of arguments');
process.exit(1);
}
switch (process.argv[2]) {
case 'production': {
const { projectDir, srcDir, distDir } = initPaths();
const targets = await discoverTargets(srcDir);
await startWebpack('production', targets, projectDir, srcDir, distDir);
break;
}
case 'development': {
const { projectDir, srcDir, distDir } = initPaths();
const targets = await discoverTargets(srcDir);
// TODO: Watch for updated .target files
await startWebpack('development', targets, projectDir, srcDir, distDir);
break;
}
default:
logger.error(`unknown target: ${process.argv[1]}, expected either 'production' or 'development'`);
process.exit(1);
}
//# sourceMappingURL=index.js.map