1 | "use strict";
|
2 | const tslib_1 = require("tslib");
|
3 | const fs = require("fs");
|
4 | const lazy_get_decorator_1 = require("lazy-get-decorator");
|
5 | const lodash_1 = require("lodash");
|
6 | const moment = require("moment");
|
7 | const os_1 = require("os");
|
8 | const path_1 = require("path");
|
9 | const rimraf_1 = require("rimraf");
|
10 | const ext_1 = require("../const/ext");
|
11 | const addConfig_1 = require("../fns/add-cmd/addConfig");
|
12 | const cmdName_1 = require("../fns/cmdName");
|
13 | const execLocal_1 = require("../fns/execLocal");
|
14 | const getBin_1 = require("../fns/getBin");
|
15 | const mkTsconfig_1 = require("../fns/mkTsconfig");
|
16 | const readJson_1 = require("../fns/readJson");
|
17 | const unlinkSafe_1 = require("../fns/unlinkSafe");
|
18 | const xSpawn_1 = require("../fns/xSpawn");
|
19 | const BuildTarget_1 = require("../interfaces/BuildTarget");
|
20 | const cli_serialiser_1 = require("../lib/cli-serialiser");
|
21 | const Log_1 = require("../lib/Log");
|
22 | const tmp_1 = require("../lib/tmp");
|
23 | const command = cmdName_1.cmdName(__filename);
|
24 | const defaultUmdName = (() => {
|
25 | try {
|
26 | return readJson_1.readJson("./package.json" ).name;
|
27 | }
|
28 | catch (_a) {
|
29 | return undefined;
|
30 | }
|
31 | })();
|
32 | const tscBin = getBin_1.getBin('typescript', 'tsc');
|
33 | const rollupCmdFile = require.resolve(`../lib/build/cmd.${ext_1.ext}`);
|
34 | const cmd = {
|
35 | builder(argv) {
|
36 | return addConfig_1.addConfig(argv, command)
|
37 | .option('entry', {
|
38 | alias: 'e',
|
39 | default: 'src/index.ts',
|
40 | describe: 'Entry file',
|
41 | type: 'string'
|
42 | })
|
43 | .option('externals', {
|
44 | alias: 'x',
|
45 | coerce: lodash_1.castArray,
|
46 | default: [],
|
47 | describe: 'External dependencies',
|
48 | type: 'array'
|
49 | })
|
50 | .option('skip-clean', {
|
51 | default: false,
|
52 | describe: 'Don\'t clean the output directory before building',
|
53 | type: 'boolean'
|
54 | })
|
55 | .option('ignore-umd-externals', {
|
56 | alias: 'iux',
|
57 | coerce(v) {
|
58 | let out = ['tslib'];
|
59 | if (v && v.length) {
|
60 | out.push(...v);
|
61 | out = lodash_1.uniq(out);
|
62 | }
|
63 | return out;
|
64 | },
|
65 | default: ['tslib'],
|
66 | describe: 'Override the externals option and always bundle the following packages in UMD',
|
67 | type: 'array'
|
68 | })
|
69 | .option('license-banner', {
|
70 | alias: 'lb',
|
71 | default: false,
|
72 | describe: 'Include the license as a banner in FESM & UMD bundles',
|
73 | type: 'boolean'
|
74 | })
|
75 | .option('skip-package-fields', {
|
76 | default: false,
|
77 | describe: 'Skip generating package mainFields',
|
78 | type: 'boolean'
|
79 | })
|
80 | .option('out', {
|
81 | alias: 'o',
|
82 | default: 'dist',
|
83 | describe: 'Output directory',
|
84 | type: 'string'
|
85 | })
|
86 | .option('rollup', {
|
87 | alias: 'r',
|
88 | default: 'rollup.config.js',
|
89 | describe: 'Path ro rollup config file',
|
90 | type: 'string'
|
91 | })
|
92 | .option('targets', {
|
93 | alias: 't',
|
94 | choices: BuildTarget_1.allBuildTargets,
|
95 | coerce: lodash_1.castArray,
|
96 | default: BuildTarget_1.allBuildTargets,
|
97 | describe: 'Build targets',
|
98 | type: 'array'
|
99 | })
|
100 | .option('umd-name', {
|
101 | alias: 'u',
|
102 | default: defaultUmdName,
|
103 | describe: 'UMD global variable name',
|
104 | type: 'string'
|
105 | })
|
106 | .option('tsconfig', {
|
107 | alias: 'ts',
|
108 | coerce(path) {
|
109 | let out = {};
|
110 | let last;
|
111 | do {
|
112 | last = readJson_1.readJson(path);
|
113 | if (!last) {
|
114 | throw new Error(`Path not found: ${path}`);
|
115 | }
|
116 | out = lodash_1.omit(lodash_1.merge(lodash_1.cloneDeep(last), out), ['extends']);
|
117 | if (last.extends) {
|
118 | path = last.extends;
|
119 | }
|
120 | } while (last.extends);
|
121 | return out;
|
122 | },
|
123 | describe: 'Path to tsconfig file to inherit from',
|
124 | type: 'string'
|
125 | });
|
126 | },
|
127 | command,
|
128 | describe: 'Build the project',
|
129 | handler(c) {
|
130 | const start = Date.now();
|
131 | validate(c);
|
132 | if (c.skipClean) {
|
133 | Log_1.Log.info(`Skipping cleaning ${c.out}`);
|
134 | }
|
135 | else {
|
136 | Log_1.Log.info(`Clearing ${c.out}`);
|
137 | rimraf_1.sync(c.out);
|
138 | Log_1.Log.success(`${c.out} cleared.`);
|
139 | }
|
140 | const tmpTsconfigs = [];
|
141 | try {
|
142 | buildCJsOrDeclaration(c, tmpTsconfigs);
|
143 | buildESM(c, tmpTsconfigs);
|
144 | buildRollup(c);
|
145 | if (c.skipPackageFields) {
|
146 | Log_1.Log.info('Skipping package.json mainFields');
|
147 | }
|
148 | else {
|
149 | Log_1.Log.info('Writing package.json');
|
150 | new PackageJsonBuilder(c).write();
|
151 | Log_1.Log.success('Wrote package.json');
|
152 | }
|
153 | Log_1.Log.success(`Build finished in ${getDuration(start)}`);
|
154 | }
|
155 | catch (e) {
|
156 | Log_1.Log.err(`Build errored in ${getDuration(start)}`);
|
157 | throw e;
|
158 | }
|
159 | finally {
|
160 | tmpTsconfigs.forEach(unlinkSafe_1.unlinkSafe);
|
161 | }
|
162 | }
|
163 | };
|
164 | function validate(c) {
|
165 | if (c.targets.includes(BuildTarget_1.BuildTarget.UMD) && !c.umdName) {
|
166 | throw new Error('umd-name is required when one of the targets is UMD');
|
167 | }
|
168 | if (!c.targets.length) {
|
169 | throw new Error('No targets specified');
|
170 | }
|
171 | for (const t of c.targets) {
|
172 | if (!BuildTarget_1.isBuildTarget(t)) {
|
173 | throw new Error(`Unknown build target: ${JSON.stringify(t)}`);
|
174 | }
|
175 | }
|
176 | }
|
177 | function buildRollup(c) {
|
178 | const incUMD = c.targets.includes(BuildTarget_1.BuildTarget.UMD);
|
179 | const incFESM5 = c.targets.includes(BuildTarget_1.BuildTarget.FESM5);
|
180 | const incFESM2015 = c.targets.includes(BuildTarget_1.BuildTarget.FESM2015);
|
181 | const banner = (() => {
|
182 | if (c.lb) {
|
183 | let e = null;
|
184 | for (const p of ['LICENSE', 'LICENSE.txt']) {
|
185 | try {
|
186 | const contents = fs.readFileSync(p, 'utf8');
|
187 | return [
|
188 | '/*!',
|
189 | contents,
|
190 | '*/',
|
191 | '',
|
192 | ''
|
193 | ].join(os_1.EOL);
|
194 | }
|
195 | catch (err) {
|
196 | e = err;
|
197 | }
|
198 | }
|
199 | if (e) {
|
200 | Log_1.Log.warn(`Unable to set license banner: ${e.stack || e.toString() || e.message}`);
|
201 | }
|
202 | }
|
203 | return null;
|
204 | })();
|
205 | if (!incUMD && !incFESM5 && !incFESM2015) {
|
206 | Log_1.Log.info("Skipping UMD" );
|
207 | Log_1.Log.info("Skipping FESM5" );
|
208 | Log_1.Log.info("Skipping FESM2015" );
|
209 | return;
|
210 | }
|
211 | const stdConf = lodash_1.merge({ output: { sourcemap: true } }, loadRollupConfig(c));
|
212 | stdConf.input = c.entry;
|
213 | stdConf.plugins = [];
|
214 | if (c.externals && c.externals.length) {
|
215 | if (Array.isArray(stdConf.external)) {
|
216 | stdConf.external.unshift(...c.externals);
|
217 | stdConf.external = lodash_1.uniq(c.externals);
|
218 | }
|
219 | else {
|
220 | stdConf.external = c.externals;
|
221 | }
|
222 | }
|
223 | if (banner && !lodash_1.has(stdConf, 'output.banner')) {
|
224 | lodash_1.set(stdConf, 'output.banner', banner);
|
225 | }
|
226 | lodash_1.set(stdConf, 'output.name', c.umdName);
|
227 | lodash_1.set(stdConf, 'output.amd.id', readJson_1.readJson("./package.json" ).name);
|
228 | const execOpts = {
|
229 | cwd: process.cwd(),
|
230 | stdio: 'inherit'
|
231 | };
|
232 | const stdArgs = [
|
233 | '--opts',
|
234 | cli_serialiser_1.CLISerialiser.serialise(stdConf),
|
235 | '--tsconfig',
|
236 | cli_serialiser_1.CLISerialiser.serialise(c.tsconfig),
|
237 | '--ignored-externals',
|
238 | cli_serialiser_1.CLISerialiser.serialise(c.ignoreUmdExternals),
|
239 | '--dist',
|
240 | c.out
|
241 | ];
|
242 | if (incFESM2015) {
|
243 | throwIfErrored(execLocal_1.execLocal(rollupCmdFile, stdArgs.concat('--formats', BuildTarget_1.BuildTarget.FESM2015), execOpts));
|
244 | }
|
245 | else {
|
246 | Log_1.Log.info("Skipping FESM2015" );
|
247 | }
|
248 | if (incFESM5 || incUMD) {
|
249 | const formats = [];
|
250 | if (incFESM5) {
|
251 | formats.push(BuildTarget_1.BuildTarget.FESM5);
|
252 | }
|
253 | else {
|
254 | Log_1.Log.info("Skipping FESM5" );
|
255 | }
|
256 | if (incUMD) {
|
257 | formats.push(BuildTarget_1.BuildTarget.UMD);
|
258 | }
|
259 | else {
|
260 | Log_1.Log.info("Skipping UMD" );
|
261 | }
|
262 | throwIfErrored(execLocal_1.execLocal(rollupCmdFile, stdArgs.concat('--formats', ...formats), execOpts));
|
263 | }
|
264 | else {
|
265 | Log_1.Log.info("Skipping FESM5" );
|
266 | Log_1.Log.info("Skipping UMD" );
|
267 | }
|
268 | }
|
269 | class PackageJsonBuilder {
|
270 | constructor(cfg) {
|
271 | this.cfg = cfg;
|
272 | this.pkgJson = readJson_1.readJson("./package.json" ) || {};
|
273 | }
|
274 | get _base() {
|
275 | const ext$ = path_1.extname(this.cfg.entry);
|
276 | return path_1.basename(this.cfg.entry, ext$);
|
277 | }
|
278 | get _baseJS() {
|
279 | return this._base + '.js';
|
280 | }
|
281 | get browser() {
|
282 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.UMD)) {
|
283 | return '_bundle/umd.js';
|
284 | }
|
285 | return null;
|
286 | }
|
287 | get esm2015() {
|
288 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.ESM2015)) {
|
289 | return `_bundle/esm2015/${this._baseJS}`;
|
290 | }
|
291 | return this.fesm5;
|
292 | }
|
293 | get esm5() {
|
294 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.ESM5)) {
|
295 | return `_bundle/esm5/${this._baseJS}`;
|
296 | }
|
297 | return this.fesm5;
|
298 | }
|
299 | get fesm2015() {
|
300 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.FESM2015)) {
|
301 | return '_bundle/fesm2015.js';
|
302 | }
|
303 | return null;
|
304 | }
|
305 | get fesm5() {
|
306 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.FESM5)) {
|
307 | return '_bundle/fesm5.js';
|
308 | }
|
309 | return null;
|
310 | }
|
311 | get jsdelivr() {
|
312 | if (this.browser) {
|
313 | return `_bundle/umd.min.js`;
|
314 | }
|
315 | return null;
|
316 | }
|
317 | get main() {
|
318 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.CJS)) {
|
319 | return this._baseJS;
|
320 | }
|
321 | else if (this.browser) {
|
322 | return this.browser;
|
323 | }
|
324 | else {
|
325 | throw new Error('Unable to resolve main file');
|
326 | }
|
327 | }
|
328 | get module() {
|
329 | return this.fesm5 || this.esm5;
|
330 | }
|
331 | get types() {
|
332 | if (this.cfg.targets.includes(BuildTarget_1.BuildTarget.DECLARATION)) {
|
333 | return `${this._base}.d.ts`;
|
334 | }
|
335 | return null;
|
336 | }
|
337 | write() {
|
338 | for (const p of ['main', 'browser', 'jsdelivr', 'fesm5', 'esm5', 'fesm2015', 'esm2015', 'types', 'module']) {
|
339 | if (this[p]) {
|
340 | this.pkgJson[p] = this[p];
|
341 | }
|
342 | else {
|
343 | delete this.pkgJson[p];
|
344 | }
|
345 | }
|
346 | if (this.types) {
|
347 | this.pkgJson.typings = this.types;
|
348 | }
|
349 | else {
|
350 | delete this.pkgJson.typings;
|
351 | }
|
352 | fs.writeFileSync("./package.json" , JSON.stringify(this.pkgJson, null, 2 ));
|
353 | this.write = lodash_1.noop;
|
354 | }
|
355 | }
|
356 | tslib_1.__decorate([
|
357 | lazy_get_decorator_1.LazyGetter(),
|
358 | tslib_1.__metadata("design:type", String),
|
359 | tslib_1.__metadata("design:paramtypes", [])
|
360 | ], PackageJsonBuilder.prototype, "_base", null);
|
361 | tslib_1.__decorate([
|
362 | lazy_get_decorator_1.LazyGetter(),
|
363 | tslib_1.__metadata("design:type", String),
|
364 | tslib_1.__metadata("design:paramtypes", [])
|
365 | ], PackageJsonBuilder.prototype, "_baseJS", null);
|
366 | tslib_1.__decorate([
|
367 | lazy_get_decorator_1.LazyGetter(),
|
368 | tslib_1.__metadata("design:type", Object),
|
369 | tslib_1.__metadata("design:paramtypes", [])
|
370 | ], PackageJsonBuilder.prototype, "browser", null);
|
371 | tslib_1.__decorate([
|
372 | lazy_get_decorator_1.LazyGetter(),
|
373 | tslib_1.__metadata("design:type", Object),
|
374 | tslib_1.__metadata("design:paramtypes", [])
|
375 | ], PackageJsonBuilder.prototype, "esm2015", null);
|
376 | tslib_1.__decorate([
|
377 | lazy_get_decorator_1.LazyGetter(),
|
378 | tslib_1.__metadata("design:type", Object),
|
379 | tslib_1.__metadata("design:paramtypes", [])
|
380 | ], PackageJsonBuilder.prototype, "esm5", null);
|
381 | tslib_1.__decorate([
|
382 | lazy_get_decorator_1.LazyGetter(),
|
383 | tslib_1.__metadata("design:type", Object),
|
384 | tslib_1.__metadata("design:paramtypes", [])
|
385 | ], PackageJsonBuilder.prototype, "fesm2015", null);
|
386 | tslib_1.__decorate([
|
387 | lazy_get_decorator_1.LazyGetter(),
|
388 | tslib_1.__metadata("design:type", Object),
|
389 | tslib_1.__metadata("design:paramtypes", [])
|
390 | ], PackageJsonBuilder.prototype, "fesm5", null);
|
391 | tslib_1.__decorate([
|
392 | lazy_get_decorator_1.LazyGetter(),
|
393 | tslib_1.__metadata("design:type", Object),
|
394 | tslib_1.__metadata("design:paramtypes", [])
|
395 | ], PackageJsonBuilder.prototype, "jsdelivr", null);
|
396 | tslib_1.__decorate([
|
397 | lazy_get_decorator_1.LazyGetter(),
|
398 | tslib_1.__metadata("design:type", Object),
|
399 | tslib_1.__metadata("design:paramtypes", [])
|
400 | ], PackageJsonBuilder.prototype, "main", null);
|
401 | tslib_1.__decorate([
|
402 | lazy_get_decorator_1.LazyGetter(),
|
403 | tslib_1.__metadata("design:type", Object),
|
404 | tslib_1.__metadata("design:paramtypes", [])
|
405 | ], PackageJsonBuilder.prototype, "module", null);
|
406 | tslib_1.__decorate([
|
407 | lazy_get_decorator_1.LazyGetter(),
|
408 | tslib_1.__metadata("design:type", Object),
|
409 | tslib_1.__metadata("design:paramtypes", [])
|
410 | ], PackageJsonBuilder.prototype, "types", null);
|
411 | function loadRollupConfig(c) {
|
412 | try {
|
413 | if (c.rollup) {
|
414 | const fullPath = path_1.join(process.cwd(), c.rollup);
|
415 | const contents = fs.readFileSync(fullPath, 'utf8');
|
416 | const reg = /export\s+default/g;
|
417 | if (reg.test(contents)) {
|
418 | try {
|
419 | const newContents = contents.replace(reg, 'module.exports = ');
|
420 | fs.writeFileSync(fullPath, newContents);
|
421 | return lodash_1.cloneDeep(require(fullPath));
|
422 | }
|
423 | finally {
|
424 | fs.writeFileSync(fullPath, contents);
|
425 | }
|
426 | }
|
427 | else {
|
428 | return lodash_1.cloneDeep(require(fullPath));
|
429 | }
|
430 | }
|
431 | }
|
432 | catch (_a) {
|
433 |
|
434 | }
|
435 | return {};
|
436 | }
|
437 | function buildESM(c, tmpTsConfigs) {
|
438 | if (c.targets.includes(BuildTarget_1.BuildTarget.ESM5)) {
|
439 | Log_1.Log.info('Building ESM5');
|
440 | spawnTsc(makeTmpTsconfig(c, tmpTsConfigs, {
|
441 | compilerOptions: {
|
442 | declaration: false,
|
443 | module: 'es2015',
|
444 | outDir: path_1.join(c.out, '_bundle', 'esm5'),
|
445 | target: 'es5'
|
446 | }
|
447 | }));
|
448 | Log_1.Log.success('Built ESM5');
|
449 | }
|
450 | else {
|
451 | Log_1.Log.info('Skipping ESM5');
|
452 | }
|
453 | if (c.targets.includes(BuildTarget_1.BuildTarget.ESM2015)) {
|
454 | Log_1.Log.info('Building ESM2015');
|
455 | spawnTsc(makeTmpTsconfig(c, tmpTsConfigs, {
|
456 | compilerOptions: {
|
457 | declaration: false,
|
458 | module: 'es2015',
|
459 | outDir: path_1.join(c.out, '_bundle', 'esm2015'),
|
460 | target: 'esnext'
|
461 | }
|
462 | }));
|
463 | Log_1.Log.success('Built ESM2015');
|
464 | }
|
465 | else {
|
466 | Log_1.Log.info('Skipping ESM2015');
|
467 | }
|
468 | }
|
469 | function buildCJsOrDeclaration(c, tmpTsconfigs) {
|
470 | const needsDeclaration = c.targets.includes(BuildTarget_1.BuildTarget.DECLARATION);
|
471 | if (c.targets.includes(BuildTarget_1.BuildTarget.CJS)) {
|
472 | if (!needsDeclaration) {
|
473 | Log_1.Log.info('Skipping declaration');
|
474 | }
|
475 | const building = needsDeclaration ? 'CommonJS + declaration' : 'CommonJS';
|
476 | Log_1.Log.info(`Building ${building}`);
|
477 | spawnTsc(makeTmpTsconfig(c, tmpTsconfigs, {
|
478 | compilerOptions: {
|
479 | declaration: needsDeclaration,
|
480 | module: 'commonjs',
|
481 | outDir: c.out
|
482 | }
|
483 | }));
|
484 | Log_1.Log.success(`Built ${building}`);
|
485 | }
|
486 | else if (needsDeclaration) {
|
487 | Log_1.Log.info('Skipping commonjs');
|
488 | Log_1.Log.info('Building declaration');
|
489 | spawnTsc(makeTmpTsconfig(c, tmpTsconfigs, {
|
490 | compilerOptions: {
|
491 | declaration: true,
|
492 | emitDeclarationOnly: true,
|
493 | module: 'commonjs',
|
494 | outDir: c.out,
|
495 | sourceMap: false
|
496 | }
|
497 | }));
|
498 | Log_1.Log.success('Built declaration');
|
499 | }
|
500 | else {
|
501 | Log_1.Log.info('Skipping commonjs');
|
502 | Log_1.Log.info('Skipping declaration');
|
503 | }
|
504 | }
|
505 | function makeTmpTsconfig(c, cleanupArray, overrides) {
|
506 | const path = tmp_1.tmp.fileSync({
|
507 | dir: process.cwd(),
|
508 | postfix: '.json',
|
509 | prefix: ".alobuild-tsconfig-"
|
510 | }).name;
|
511 | const tsconfig = mkTsconfig_1.mkTsconfig(lodash_1.merge(lodash_1.cloneDeep(c.tsconfig), overrides || {}));
|
512 | delete tsconfig.compilerOptions.outFile;
|
513 | fs.writeFileSync(path, JSON.stringify(tsconfig, null, 2 ));
|
514 | cleanupArray.push(path);
|
515 | return path;
|
516 | }
|
517 | function spawnTsc(tsconfigPath) {
|
518 | const proc = xSpawn_1.xSpawnSync(process.execPath, [tscBin, '-p', tsconfigPath], { stdio: 'inherit' });
|
519 | throwIfErrored(proc);
|
520 | }
|
521 | function throwIfErrored(res) {
|
522 | if (res.status !== 0) {
|
523 | throw new Error(`Process exited with code ${res.status}`);
|
524 | }
|
525 | }
|
526 | function getDuration(startPoint) {
|
527 | const d = moment.duration(Date.now() - startPoint);
|
528 | return [
|
529 | d.hours().toString(),
|
530 | lodash_1.padStart(d.minutes().toString(), 2 , "0" ),
|
531 | lodash_1.padStart(d.seconds().toString(), 2 , "0" )
|
532 | ].join(':') + `.${lodash_1.padStart(d.milliseconds().toString(), 3 /* PAD_MS */, "0" /* PAD_CHAR */)}`;
|
533 | }
|
534 |
|
535 | fs.readdirSync(process.cwd(), 'utf8')
|
536 | .filter(p => p.startsWith(".alobuild-tsconfig-" ) && p.endsWith('.json'))
|
537 | .forEach(unlinkSafe_1.unlinkSafe);
|
538 | module.exports = cmd;
|