ipsos-components
Version:
Material Design components for Angular
132 lines (104 loc) • 5.28 kB
text/typescript
import {join, resolve as resolvePath} from 'path';
import {spawn} from 'child_process';
import {red} from 'chalk';
import {PackageBundler} from './build-bundles';
import {buildConfig} from './build-config';
import {getSecondaryEntryPointsForPackage} from './secondary-entry-points';
import {compileEntryPoint, renamePrivateReExportsToBeUnique} from './compile-entry-point';
const {packagesDir, outputDir} = buildConfig;
/** Name of the tsconfig file that is responsible for building an ES2015 package. */
const buildTsconfigName = 'tsconfig-build.json';
/** Name of the tsconfig file that is responsible for building the tests. */
const testsTsconfigName = 'tsconfig-tests.json';
export class BuildPackage {
/** Path to the package sources. */
sourceDir: string;
/** Path to the ES2015 package output. */
outputDir: string;
/** Path to the ES5 package output. */
esm5OutputDir: string;
/** Whether this package will re-export its secondary-entry points at the root module. */
exportsSecondaryEntryPointsAtRoot = false;
/** Whether the secondary entry-point styles should be copied to the release output. */
copySecondaryEntryPointStylesToRoot = false;
/** Path to the entry file of the package in the output directory. */
readonly entryFilePath: string;
/** Path to the tsconfig file, which will be used to build the package. */
private readonly tsconfigBuild: string;
/** Path to the tsconfig file, which will be used to build the tests. */
private readonly tsconfigTests: string;
/** Package bundler instance. */
private bundler = new PackageBundler(this);
/** Secondary entry-points partitioned by their build depth. */
private get secondaryEntryPointsByDepth(): string[][] {
this.cacheSecondaryEntryPoints();
return this._secondaryEntryPointsByDepth;
}
private _secondaryEntryPointsByDepth: string[][];
/** Secondary entry points for the package. */
get secondaryEntryPoints(): string[] {
this.cacheSecondaryEntryPoints();
return this._secondaryEntryPoints;
}
private _secondaryEntryPoints: string[];
constructor(readonly name: string, readonly dependencies: BuildPackage[] = []) {
this.sourceDir = join(packagesDir, name);
this.outputDir = join(outputDir, 'packages', name);
this.esm5OutputDir = join(outputDir, 'packages', name, 'esm5');
this.tsconfigBuild = join(this.sourceDir, buildTsconfigName);
this.tsconfigTests = join(this.sourceDir, testsTsconfigName);
this.entryFilePath = join(this.outputDir, 'index.js');
}
/** Compiles the package sources with all secondary entry points. */
async compile() {
// Compile all secondary entry-points with the same depth in parallel, and each separate depth
// group in sequence. This will look something like:
// Depth 0: coercion, platform, keycodes, bidi
// Depth 1: a11y, scrolling
// Depth 2: overlay
for (const entryPointGroup of this.secondaryEntryPointsByDepth) {
await Promise.all(entryPointGroup.map(p => this._compileBothTargets(p)));
}
// Compile the primary entry-point.
await this._compileBothTargets();
}
/** Compiles the TypeScript test source files for the package. */
async compileTests() {
await this._compileTestEntryPoint(testsTsconfigName);
}
/** Creates all bundles for the package and all associated entry points. */
async createBundles() {
await this.bundler.createBundles();
}
/** Compiles TS into both ES2015 and ES5, then updates exports. */
private async _compileBothTargets(p = '') {
return compileEntryPoint(this, buildTsconfigName, p)
.then(() => compileEntryPoint(this, buildTsconfigName, p, this.esm5OutputDir))
.then(() => renamePrivateReExportsToBeUnique(this, p));
}
/** Compiles the TypeScript sources of a primary or secondary entry point. */
private _compileTestEntryPoint(tsconfigName: string, secondaryEntryPoint = ''): Promise<any> {
const entryPointPath = join(this.sourceDir, secondaryEntryPoint);
const entryPointTsconfigPath = join(entryPointPath, tsconfigName);
return new Promise((resolve, reject) => {
const ngcPath = resolvePath('./node_modules/.bin/ngc');
const childProcess = spawn(ngcPath, ['-p', entryPointTsconfigPath], {shell: true});
// Pipe stdout and stderr from the child process.
childProcess.stdout.on('data', (data: any) => console.log(`${data}`));
childProcess.stderr.on('data', (data: any) => console.error(red(`${data}`)));
childProcess.on('exit', (exitCode: number) => exitCode === 0 ? resolve() : reject());
})
.catch(() => {
const error = red(`Failed to compile ${secondaryEntryPoint} using ${entryPointTsconfigPath}`);
console.error(error);
});
}
/** Stores the secondary entry-points for this package if they haven't been computed already. */
private cacheSecondaryEntryPoints() {
if (!this._secondaryEntryPoints) {
this._secondaryEntryPointsByDepth = getSecondaryEntryPointsForPackage(this);
this._secondaryEntryPoints =
this._secondaryEntryPointsByDepth.reduce((list, p) => list.concat(p), []);
}
}
}