Skip to content

Commit

Permalink
feat(output): Adds visualization for serve and build output. (#557)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo committed Feb 25, 2019
1 parent 0e310b9 commit 672b5ef
Show file tree
Hide file tree
Showing 26 changed files with 43,260 additions and 223 deletions.
17 changes: 13 additions & 4 deletions apps/angular-console-e2e/src/integration/tasks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,19 @@ describe('Tasks', () => {
.contains('Run')
.click();

cy.get('div.js-status-build-success', { timeout: 220000 }).contains(
'Build completed'
);
cy.get('div.js-status-server-url', { timeout: 220000 }).contains('browser');
cy.contains('button', 'Open App', { timeout: 220000 });

cy.contains('.summary .content', 'Started', { timeout: 220000 });

cy.get('.header .mat-select-trigger').click({ force: true });

cy.get('.mat-option-text')
.contains('Parsed')
.click();

cy.contains('.summary .content', /[0-9.]+(k|m|g)?b/i, { timeout: 220000 });

cy.contains('mat-grid-tile', /^.+\.js/);

cy.get('button')
.contains('Cancel')
Expand Down
2 changes: 1 addition & 1 deletion libs/feature-run/src/lib/npmscript/npmscript.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class NpmScriptComponent implements OnInit {
return this.runner.runCommand(
this.npmRunGQL.mutate({
path: this.path(),
npmClient: s.npmClient,
npmClient: s.npmClient || '',
runCommand: c.commands
}),
false,
Expand Down
75 changes: 41 additions & 34 deletions libs/server/src/lib/api/detailed-status-calculator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,40 +55,47 @@ describe('detailedStatusCalculator', () => {
chunk {vendor} vendor.js, vendor.js.map (vendor) 7.57 MB [initial] [rendered]
`);

expect(c.detailedStatus).toEqual({
type: StatusType.BUILD,
buildStatus: 'build_success',
progress: 100,
indexFile: undefined,
isForProduction: false,
outputPath: undefined,
serverHost: undefined,
date: '2018-09-23T19:46:04.026Z',
time: '16477ms',
chunks: [
{ name: 'main', file: 'main.js', size: '381 kB', type: 'initial' },
{
name: 'polyfills',
file: 'polyfills.js',
size: '237 kB',
type: 'initial'
},
{
name: 'runtime',
file: 'runtime.js',
size: '5.22 kB',
type: 'entry'
},
{ name: 'styles', file: 'styles.js', size: '86 kB', type: 'initial' },
{
name: 'vendor',
file: 'vendor.js',
size: '7.57 MB',
type: 'initial'
}
],
errors: []
});
expect(c.detailedStatus).toEqual(
expect.objectContaining({
type: StatusType.BUILD,
buildStatus: 'build_success',
progress: 100,
indexFile: undefined,
isForProduction: false,
outputPath: undefined,
serverHost: undefined,
date: '2018-09-23T19:46:04.026Z',
time: '16.48s',
chunks: [
{ name: 'main', file: 'main.js', size: '381 kB', type: 'initial' },
{
name: 'polyfills',
file: 'polyfills.js',
size: '237 kB',
type: 'initial'
},
{
name: 'runtime',
file: 'runtime.js',
size: '5.22 kB',
type: 'entry'
},
{
name: 'styles',
file: 'styles.js',
size: '86 kB',
type: 'initial'
},
{
name: 'vendor',
file: 'vendor.js',
size: '7.57 MB',
type: 'initial'
}
],
errors: []
})
);
});

it('should handle ansi characters', () => {
Expand Down
56 changes: 44 additions & 12 deletions libs/server/src/lib/api/detailed-status-calculator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { readJsonFile } from '../utils/utils';
import { Chunk, parseStats, calculateStatsFromChunks } from '../utils/stats';
import {
getProjectArchitect,
SUPPORTED_KARMA_TEST_BUILDERS,
SUPPORTED_NG_BUILD_BUILDERS
} from '../utils/architect-utils';
} from '../utils/architect';
import { join } from 'path';
import { existsSync, readFileSync } from 'fs';

export enum StatusType {
BUILD = 'build',
Expand All @@ -25,13 +27,6 @@ class EmptyDetailedStatusCalculator implements DetailedStatusCalculator<null> {
reset() {}
}

export interface Chunk {
name: string;
file: string;
size: string;
type: string;
}

export interface BuildDetailedStatus {
type: StatusType.BUILD;
buildStatus:
Expand All @@ -49,6 +44,7 @@ export interface BuildDetailedStatus {
isForProduction?: boolean;
outputPath?: string;
indexFile?: string;
stats?: any;
}

interface BuildArchitectOpts {
Expand Down Expand Up @@ -108,7 +104,7 @@ export class BuildDetailedStatusCalculator
''
);

const {
let {
processedChunks,
...newValue
} = BuildDetailedStatusCalculator.updateDetailedStatus(
Expand All @@ -119,11 +115,14 @@ export class BuildDetailedStatusCalculator
_value
);

// Don't override chunks unless it has changed or else we will have to keep calling Object.values.
if (this.processedChunks !== processedChunks) {
newValue.chunks = Object.values(processedChunks);
this.processedChunks = processedChunks;
}

newValue = this.addStats(newValue);

this.detailedStatus = newValue;
}

Expand All @@ -134,6 +133,29 @@ export class BuildDetailedStatusCalculator
};
}

addStats(nextStatus: BuildDetailedStatus) {
const justCompleted =
nextStatus.progress === 100 && this.detailedStatus.progress < 100;

if (justCompleted && this.architectOptions) {
const statsPath = `${this.cwd}/${
this.architectOptions.outputPath
}/stats.json`;

if (existsSync(statsPath)) {
const statsJson = JSON.parse(readFileSync(statsPath).toString());
nextStatus.stats = parseStats(
statsJson,
join(this.cwd, this.architectOptions.outputPath)
);
} else {
nextStatus.stats = calculateStatsFromChunks(nextStatus.chunks);
}
}

return nextStatus;
}

static updateDetailedStatus(
state: BuildDetailedStatus & { processedChunks: { [k: string]: Chunk } },
value: string
Expand All @@ -142,8 +164,8 @@ export class BuildDetailedStatusCalculator
const newErrors = [] as string[];
let _state = state;
let processedChunks = _state.processedChunks as any;
let date = '';
let time = '';
let date = state.date || '';
let time = state.time || '';
let progress = _state.progress;
let buildStatus = _state.buildStatus;

Expand Down Expand Up @@ -190,7 +212,7 @@ export class BuildDetailedStatusCalculator
const timeRegExp = /Time: ([^\s)]+)/g;
const timeMatch = timeRegExp.exec(line);
if (timeMatch) {
time = timeMatch[1];
time = parseTime(timeMatch[1]);
}
});
}
Expand Down Expand Up @@ -527,3 +549,13 @@ function collectPreviousErrorsFrom(idx: number, lines: string[]): string[] {

return xs;
}

function parseTime(s: string) {
if (s.endsWith('ms')) {
const x = Number(s.slice(0, s.length - 2));
if (Number.isInteger(x)) {
return `${(x / 1000).toFixed(2)}s`;
}
}
return s;
}
2 changes: 1 addition & 1 deletion libs/server/src/lib/api/run-command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Commands } from './commands';
import { createDetailedStatusCalculator } from './detailed-status-calculator';
import { normalizeCommands } from '../utils/architect-utils';
import { normalizeCommands } from '../utils/architect';
import { PseudoTerminalFactory } from '@angular-console/server';
import { platform } from 'os';
import { FileUtils } from '../utils/file-utils';
Expand Down
2 changes: 1 addition & 1 deletion libs/server/src/lib/resolvers/mutation.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export class MutationResolver {
async showItemInFolder(@Args('item') item: string) {
if (item) {
const opn = require('opn');
opn(item);
opn(item).catch((err: any) => console.error(err));
return { result: true };
} else {
return { result: false };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ import { join } from 'path';
import { existsSync } from 'fs';
import { readJsonFile } from './utils';

// For some operations we need to add additional flags or configration in order to make sure we get the expected output.

// We use known builders to ensure that input flags and output are what we expect.
export const SUPPORTED_KARMA_TEST_BUILDERS = [
'@angular-devkit/build-angular:karma'
];
export const SUPPORTED_NG_BUILD_BUILDERS = [
'@angular-devkit/build-angular:dev-server',
'@angular-devkit/build-angular:browser'
];
export const SUPPORTED_NG_BUILD_BUILDERS_WITH_STATS = [
'@angular-devkit/build-angular:browser'
];

// For some operations we need to add additional flags or configuration
// in order to make sure we get the expected output.
export function normalizeCommands(cwd: string, cmds: string[]): string[] {
const operationName = cmds[0];
const project = cmds[1];
const { json: angularJson } = readJsonFile('./angular.json', cwd);
const builder = getProjectArchitect(project, operationName, angularJson)
.builder;

// Extend the karma configuration so we can get the output needed.
if (SUPPORTED_KARMA_TEST_BUILDERS.includes(builder)) {
const projectRoot = angularJson.projects[cmds[1]].root;
const karmaConfigPath = join(cwd, projectRoot, 'karma.conf.js');
Expand All @@ -30,6 +35,11 @@ export function normalizeCommands(cwd: string, cmds: string[]): string[] {
]);
}
}

// Make sure we generate stats data so we can parse it later.
if (SUPPORTED_NG_BUILD_BUILDERS_WITH_STATS.includes(builder)) {
return cmds.concat(['--stats-json']);
}
return cmds;
}

Expand Down
Loading

0 comments on commit 672b5ef

Please sign in to comment.