angular: [RC5]: Minified bundle breaks

I’m submitting a … (check one with “x”)

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior Minified bundle breaks, but SOLVED temporarily by either:

Error traces:

lib-2cf12bf509.js:7 Unhandled Promise rejection: Template parse errors:
Can't bind to 'brand' since it isn't a known property of 'as-navbar'.
1. If 'as-navbar' is an Angular component and it has 'brand' input, then verify that it is part of this module.
2. If 'as-navbar' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schema' of this component to suppress this message.
 ("<as-navbar [ERROR ->][brand]="appBrand"></as-navbar>
<div class="container" style="margin-top: 100px;">
    <router-outlet></"): a@0:11 ; Zone: <root> ; Task: Promise.then ; Value:

Expected/desired behavior The minified bundle should work as in RC4

Reproduction of the problem https://github.com/OasisDigital/rc5-declaration-order

npm install

// try run in dev, it works well now
npm start

// try run in prod, the bundle created but break
npm run serve-build

// now try changing the mangle option and retry, it works!

What is the expected behavior? Should work as in RC4

What is the motivation / use case for changing the behavior?

Please tell us about your environment:

  • Angular version: 2.0.0-rc.5
  • Browser: [all | Chrome 52 | Web Browser
  • Language: [all | TypeScript 1.8.10]

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 58
  • Comments: 122 (26 by maintainers)

Commits related to this issue

Most upvoted comments

@robertoforlani Hopefully someone will have time to write a comprehensive explanation soon. In the meantime here is what I can do in a couple of minutes.

In order to obtain a warning free and error-free working “production” build, you need to edit the NgModule app module definition for your program, specifically the declarations array. This array should contain a list of all of the components and directives in your application.

Now for the harder part. You must perform a “topological sort” of this list, or for those who didn’t study computer science formally or recently, you need to rearrange the order of this list such that the components are in reverse order of use, with the components used most “deeply” in your component hierarchy, listed first.

For example, consider if you had five components in your program, A B C D E. If for example component A used component B in its template, and component B used component C in its template, and so on, then the dependencies between these components are A->B, B->C, C->D, D->E, E->F. In this case the correct order to list them in the declarations would be declarations: [E, D, C, B, A].

Fortunately, in most applications there is not such a deep dependency graph among all components. In many cases you will make this error go away just by editing that declarations list to (1) list all your components, and (2) list your directives and fine-grained small components the beginning, as a heuristic.

How does something like this get broken and still released in RC5?

Bundling and minification are not new things, they are an essential and fundamental part of the JavaScript ecosystem. The bundling and minification within Angular 2 has had plenty of issues before - more excusable when it was Alpha or Beta and maybe the first couple of times it happened.

Surely the testing and release system should include some tests that include some bundling and minification?

+1

the Function#name minification issue was resolved by 51877ef4ed5016bd0c57f35e7bbb1ee26511ab5d, once rc.6 is out it should not longer be necessary to tell uglify not to mangle function names.

Solved: The problem is the order of the components in declarations field, but it’s weird it’s only happening in bundled-code, I need early feedback on that when in development

Thanks to @hansl, we got to the bottom of this last night.

The code generation uses Function#name in several places, which is not a problem with Ahead of Time (AOT) compilation, but if we are in the JIT mode and the input is minified code then name collisions occur.

Declarations reordering might make the problem go away, but there still might be hidden surprises with that approach since its not really solving the problem.

The only safe fix right now is to configure uglify with mangle: { screw_ie8 : true, keep_fnames: true} or use AOT template compilation.

We are looking into an actual fix for JIT.

I also have this problem. Changing the declarations order did not fix it for me.

Experienced same problem and got up and running with the same solution.

I am not, as of this moment, particularly a fan of this new behavior 😃 and I heartily encourage the team to document it in the change log under “breaking changes”.

Same here. I’m using Webpack (https://github.com/AngularClass/angular2-webpack-starter) and the solutions proposed here seem very overkill at first glance. No matter how I order my declarations, I end up getting the same error. Also, while I wouldn’t call those proposals hacky, they seem far from usable in a business-critical application.

Regardless, with all due respect to the Angular2 team it’s beyond me how this could have made it into RC5. Also, rolling out NgModules at this stage IMHO seems like a very controversial move.

Same problem here, solved it with the mangle option set to false.

@ediri Using an RC in production is bad, there’s no question about that (we are not doing that btw). The point that I was trying to make is that most people actually don’t expect there to be such significant changes at this stage and migrating to the new modules was obviously inevitable. It basically threw everything apart for us (the app is quite large at this point), refactoring takes time and sometimes - like in this case - refactoring almost seems impossible.

Solution to fix “ng serve --prod” with “angular-cli 1.0.0-beta.11-webpack.2 - RC5”

Ok, I finally figured out a way by directly changing the file in the node_modules folder, but I imagine there is a better place to do this within my project. Thanks @mikeeus for the setting.

capture2

@herlon214 - It works fine with the normal build, I am trying to do a --prod build which is where I have a problem.

The solution proposed in #1644 worked for me:

...
mangle: { screw_ie8 : true, keep_fnames: true }, //prod

@ediri @thecritic i do agree with @ediri , that’s not the kind of changes supposed to appear in a RC.

I have exactly same problem since updating to Angular2 RC.5. In RC4 all was working very well. Not uglified bundle works well. Also uglified bundle but without --mangle works well but it weights slightly more that it would with mangle

There are two workarounds that were also mentioned here:

  1. reorder things in declarations - which really does not always works because some components might use one another in both ways in which case this approach would not help. However because this helps in some cases then I would suspect that uglified package puts definitions according to order in declarations.
  2. uglify without --mangle which producees minified package but slightly bigger than it would be with mangle from what I observed.

I hope it gets solved. In RC.4 all was working fine in my case with same components and same version of uglifyJS.

Angular 2.0.0-rc.5 browsers-all typescript: 1.8.10 uglifyJS: 2.4.10

I am getting the same problem even I have already included the following code in the webpack.config as described on angular.io

new webpack.optimize.UglifyJsPlugin({
  mangle: {
    keep_fnames: true
  },
})

My project using ASP.NET MVC 4 and Angular 2 is using for one of many single page app we are currently having.

The error I am facing now is during the uglify process, the ngModel is becoming ngmodel (lower case)

zone.js:388Unhandled Promise rejection: Template parse errors: Can’t bind to ‘ngmodel’ since it isn’t a known property of ‘input’. (“olumn-main-map> <div id=map> </div> <div class="checkbox chk-traffic"> <label> <input type=checkbox [ERROR ->][(ngmodel)]=showTrafficLayer (ngmodelchange)=mapService.setTraffic($event) /> Show Traffic </label> <”): AppComponent@0:313 Can’t bind to ‘ngif’ since it isn’t a known property of ‘div’. ("$event) /> Show Traffic </label> </div> </div> <map></map> </div> </div> <div class=loading-wrapper [ERROR ->]*ngif=dispatchService.isLoading> <div class=loading-icon> <i class=“fa fa-spinner fa-spin fa-3x fa-fw”): AppComponent@0:480 Property binding ngif not used by any directive on an embedded template

Original

<input type="checkbox" [(ngModel)]="showTrafficLayer" (ngModelChange)="mapService.setTraffic($event)" />

Uglify

<input type=checkbox [(ngmodel)]=showTrafficLayer (ngmodelchange)=mapService.setTraffic($event) />

Have anyone faced this issue?

@mikeeus I have the same confusion as @nukuuk with where to put the “mangle” setting - because there is no “webpack.config.js” file (I did a fresh “ng new” with angular-cli 1.0.0-beta.11-webpack.2 - RC5).

So, where do I create the webpack.config.js file and do I need to modify angular-cli.json to use it?

Attached is a screenshot of the files I have with the default angular-cli.json settings.

capture

If anyone wants to generate an arbitrarily large application to help prove out tools (and reveal issues like this one), I just updated my “angular2-stress-test” for rc.5 and NgModule:

https://www.npmjs.com/package/angular2-stress-test

npm install -g angular2-stress-test
cd directory-with-your-components-in-it
angular2-stress-test 500

My code works perfectly in dev environment when I try npm run build I get the following error:

ERROR in ./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./node_modules/extract-text-webpack-plugin/dist/loader.js? {“omit”:0,“remove”:true}!./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./src/app/communication-center/comm-center .component.scss Module build failed: .all-common-grid { ^ Invalid CSS after “e”: expected 1 selector or at-rule, was “exports = module.ex” in D:\dev\Greater_Giving\CommunicationCenter\src\app\communication-center\comm-center.component.scss (line 1, column 1) @ ./src/app/communication-center/comm-center.component.scss 2:21-317 @ ./src/app/communication-center/comm-center.component.ts @ ./src/app/communication-center/comm-center.module.ts @ ./src/app/app-routing.module.ts @ ./src/app/app.module.ts @ ./src/app/main.ts

ERROR in ./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./node_modules/extract-text-webpack-plugin/dist/loader.js? {“omit”:0,“remove”:true}!./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./src/assets/style.scss Module build failed: /* Imported Stylesheet */ ^ Invalid CSS after “e”: expected 1 selector or at-rule, was “exports = module.ex” in D:\dev\Greater_Giving\CommunicationCenter\src\assets\style.scss (line 1, column 1) @ ./src/assets/style.scss 2:21-286

Following is my code

webpack.config.common.js

var HtmlWebpackPlugin = require(‘html-webpack-plugin’); var ExtractTextPlugin = require(‘extract-text-webpack-plugin’); var CopyWebpackPlugin = require(‘copy-webpack-plugin’); var helpers = require(‘./helpers’); var webpack = require(‘webpack’);

module.exports = { entry: { ‘app’: ‘./src/app/main.ts’, ‘polyfills’: ‘./src/polyfills.ts’, ‘styles’ : ‘./src/assets/style.scss’ }, resolve: { extensions: [‘.ts’, ‘.js’] }, module: { rules: [ { test: /.ts$/, use: [ { loader: ‘awesome-typescript-loader’, options: { transpileOnly: true } }, { loader: ‘angular2-template-loader’ }, { loader: ‘angular-router-loader’ } ] }, { test: /.html$/, loaders: [‘html-loader’] }, { test: /.scss$/, exclude: [ /node_modules/, helpers.root(‘src’, ‘style.scss’) ], use: [ ‘to-string-loader’, ‘css-loader’, ‘sass-loader’ ] }, { test: /.scss$/ , use: ExtractTextPlugin.extract({ use: ‘css-loader!sass-loader’ }) }, { test: /.(png|jpe?g|gif|svg|woff|woff2|otf|ttf|eot|ico)$/, use: ‘file-loader?name=assets/[name].[hash].[ext]’ } ], exprContextCritical: false }, plugins: [ new ExtractTextPlugin({ // define where to save the file filename: ‘styles/[name].bundle.css’, allChunks: true, }), new HtmlWebpackPlugin({ template: ‘src/index.html’ }), new CopyWebpackPlugin([ { from: ‘node_modules/froala-editor/css/’, to: ‘assets/froala-editor/css/’, }, { from: ‘node_modules/font-awesome/css/font-awesome.min.css’, to: ‘assets/font-awesome/css/font-awesome.min.css’, }, { from: ‘node_modules/font-awesome/fonts’, to: ‘assets/font-awesome/fonts’ } ]), new webpack.ProvidePlugin({ $: “jquery”, jQuery: “jquery” }) ] };

webpack.config.prod.js var path = require(‘path’); var webpack = require(‘webpack’); var webpackMerge = require(‘webpack-merge’); var commonConfig = require(‘./webpack.config.common’); var ExtractTextPlugin = require(‘extract-text-webpack-plugin’); var UglifyJSPlugin = require(‘uglifyjs-webpack-plugin’);

const ENV = process.env.NODE_ENV = process.env.ENV = ‘production’;

module.exports = webpackMerge(commonConfig, { output: { path: path.resolve(__dirname, ‘dist’), publicPath: ‘/’, filename: ‘[name].[hash].js’, chunkFilename: ‘[id].[hash].chunk.js’ }, plugins: [ new webpack.NoEmitOnErrorsPlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: { keep_fnames: true } }), new ExtractTextPlugin(‘styles.[hash].css’), new webpack.DefinePlugin({ ‘process.env’: { ‘ENV’: JSON.stringify(ENV) } }), new webpack.LoaderOptionsPlugin({ options: { htmlLoader: { minimize: false // workaround for ng2 } } }), new UglifyJSPlugin() ] });

@Maseeharazzack

Where do you put mangle: { screw_ie8 : true, keep_fnames: true}? I’m having trouble figuring out how to reconfigure uglify when using angular-cli.

update: JIT fix will required bigger changes in the core since it’s not really an issue with the core code/design, but with how the classes are transpiled to functions in various tools. We will consider implementing a workaround in the core once more pressing issue are resolved. In the meantime please use keep_fnames option in uglify or use Angular’s AOT compilation with ngc.

Experienced almost the same problem.

I have 2 directives (A and B) and 1 component ©. if the order in declarations is [A, B, C], I get the error above for @Input in directive B. if the order in declarations is [B, A, C], I get the error above for @Input in directive A. A and B don’t share any dependencies. C is using both A and B. This happens only for bundled build. I am using cli version 1.0.0-beta.10

With ES5 if declarations are in the “wrong” order some components will simply not be displayed, without any errors. Plunk: plnkr.co/edit/7qi6Um1UzTXBDrV5q1Js

If this is not fixed for 2.0.0 it would be better to say that Angular 2 does not support ES5, period.

I faced similar issue in bundled release for https://sirajc.github.io/angular2-labs/ I had to add NavbarComponent to bootstrap array bootstrap: [ AppComponent, NavbarComponent ] while deploying, whereas locally during dev I had only bootstrap: [ AppComponent] I encountered this issue few days ago while working on master branch, Thought this is the intended behavior

@Martin-Wegner I got this to work. I had to update package.json, to make sure I had updated versions for all dev dependencies. In addition, I had to change this dependency to 2.5.41, in order for the client-side build to work, as mentioned in https://github.com/angular/angular.io/issues/3198

  • "@types/jasmine": "^2.5.35",
    

Thanks for your assistance along the way. That said, I am still concerned as to how minor versions in these dependencies, have such a significant impact, and it appears that the angular.io docs for webpack and angular https://angular.io/docs/ts/latest/guide/webpack.html are not being kept up to date entirely, or aren’t being fully tested. This is the second time, I’ve run into an issue when following them.

“ngc” is the command line Angular 2 template precompiler. It is in the package “npm i @angular/compiler-cli”.

@TheLarkInn I think @ofuangka was asking: where should this be put today, to have it work, rather than at an unknown future date when a new CLI release ships?

(The best answer is probably: nowhere - instead, use “npm link” to run with the current master CLI instead of the released version.)

@Ibrahim-Islam you are on one of the betas affected by a minification issue that lasted like for 10 betas (beta.1 to ~beta.15 or so). It has nothing to do with this issue though.

Aside from this issue with ngUpgrade, I suspect this will mostly be a “doesn’t matter at all” in the near future. As soon as CLI uses NGC, that will “raise the bar”. Once any random person off the Internet can launch a new project in a couple of minutes with CLI and have template pre-compilation running, no one seriously using Angular to to the point they care about production mode, will be able to justify not using NGC. Other tooling will have to catch up very quickly or be abandoned.

Imagine all of this but adding ngUpgrade in the middle 😛

We like rock’n’roll! 😃

I managed to fix my application. The problem was that the 2 components weren’t using moduleId: module.id in the @Component declaration. Once I added moduleId: module.id prod build is ok.

@antonybudianto Which order did you change ?

@trungk18 I think you have to also configure your html-loader. Try this:

htmlLoader: {
        minimize: false // workaround for ng2
}

This workaround is from the Webpack production configuration in Angular docs.

@princemaple thanks for the suggestion, still getting the original error message (see below) when running after building for prod mode. Building in dev mode, works fine.

zone.js?fad3:355Unhandled Promise rejection: Template parse errors: Can’t bind to ‘appname’ since it isn’t a known property of ‘app-nav’.

  1. If ‘app-nav’ is an Angular component and it has ‘appname’ input, then verify that it is part of this module.
  2. If ‘app-nav’ is a Web Component then add “CUSTOM_ELEMENTS_SCHEMA” to the ‘@NgModule.schema’ of this component to suppress this message.

@mchamo you probably have htmlLoader, make sure you set it like so:

      {
        test: /\.html$/,
        loader: 'html',
        options: {
          minimize: true,
          removeAttributeQuotes: false,
          caseSensitive: true, // <- this
          customAttrSurround: [
            [/#/, /(?:)/],
            [/\*/, /(?:)/],
            [/\[?\(?/, /(?:)/]
          ],
          customAttrAssign: [/\)?\]?=/]
        }
      },

@ricklove I’ve upgraded to the latest releases Angular 2.0.0 and Angular CLI 1.0.0-beta.14 but the edit mangle approach is not working.

The webpack-build-production.ts file is in a different location. It now seems to be in;

node_modules/angular-cli/models/webpack-build-production.js

When I edit this file and change it to include keep_fnames:true I still get the error…

`Can’t bind to ‘customerNumber’ since it isn’t a known property of ‘channel-detail-panel’.

  1. If ‘channel-detail-panel’ is an Angular component and it has ‘customerNumber’ input, then verify that it is part of this module.
  2. If ‘channel-detail-panel’ is a Web Component then add “CUSTOM_ELEMENTS_SCHEMA” to the ‘@NgModule.schema’ of this component to suppress this message. ("nnel-detail-panel *ngFor=“let channel of channelList.results” [ERROR ->][customerNumber]=“customerNumber” [channelModel]=“channel”> "): ChannelManagementComponent@10:38`

I’ve compared the two main.xxxx.bundle.js files with and without this workaround and they are different. The one with the workaround is about 1.47 Mb and one without the change is about 1.32 Mb.

I see this issue has been closed and “included” in release 2.0.1 of Angular but I can’t tell what was actually changed.

I’ve also tried a number of different combinations with the declarations order but I still get the problem.

Which versions of Angular and Angular CLI are people using in which the edit mangle approach works??

Any help would be much appreciated 😃

[Update] - I’ve just seen @IgorMinar comment about 51877ef fixing this issue in rc.6 but I’m using release 2.0.0 and it still seems to be a problem.

[SOLVED] - Ack, my fault. I think my actual problem was that my selector declaration in the sub-component “channel-detail-panel” wasn’t right it was set to “app-channel-detail-panel” when it should have been just “channel-detail-panel” - so the error was right, but not explaining things very well.

I think this issue is working correctly now in Angular 2.0.0 + Angular CLI 1.0.0-beta.14 without the edit mangle workaround. Just make sure your selector declarations are correct.

i tried the suggestions in the thread. still getting:

Can't bind to 'icon' since it isn't a known property of 'button'. ("ver':hovered,'ui-state-focus':focused,'ui-state-disabled':disabled}" ><button type="button" [ERROR ->][icon]="icon" pButton *ngIf="showIcon" (click)="onButtonClick($event,in)" [ngClass]="): Calendar@7:31 ; Zone: <root> ; Task: Promise.then ; Value: BaseException {message: "Template parse errors:↵Can't bind to 'icon' since …in)" ↵ [ngClass]="): Calendar@7:31", stack: "Error: Template parse errors:↵Can't bind to 'icon'…odules/zone.js/dist/zone.js?1472035648186:365:38)"} Error: Template parse errors: Can't bind to 'icon' since it isn't a known property of 'button'. ("ver':hovered,'ui-state-focus':focused,'ui-state-disabled':disabled}" ><button type="button" [ERROR ->][icon]="icon" pButton *ngIf="showIcon" (click)="onButtonClick($event,in)" [ngClass]="): Calendar@7:31 at new BaseException (http://localhost:5555/node_modules/@angular/compiler/bundles/compiler.umd.js:5116:27) at TemplateParser.parse (http://localhost:5555/node_modules/@angular/compiler/bundles/compiler.umd.js:8318:23) at RuntimeCompiler._compileTemplate (http://localhost:5555/node_modules/@angular/compiler/bundles/compiler.umd.js:15941:55) at eval (http://localhost:5555/node_modules/@angular/compiler/bundles/compiler.umd.js:15869:87) at Set.forEach (native) at compile (http://localhost:5555/node_modules/@angular/compiler/bundles/compiler.umd.js:15869:51) at ZoneDelegate.invoke (http://localhost:5555/node_modules/zone.js/dist/zone.js?1472035648186:332:29) at Zone.run (http://localhost:5555/node_modules/zone.js/dist/zone.js?1472035648186:225:44) at http://localhost:5555/node_modules/zone.js/dist/zone.js?1472035648186:591:58 at ZoneDelegate.invokeTask (http://localhost:5555/node_modules/zone.js/dist/zone.js?1472035648186:365:38)consoleError @ zone.js?1472035648186:484_loop_1 @ zone.js?1472035648186:511drainMicroTaskQueue @ zone.js?1472035648186:515ZoneTask.invoke @ zone.js?1472035648186:437

@cdarken Currently I am using angular-cli 1.0.0-beta.11-webpack.2 with RC5 (the following may not be the case with angular-cli 1.0.0-beta.10, I don’t know). And as this thread reports, if you run ng build -prod this will break the app because (presumably)
a) the cli mangles the javascript bundle and angular or webpack doesn’t like this, and/or b) there is some problem with the ordering of the the components in main module declaration.

There is not bug fix for this now, hopefully will happen soon.

In the mean time, my workaround involves running ng build which will bundle the app but not minify/mangle the javascript bundles. Then I am using gulp-uglify with {mangle: false} to concatenate and minify into a final production bundle. It works. But I would much prefer if the angular cli finished the job.

@IgorMinar Won’t there currently be an issue relying on AOT compilation when using ngUpgrade? ngUpgrade doesn’t utilize the aot code even if it exists.

Same here. Using systemjs and systemjsBuilder. Temporary solution: I used gulp-uglify to bundle my files at the end of build process. Removed this pipe and it works. Using SystemJs without systemjsBuilder (for dev: directly mapped to the node_modules folder) it was no problem.

So it looks more for a bundling/minifiying/uglifying problem than implicit ordering to me…but we’ll see

@thecritic using a RCx for a business-critical application is borderline… But that’s none of my business… 😉

Note: I added moduleId: module.id and it made things worse. The minified javascript isn’t loading anything except a useless error ‘home.js:260 Uncaught TypeError: e.match is not a function

Going to try to add moduleId back but use NgModule?

Then try playing with the order of the declarations?

Is there an actual fix or just keep trying until it works for me?

Update:

“SOLUTION”: The solution for me was to remove moduleId: module.id and re-arrange the order of the components in the declarations with NgModule.

Now to figure out why it’s not working with moduleId: module.id ?

Update II: Yah, my time is up for they day…webpack -p is really not liking moduleId at all! 😦 Moreover, it looks like it never has? bleh

Same problem, also happening when using Angular 2 with JavaScript ES5 (even with the normal version, not bundled).

Fixed it - I had this error in my unit tests, so I had to fix the declarations in my TestBed.configureTestingModule call instead of my app module.