Skip to content

Commit

Permalink
feat(builders): introduce node build and execute builders
Browse files Browse the repository at this point in the history
These builders handle building and executing node applications
FrozenPandaz authored and vsavkin committed Oct 1, 2018
1 parent 039c151 commit 469af6e
Showing 16 changed files with 1,416 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ node_modules
.idea
.vscode
dist
build
/build
test
.DS_Store
tmp
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tmp
build
/build
node_modules
/package.json
packages/schematics/src/collection/**/files/*.json
packages/schematics/src/collection/**/files/*.json
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@
"checkformat": "prettier \"./**/*.{ts,js,json,css,md}\" \"!./**/{__name__,__directory__}/**\" --list-different"
},
"devDependencies": {
"@angular-devkit/architect": "0.8.3",
"@angular-devkit/build-angular": "0.8.3",
"@angular-devkit/build-webpack": "0.8.3",
"@angular-devkit/core": "0.8.3",
"@angular-devkit/schematics": "0.8.3",
"@angular/cli": "6.2.3",
@@ -39,15 +41,19 @@
"@schematics/angular": "0.8.3",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/jest": "^23.3.2",
"@types/node": "~8.9.4",
"@types/prettier": "^1.10.0",
"@types/webpack": "^4.4.11",
"@types/yargs": "^11.0.0",
"angular": "1.6.6",
"app-root-path": "^2.0.1",
"circular-dependency-plugin": "^5.0.2",
"commitizen": "^2.10.1",
"conventional-changelog-cli": "^1.3.21",
"cosmiconfig": "^4.0.0",
"cz-conventional-changelog": "^2.1.0",
"fork-ts-checker-webpack-plugin": "^0.4.9",
"fs-extra": "5.0.0",
"graphviz": "^0.0.8",
"husky": "^1.0.0-rc.13",
@@ -60,6 +66,7 @@
"karma-chrome-launcher": "~2.2.0",
"karma-jasmine": "~1.1.1",
"karma-webpack": "2.0.4",
"license-webpack-plugin": "^1.4.0",
"lint-staged": "^7.2.2",
"ng-packagr": "3.0.6",
"npm-run-all": "4.1.2",
@@ -74,6 +81,8 @@
"tslint": "5.11.0",
"typescript": "~2.9.2",
"viz.js": "^1.8.1",
"webpack": "4.9.2",
"webpack-node-externals": "^1.7.2",
"yargs": "^11.0.0",
"yargs-parser": "10.0.0",
"zone.js": "^0.8.26"
8 changes: 7 additions & 1 deletion packages/builders/package.json
Original file line number Diff line number Diff line change
@@ -25,6 +25,12 @@
"builders": "./src/builders.json",
"dependencies": {
"@angular-devkit/architect": "~0.8.0",
"rxjs": "6.2.2"
"@angular-devkit/build-webpack": "~0.8.0",
"fork-ts-checker-webpack-plugin": "0.4.9",
"license-webpack-plugin": "^1.4.0",
"rxjs": "6.2.2",
"ts-loader": "4.5.0",
"webpack": "4.9.2",
"webpack-node-externals": "1.7.2"
}
}
12 changes: 11 additions & 1 deletion packages/builders/src/builders.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"$schema": "../architect/src/builders-schema.json",
"$schema": "@angular-devkit/architect/src/builders-schema.json",
"builders": {
"node-build": {
"class": "./node/build/node-build.builder",
"schema": "./node/build/schema.json",
"description": "Build a Node application"
},
"node-execute": {
"class": "./node/execute/node-execute.builder",
"schema": "./node/execute/schema.json",
"description": "Build a Node application"
},
"jest": {
"class": "./jest/jest.builder",
"schema": "./jest/schema.json",
36 changes: 8 additions & 28 deletions packages/builders/src/jest/jest.builder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import JestBuilder from './jest.builder';
import { normalize } from '@angular-devkit/core';
import * as jestCLI from 'jest';
jest.mock('jest');
const { runCLI } = require('jest');
import * as path from 'path';

describe('Jest Builder', () => {
let builder: JestBuilder;

beforeEach(() => {
builder = new JestBuilder();
});

it('should send appropriate options to jestCLI', () => {
const runCLI = spyOn(jestCLI, 'runCLI').and.returnValue(
runCLI.mockReturnValue(
Promise.resolve({
results: {
success: true
}
})
);
});

it('should send appropriate options to jestCLI', () => {
const root = normalize('/root');
builder
.run({
@@ -46,13 +47,6 @@ describe('Jest Builder', () => {
});

it('should send other options to jestCLI', () => {
const runCLI = spyOn(jestCLI, 'runCLI').and.returnValue(
Promise.resolve({
results: {
success: true
}
})
);
const root = normalize('/root');
builder
.run({
@@ -98,19 +92,12 @@ describe('Jest Builder', () => {
);
});

it('should send the main to jestCLI', () => {
const runCLI = spyOn(jestCLI, 'runCLI').and.returnValue(
Promise.resolve({
results: {
success: true
}
})
);
it('should send the main to runCLI', () => {
const root = normalize('/root');
builder
.run({
root,
builder: '',
builder: '@nrwl/builders:jest',
projectType: 'application',
options: {
jestConfig: './jest.config.js',
@@ -139,13 +126,6 @@ describe('Jest Builder', () => {
});

it('should return the proper result', async done => {
spyOn(jestCLI, 'runCLI').and.returnValue(
Promise.resolve({
results: {
success: true
}
})
);
const root = normalize('/root');
const result = await builder
.run({
4 changes: 2 additions & 2 deletions packages/builders/src/jest/jest.builder.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import { map } from 'rxjs/operators';

import * as path from 'path';

import { runCLI as runJest } from 'jest';
const { runCLI } = require('jest');

export interface JestBuilderOptions {
jestConfig: string;
@@ -61,7 +61,7 @@ export default class JestBuilder implements Builder<JestBuilderOptions> {
);
}

return from(runJest(config, [options.jestConfig])).pipe(
return from(runCLI(config, [options.jestConfig])).pipe(
map((results: any) => {
return {
success: results.results.success
162 changes: 162 additions & 0 deletions packages/builders/src/node/build/node-build.builder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { normalize } from '@angular-devkit/core';
import { TestLogger } from '@angular-devkit/architect/testing';
import BuildNodeBuilder from './node-build.builder';
import { BuildNodeBuilderOptions } from './node-build.builder';
import { of } from 'rxjs';
import * as fs from 'fs';

describe('NodeBuildBuilder', () => {
let builder: BuildNodeBuilder;
let testOptions: BuildNodeBuilderOptions;

beforeEach(() => {
builder = new BuildNodeBuilder({
host: <any>{},
logger: new TestLogger('test'),
workspace: <any>{
root: '/root'
},
architect: <any>{}
});
testOptions = {
main: 'apps/nodeapp/src/main.ts',
tsConfig: 'apps/nodeapp/tsconfig.app.json',
outputPath: 'dist/apps/nodeapp',
externalDependencies: 'all',
fileReplacements: [
{
replace: 'apps/environment/environment.ts',
with: 'apps/environment/environment.prod.ts'
},
{
replace: 'module1.ts',
with: 'module2.ts'
}
]
};
});

describe('run', () => {
it('should call runWebpack', () => {
const runWebpack = spyOn(
builder.webpackBuilder,
'runWebpack'
).and.returnValue(
of({
success: true
})
);

builder.run({
root: normalize('/root'),
projectType: 'application',
builder: '@nrwl/builders:node-build',
options: testOptions
});

expect(runWebpack).toHaveBeenCalled();
});

it('should emit the outfile along with success', async () => {
const runWebpack = spyOn(
builder.webpackBuilder,
'runWebpack'
).and.returnValue(
of({
success: true
})
);

const buildEvent = await builder
.run({
root: normalize('/root'),
projectType: 'application',
builder: '@nrwl/builders:node-build',
options: testOptions
})
.toPromise();

expect(buildEvent.success).toEqual(true);
expect(buildEvent.outfile).toEqual('/root/dist/apps/nodeapp/main.js');
});

describe('when stats json option is passed', () => {
beforeEach(() => {
const stats = {
stats: 'stats'
};
spyOn(builder.webpackBuilder, 'runWebpack').and.callFake((opts, cb) => {
cb({
toJson: () => stats,
toString: () => JSON.stringify(stats)
});
return of({
success: true
});
});
spyOn(fs, 'writeFileSync');
});

it('should generate a stats json', async () => {
await builder
.run({
root: normalize('/root'),
projectType: 'application',
builder: '@nrwl/builders:node-build',
options: {
...testOptions,
statsJson: true
}
})
.toPromise();

expect(fs.writeFileSync).toHaveBeenCalledWith(
'/root/dist/apps/nodeapp/stats.json',
JSON.stringify(
{
stats: 'stats'
},
null,
2
)
);
});
});
});

describe('options normalization', () => {
it('should add the root', () => {
const result = (<any>builder).normalizeOptions(testOptions);
expect(result.root).toEqual('/root');
});

it('should resolve main from root', () => {
const result = (<any>builder).normalizeOptions(testOptions);
expect(result.main).toEqual('/root/apps/nodeapp/src/main.ts');
});

it('should resolve the output path', () => {
const result = (<any>builder).normalizeOptions(testOptions);
expect(result.outputPath).toEqual('/root/dist/apps/nodeapp');
});

it('should resolve the tsConfig path', () => {
const result = (<any>builder).normalizeOptions(testOptions);
expect(result.tsConfig).toEqual('/root/apps/nodeapp/tsconfig.app.json');
});

it('should resolve the file replacement paths', () => {
const result = (<any>builder).normalizeOptions(testOptions);
expect(result.fileReplacements).toEqual([
{
replace: '/root/apps/environment/environment.ts',
with: '/root/apps/environment/environment.prod.ts'
},
{
replace: '/root/module1.ts',
with: '/root/module2.ts'
}
]);
});
});
});
Loading

0 comments on commit 469af6e

Please sign in to comment.