11import * as fs from 'fs-extra' ;
22import * as path from 'path' ;
33import * as webpack from 'webpack' ;
4+ import { red } from 'chalk' ;
45
56import { getAppFromConfig } from '../utilities/app-utils' ;
67import { BuildTaskOptions } from '../commands/build' ;
78import { NgCliWebpackConfig } from '../models/webpack-config' ;
89import { getWebpackStatsConfig } from '../models/webpack-configs/utils' ;
910import { CliConfig } from '../models/config' ;
1011import { statsToString , statsWarningsToString , statsErrorsToString } from '../utilities/stats' ;
12+ import { oneLine } from 'common-tags' ;
1113
1214const Task = require ( '../ember-cli/lib/models/task' ) ;
1315const SilentError = require ( 'silent-error' ) ;
@@ -17,9 +19,9 @@ export default Task.extend({
1719 run : function ( runTaskOptions : BuildTaskOptions ) {
1820 const config = CliConfig . fromProject ( ) . config ;
1921
20- const app = getAppFromConfig ( runTaskOptions . app ) ;
22+ const appConfig = getAppFromConfig ( runTaskOptions . app ) ;
2123
22- const outputPath = runTaskOptions . outputPath || app . outDir ;
24+ const outputPath = runTaskOptions . outputPath || appConfig . outDir ;
2325 if ( this . project . root === path . resolve ( outputPath ) ) {
2426 throw new SilentError ( 'Output path MUST not be project root directory!' ) ;
2527 }
@@ -30,7 +32,7 @@ export default Task.extend({
3032 fs . removeSync ( path . resolve ( this . project . root , outputPath ) ) ;
3133 }
3234
33- const webpackConfig = new NgCliWebpackConfig ( runTaskOptions , app ) . buildConfig ( ) ;
35+ const webpackConfig = new NgCliWebpackConfig ( runTaskOptions , appConfig ) . buildConfig ( ) ;
3436 const webpackCompiler = webpack ( webpackConfig ) ;
3537 const statsConfig = getWebpackStatsConfig ( runTaskOptions . verbose ) ;
3638
@@ -47,6 +49,27 @@ export default Task.extend({
4749 this . ui . writeLine ( statsToString ( json , statsConfig ) ) ;
4850 }
4951
52+ if ( runTaskOptions . target === 'production' && ! ! appConfig . budgets ) {
53+ let budgetErrors : string [ ] = [ ] ;
54+ appConfig . budgets . forEach ( ( budget : { name : string ; budget : number } ) => {
55+ const chunk = json . chunks . filter (
56+ ( c : { names : string [ ] ; } ) => c . names . indexOf ( budget . name ) !== - 1 ) [ 0 ] ;
57+ const asset = json . assets . filter ( ( x : any ) => x . name == chunk . files [ 0 ] ) [ 0 ] ;
58+ const size = asset . size / 1000 ;
59+ if ( size > budget . budget ) {
60+ budgetErrors . push ( oneLine `${ budget . name }
61+ budget: ${ budget . budget } kB
62+ size: ${ size . toPrecision ( 3 ) } kB` ) ;
63+ }
64+ } ) ;
65+ if ( budgetErrors . length > 0 ) {
66+ const budgetError = 'Allowed bundle budgets have been exceeded' ;
67+ this . ui . writeLine ( red ( `\n...${ budgetError } ` ) ) ;
68+ budgetErrors . forEach ( err => this . ui . writeLine ( red ( ` ${ err } ` ) ) ) ;
69+ reject ( budgetError ) ;
70+ }
71+ }
72+
5073 if ( stats . hasWarnings ( ) ) {
5174 this . ui . writeLine ( statsWarningsToString ( json , statsConfig ) ) ;
5275 }
0 commit comments