Skip to content

The result of code generated by ng build --prod is different from code generated by ng build #6454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lucianojardim opened this issue May 25, 2017 · 8 comments

Comments

@lucianojardim
Copy link

lucianojardim commented May 25, 2017

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Versions.

@angular/cli: 1.0.5
node: 6.10.3
os: darwin x64
@angular/common: 4.1.3
@angular/compiler: 4.1.3
@angular/core: 4.1.3
@angular/forms: 4.1.3
@angular/http: 4.1.3
@angular/platform-browser: 4.1.3
@angular/platform-browser-dynamic: 4.1.3
@angular/router: 4.1.3
@angular/cli: 1.0.5
@angular/compiler-cli: 4.1.3

Repro steps.

Both ng build and ng build --prod run without generating error messages. Everything seems OK but the code generated by ng build results in the display of 77 lines (as expected) while ng build --prod displays 1 line only.

The log given by the failure.

I didn't modify the environment settings.
There is no failure that I could see. Both seem to be compiling without issues.

ng build
Hash: ea7b04b8a69e4a08f068
Time: 19641ms
chunk {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 158 kB {5} [initial] [rendered]
chunk {1} main.bundle.js, main.bundle.js.map (main) 821 kB {4} [initial] [rendered]
chunk {2} styles.bundle.js, styles.bundle.js.map (styles) 147 kB {5} [initial] [rendered]
chunk {3} scripts.bundle.js, scripts.bundle.js.map (scripts) 266 kB {5} [initial] [rendered]
chunk {4} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.92 MB [initial] [rendered]
chunk {5} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]

ng build --prod
Hash: 277f842cca1d5921283b
Time: 31756ms
chunk {0} polyfills.1577c7d212bc014644eb.bundle.js (polyfills) 158 kB {5} [initial] [rendered]
chunk {1} main.c366c9602d2a66ca8dac.bundle.js (main) 965 kB {4} [initial] [rendered]
chunk {2} scripts.c4fec663d6273ee04888.bundle.js (scripts) 266 kB {5} [initial] [rendered]
chunk {3} styles.d96180d746287286ac7b.bundle.css (styles) 175 bytes {5} [initial] [rendered]
chunk {4} vendor.314120fa29a6055b1439.bundle.js (vendor) 1.92 MB [initial] [rendered]
chunk {5} inline.42b23acf2c594abf3fb5.bundle.js (inline) 0 bytes [entry] [rendered]

Desired functionality.

I was expecting the both (ng build and ng build --prod) would produce the same result during execution.

I've tried compiling with @angular/cli versions 1.02, 1.03, 1.04, and 1.05, and all versions produced the same result on mac and windows.

Mention any other details that might be useful.

Component that is producing this behavior:

import {Component, OnDestroy, OnInit} from '@angular/core';
import {Router, ActivatedRoute} from '@angular/router';
import {Subscription} from 'rxjs/Subscription';

import {BrandService} from './brand.service';
import {Brand} from './brand.model';
import {Series} from './series/series.model';
import {SeriesService} from './series/series.service';

@component({
selector: 'app-brand',
templateUrl: './brand.component.html',
styleUrls: ['./brand.component.css']
})
export class BrandComponent implements OnInit, OnDestroy {
selectedBrand: Brand;
subscription: Subscription;
selectedSeries: Series;
serieses: Series[] = [];
selectFirstOption = 'Select a Series';

constructor(private _router: Router,
private _activatedRoute: ActivatedRoute,
private _brandService: BrandService,
private _seriesService: SeriesService) {
}

ngOnInit() {
this.getSelectedBrand();
this.getSerieses(this.selectedBrand);
}

onSelectedSeries(): void {
if (typeof this.selectedSeries === 'object') {
this._seriesService.setSelectedSeries(
this._seriesService.getSeriesByNameAndBrand(
this.selectedSeries.name,
this._brandService.getSelectedBrand()
)
);
this._router.navigate([encodeURIComponent(this.selectedSeries.name)], {relativeTo: this._activatedRoute})
.then()
.catch();
} else {
this._router.navigate(['.'], {relativeTo: this._activatedRoute})
.then()
.catch();
}
}

getSelectedBrand() {
this.selectedBrand = this._brandService.getSelectedBrand();
this.subscription = this._brandService.selectedBrandChanged
.subscribe(
(brand: Brand) => {
this.selectedBrand = brand;
}
);
}

getSerieses(selectedBrand: Brand) {
this.serieses = this._seriesService.getSerieses(selectedBrand);
}

ngOnDestroy() {
this.subscription.unsubscribe();
}
}

HTML template:
<app-header></app-header>

<div class="container-fluid">

<div class="row">

<div class="col-xs-12 col-md-12">

<form class="form-group" #f="ngForm" novalidate>

<label>Series</label>

<select title="Select a series" class="selectpicker form-control" (change)="onSelectedSeries()"

name="selectForSeries"

[(ngModel)]="selectedSeries">

<option>{{selectFirstOption}}</option>

<option *ngFor="let series of serieses" [ngValue]="series">{{series.name}}</option>

</select>

</form>

<hr>

<router-outlet></router-outlet>

</div>

</div>

</div>

@Simon-Briggs
Copy link

Simon-Briggs commented May 25, 2017

https://github.com/angular/angular-cli/wiki/build#--dev-vs---prod-builds

If you don't specify --prod the default build is --dev which doesn't AOT compile or minify your app

@lucianojardim
Copy link
Author

I want to use --prod in the build (and get the benefits of minifying it and aot compilation) but I can't. If I do that, the application doesn't work correctly. Today, only if I omit --prod, I get the results that I would expected (77 rows displayed, instead of only one).

I don't know why that happens but I can reproduce it in two different operating systems (mac os and windows), and in different versions of @angular/cli (1.02, 1.03, 1.04, and 1.05).

@sumitarora
Copy link
Contributor

@lucianojardim Seems like your code is not aot compatible and having issues in that. You can run aot dev build using ng s --aot and check if that works as well as fix the error as you will see more detailed errors. If it's still an issue, Can you share code replicating issue or subset of it?

@sumitarora sumitarora self-assigned this May 25, 2017
@lucianojardim
Copy link
Author

"ng s --aot" and "ng build --aot" produce the expected results but "ng build --prod --aot false" doesn't. It seems to indicate that the issue could be in the minification/optimization process (not the aot).

canbedeleted.zip

I've uploaded an anonymized version of the app. The app can be recreated by just running "npm install".

If you run ng b --prod, the issue can be reproduced doing the following: when the first screen is displayed, please, enter any valid email address, in the nav bar choose "Brands", then "Try this", select series "10500. This series is expected to have 77 items but only 1 will be displayed.

If you have any questions, please, let me know.

Thank you for your assistance.

@sumitarora
Copy link
Contributor

@lucianojardim Yes seems like issue is due to UglifyJsPlugin removing that and running prod build works fine.

@lucianojardim
Copy link
Author

lucianojardim commented May 26, 2017

I'm new to @angular/cli. What should I do to minify the code or gain better performance?

@filipesilva filipesilva added P1 Impacts a large percentage of users; if a workaround exists it is partial or overly painful severity2: inconvenient type: bug/fix labels Jun 26, 2017
@filipesilva
Copy link
Contributor

Heya @lucianojardim, I've been looking at your code and think I've found the problem.

In the setSelected method inside selected.service.ts, you have this piece of code:

this._selectedType = Series.name;

Where Series is this class:

export class Series {
  id: number;
  name: string;
  brandId: number;

  constructor(id: number, name: string, brandId: number) {
    this.id = id;
    this.name = name;
    this.brandId = brandId;
  }
}

When you do Series.name you are not accessing the name property of a Series instance, but rather the name property of the class Series itself.

A class gets downleveled to a function in ES5, and functions do have the name property - it's the name of the function itself. So in this case, it's the string "Series".

A big part of uglification is name mangling, where function and variable names are converted to a shorter version. This yields significant size savings and is done on production builds.

This means that in production, Series.name is not "Series", but something else like "e". And this is how your code is breaking right now.

Code that relies on accessing a function's name is not able to be uglifyied, and for that reason it is a good practice in the JS world to not rely on it. You can find that warning here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

Warning: Be careful when using Function.name and source code transformations, such as those carried out by JavaScript compressors (minifiers) or obfuscators. These tools are often used as part of a JavaScript build pipeline to reduce the size of a program prior to deploying it to production. Such transformations often change a function's name at build-time.

My advice for getting around this is to set a static property with the string you need instead:

export class Series {
  static type = 'Series';
  id: number;
  name: string;
  brandId: number;

  constructor(id: number, name: string, brandId: number) {
    this.id = id;
    this.name = name;
    this.brandId = brandId;
  }
}

This way you can use Series.type instead of Series.name and it will not break on production builds.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants