UNPKG

zarbis

Version:

Configuration-less build tool

127 lines 5.04 kB
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