angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.72k stars 11.98k forks source link

Angular cli changes css files order when build #9475

Closed chaouiy closed 4 years ago

chaouiy commented 6 years ago

When I check bundle after ng build --prod --aot false I found that css files order was modified by the build process.

angular-cli.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "performance"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "../node_modules/bootstrap/dist/css/bootstrap.css",
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/animate.css/animate.min.css",
        "../node_modules/ng2-toastr/bundles/ng2-toastr.min.css",
        "styles.scss"
      ],
      "scripts": [
        "../node_modules/jquery/dist/jquery.js",
        "../node_modules/metismenu/dist/metisMenu.js",
        "../node_modules/jquery-sparkline/jquery.sparkline.js",
        "../vendor/pace/pace.min.js"
      ],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json"
    },
    {
      "project": "src/tsconfig.spec.json"
    },
    {
      "project": "e2e/tsconfig.e2e.json"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "component": {}
  }
}

package.json

{
  "name": "performance",
  "version": "1.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --host 0.0.0.0",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^4.0.1",
    "@angular/common": "^4.0.1",
    "@angular/compiler": "^4.0.1",
    "@angular/compiler-cli": "^4.0.1",
    "@angular/core": "^4.0.1",
    "@angular/forms": "^4.0.1",
    "@angular/http": "^4.0.1",
    "@angular/platform-browser": "^4.0.1",
    "@angular/platform-browser-dynamic": "^4.0.1",
    "@angular/platform-server": "^4.0.1",
    "@angular/router": "^4.0.1",
    "@ngui/auto-complete": "^0.16.0",
    "@swimlane/ngx-charts": "^6.1.0",
    "angular-autofocus-fix": "^0.1.0",
    "angular2-image-upload": "^1.0.0-rc.0",
    "angular2-masonry": "^0.4.0",
    "angular2-moment": "^1.7.0",
    "animate.css": "3.1.1",
    "bootstrap": "^3.3.7",
    "chart.js": "^2.7.1",
    "core-js": "^2.4.1",
    "d3": "^4.11.0",
    "font-awesome": "^4.7.0",
    "jquery": "^3.1.0",
    "jquery-slimscroll": "^1.3.8",
    "jquery-sparkline": "^2.4.0",
    "jvectormap": "1.2.2",
    "metismenu": "^2.5.0",
    "ng2-charts": "^1.5.0",
    "ng2-completer": "^1.6.3",
    "ng2-file-upload": "^1.2.1",
    "ng2-smart-table": "^1.2.2",
    "ng2-toastr": "^4.1.2",
    "ngx-bootstrap": "^1.6.6",
    "ngx-slimscroll": "^3.4.1",
    "ngx-ui-switch": "1.4.4",
    "ngx-webstorage": "^1.8.0",
    "peity": "^3.2.1",
    "rxjs": "^5.1.0",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@angular/cli": "^1.0.0",
    "@angular/compiler-cli": "^2.4.0",
    "@types/jasmine": "2.5.38",
    "@types/node": "~6.0.60",
    "codelyzer": "~2.0.0",
    "jasmine-core": "~2.5.2",
    "jasmine-spec-reporter": "~3.2.0",
    "karma": "~1.4.1",
    "karma-chrome-launcher": "~2.0.0",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^0.2.0",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.0",
    "ts-node": "~2.0.0",
    "tslint": "~4.5.0",
    "typescript": "~2.4"
  }
}
clydin commented 6 years ago

Please provide the output of ng --version. A minimal reproduction would also be very useful to aid in further investigate of the issue.

chaouiy commented 6 years ago

ng --version:

Your global Angular CLI version (1.6.7) is greater than your local
version (1.6.5). The local Angular CLI version is used.

To disable this warning use "ng set --global warnings.versionMismatch=false".

    _                      _                 ____ _     ___
   / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
  / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
 / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
/_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
               |___/

Angular CLI: 1.6.5
Node: 9.4.0
OS: linux x64
Angular: 4.4.6
... animations, common, compiler, compiler-cli, core, forms
... http, platform-browser, platform-browser-dynamic
... platform-server, router, tsc-wrapped

@angular/cli: 1.6.5
@angular-devkit/build-optimizer: 0.0.42
@angular-devkit/core: 0.0.29
@angular-devkit/schematics: 0.0.52
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.5
@schematics/angular: 0.1.17
typescript: 2.4.2
webpack: 3.10.0
chaouiy commented 6 years ago

When I open xxxxbundle.css I find the order of css injections different than the order specified in angular-cli.json

dgsqrs commented 6 years ago

I have the same issue starting cli 1.6.4 (does not occurs on 1.7.0-beta3).

jmorganmartin commented 6 years ago

I can confirm this issue exists in angular-cli 1.65, 1.6.6 and 1.6.7. If you reverse the order of your styles array in angular-cli.json, you can preview the bug in 'serve' mode, to a degree

jmorganmartin commented 6 years ago

@clydin on 1.6.7, when I build with a styles array like below:

  "styles": [
    "../node_modules/bootstrap/dist/css/bootstrap.min.css",
    "../node_modules/font-awesome/css/font-awesome.min.css",
    "../node_modules/angular-calendar/dist/css/angular-calendar.css",
    "../node_modules/nouislider/distribute/nouislider.min.css",
    "styles.scss"
  ],

The CSS files are bundled with styles.scss at the top. The rest follow the correct order. (In my screenshoot, nouislider is after angular-calendar on the same line; it's in there, but not in the screenshot).

image

jmorganmartin commented 6 years ago

Reverting to 1.6.3 (and then installing @angular-devkit/core@0.0.29 manually via NPM) was the only solution I could find.

chaouiy commented 6 years ago

ng build --prod -extract-css false solved the problem until finding final solution

mark-langer commented 6 years ago

@clydin I'm experiencing this issue with the Angular CLI v1.7.1 too. The styles array looks like this:

"styles": [
    "./app/shared/styles/material-theming.css",
    "./app/shared/styles/styles.css"
],

Yet, the CSS of material-theming.css is inserted below the rules of styles.css.

This issue is marked with the label "need: more info". What other info can we provide that would help you debug this?

Come2Daddy commented 6 years ago

I had the same problem while adding third-party CSS framework I wanted to extend. Finaly I just imported it through src/styles.(sass/css/scss) and it works great. As styles you insert into .angular-cli.json are intended to be global, using src/styles.(sass/css/scss) you reach the same goal. I think it's a nice work around.

rflament commented 6 years ago

I had the same problem with 1.6.4 and switching to cli 1.7.4 fixed it.

msklvsk commented 6 years ago

Did a clean npm i with the latest everything, including cli 1.7.4 — the problem is still there.

I’m afraid “need: more info” label diverts attention away from this issue while ng --version was provided back in February.

danielstern commented 6 years ago

Strangely, I notice that the styles are in the desired order when I run in dev mode, but in the wrong order when I run in production.

andresmgsl commented 6 years ago

Any update on this?

jmorganmartin commented 6 years ago

@andresmgsl Not sure which version fixed this, but it's not present in 1.7.1, at least.

angusoid commented 6 years ago

I already reverted CLI twice because of this issue.

1.71 > 1.68 1.74 > 1.68

Same problem with 6.03 version now.

Dev build is fine, prod build still not good.

Related: https://github.com/angular/angular-cli/issues/10579

nicolasfoisy commented 6 years ago

I solved this issue by placing the css I wanted to import on top of styles.css instead of in the json file like recomended...

sebek64 commented 6 years ago

This issue is still present in 6.0.5. Or at least in some form. I'm migrating an existing project to Angular CLI, and when disabling extractCss, it works as intended, while with extractCss enabled, the styles are broken.

gaim281 commented 6 years ago

@nicolasfoisy can you please explain what you did there to solve it? what do you by placing the css... where did you place it? copied it into styles.css?

usernameisalreadyt4ken commented 6 years ago

Still present in 6.0.7. Setting extractCss to false fixes it for me too.

ErazerBrecht commented 6 years ago

Indeed issue is still present:

Repo: https://github.com/ErazerBrecht/ErazerCQRS/blob/5861a00cd484bc689d41212de248e46ba8d8a891/Erazer.Web.Angular/angular.json#L23

styles.css is the last style in the array but when extractCss is enabled, the bootstrap css file overwrites the styles.css rules because it's added under it in the bundle.

Angular CLI: 6.0.8 Node: 10.4.0 OS: win32 x64 Angular: 6.0.4

oneal1801 commented 6 years ago

@ErazerBrecht I am using a .scss file with the imports of the third party style instead of the style.css and I am having the same issue, every time I run the command ng build --prod it create the dist folder but the style.css is like corrupted because all classes are together in 1 line and are not taking effect, same happens to the main.js file.😓😭

do you think I should change it back to the style.css?

kuflash commented 6 years ago

@clydin I also see a similar problem, but I build my application with custom webpack config. And CSS selectors is reorder when I have AngularCompilerPlugin in my pipeline.

I'm created repository for showing this problem. In it you will see 2 directories (dist-dev and dist-prod) with different ordering CSS selectors.

I'm using:

Angular CLI: 6.0.8 Node: 9.10.1 OS: MacOS 10.13.4 Angular: 6.0.9

kuflash commented 6 years ago

It turned out to fix the problem by transferring the import common.scss from the app.module.ts to the browser.module.ts. But I'm sure that this is really the right decision.

I'm uploaded this fix in fix-reorder branch

Trojaan commented 6 years ago

Anyone else have a workaround for this issue? Setting extractCss doesn't seem to work for me either... Angular CLI 6.1.5.

oneal1801 commented 6 years ago

@Trojaan i fixed this issue with this issue #13948 adding this line in the index <script>document.write('<base href="' + document.location + '" />');</script> https://github.com/angular/angular/issues/13948

Trojaan commented 6 years ago

@oneal1801 Thanks! This fixed it! :)

fedotxxl commented 5 years ago

Very strange bug. My temporary solution:

moved all css files from angular.json to styles.scss using @import

elvince commented 5 years ago

Any update on this bug. I face the same issue. I did the same workaround as fedotxxl but this is not the proper way and I receive depreciation warning: "Including .css files with @import is non-standard behaviour which will be removed in future versions of LibSass. Use a custom importer to maintain this behaviour. Check your implementations documentation on how to create a custom importer."

Thanks for the feedback

jaykhatri commented 5 years ago

The problem is with your @import like you are importing some google font. So Angular transpile that stylesheet on priority basis and gets loaded before the said order. Let see this example:

"styles": ["node_modules/bootstrap/dist/css/bootstrap.min.css", "src/assets/css/new-age.css" ],

Just look at this new-age.css file: @import url('https://fonts.googleapis.com/css?family=Lato|Oswald'); html, body { width: 100%; height: 100%; background: #edf1f5; } ......

Solution is to make a separate css file for these imports and then mention it angular.json like this:

"styles": ["node_modules/bootstrap/dist/css/bootstrap.min.css", "src/assets/css/new-age.css", "src/assets/css/imp.css" ],

fedotxxl commented 5 years ago

What's the point to prioritize CSS files with @import?

elvince commented 5 years ago

As a develloper I should handle my priority or at least I should be able to tell that I don't want priority manager by Angular. I put stuff in specific order. This shouldn't be altered. More the worst thing is that we are only facing this in "build mode" not in serve. That's another stuff that is in my opinion is bad. That's the type of stuff you don't want to face when you deliver your app in QA environment.

thanks

jaykhatri commented 5 years ago

As a develloper I should handle my priority or at least I should be able to tell that I don't want priority manager by Angular. I put stuff in specific order. This shouldn't be altered. More the worst thing is that we are only facing this in "build mode" not in serve. That's another stuff that is in my opinion is bad. That's the type of stuff you don't want to face when you deliver your app in QA environment.

thanks

You need not to change the order or anything, All you need to do is to keep @import in a separate css file and add that too in angular.json and it will start working. I had exactly the same issue which I tried and it worked like charm for me.

jaykhatri commented 5 years ago

What's the point to prioritize CSS files with @import?

When Angular bundles multiple css files, it keep content of those files with @import prior to other no matter whatever order you put in angular.json.

sebek64 commented 5 years ago

@jaykhatri Maybe this behavior has some good reason, but it is often very inconvenient. For example, one can use some third-party library with a stylesheet using an import. There's no simple way to put the import in a separate file.

jaykhatri commented 5 years ago

@jaykhatri Maybe this behavior has some good reason, but it is often very inconvenient. For example, one can use some third-party library with a stylesheet using an import. There's no simple way to put the import in a separate file.

That's the bug for sure. All I shared was my experience in case if someone have simple @imports that can be handled.

elvince commented 5 years ago

Third party library is the key point here. I don't want to recreate/split all library css. I think we need to have a bool in the compiler to choose or not to apply the Css @import ordering.

As we said, the worst part in this also is that Prod Build & Serve don't behave the same.

elvince commented 5 years ago

Any news on this? Thanks,

@alan-agius4 @clydin Do you need more information to track this?

alan-agius4 commented 5 years ago

Hi, I have tried this using @angular-devkit/build-angular version 0.10.0 and @angular/cli version @angular/cli and was unable to reproduce.

When having the below;

"styles": [
  "node_modules/bootstrap/dist/css/bootstrap.min.css",
  "src/styles.scss"
],

The bootstrap css files was emitted on top of the contentes of styles.scss

Can you setup a minimal repro please? A good way to make a minimal repro is to create a new app via ng new repro-app and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here.

elvince commented 5 years ago

@alan-agius4

Hi,

Sorry for the late answer, but now here is a repro: https://github.com/elvince/AngularCSSReproBug

You can see that in angular.json I set:

"styles": [ "src/styles2.css", "src/styles.scss", "src/style.css" ]

And if you do: ng server --prod=true or ng build --prod

The content of the last Style.css is put at the beginning of the final style file.

I hope this will allow you to repro properly the bug and find the root cause. If you need more input, plz ask

alan-agius4 commented 5 years ago

@elvince, in css the @import rule must be at the top of the stylesheet, thus this sheetsheet which contains @import is taking priority over others. See https://developer.mozilla.org/en-US/docs/Web/CSS/@import

If the @import rule is removed the order is retained properly.

Closing as it's working as expected.

sebek64 commented 5 years ago

I don't understand why this has been closed. This is apparently a bug in cli, because it behaves differently in development and production mode. It should either behave consistently, or produce an error if there is some syntax error in the inputs.

elvince commented 5 years ago

@alan-agius4 Thanks for the feedback. While I understand that you are folowing the @import rules. I was just wondering if we can smartly solve this case.

I mean Angular is awesome because we have a lot of module available to us and sometime we can have @import statement in the css files that are in those external modules and we need to keep depency loading.

Let's say a module A depends on BootStrap but add a import statement how can we deal with this?

Here are my proposal: 1 - in case an @import is detected in a file, just push the statement at the top of the css but keep the rest at the same position (file ordering) 2 - Have a set of recommandation for "Modules css" to add import in seperated files so we can add them safely and the current reordering will work. 3 - ?? any other options?

Following what @sebek64 is saying, in all case Dev and Prod must behave the same so we don't discover css bugs later on in our dev workflow.

Thanks

fergardi commented 5 years ago

@chaouiy

ng build --prod -extract-css false solved the problem until finding final solution

Thank you, it is working for me as well! Can you explain me why this options works?

mloffer commented 4 years ago

Yikes, just ran into this. This seems like a much higher-priority issue than the attention it's currently being given would indicate. This bug eliminates the benefits of a testing environment. (Ask me how I know.)

The current workaround (to turn off extractCss) has the effect of applying styles from JavaScript instead of letting the browser handle it natively. This is a pretty bad compromise from a performance standpoint.

joshtune commented 4 years ago

I am having issues with this too. Hope it can be addressed

Dunos commented 4 years ago

So it's been more than 2 years, 1 after marked as "broken", but we still have no news about it at this day in 2020...

web-warrior commented 4 years ago

what a mess, consitency is very important, the fact that I have to use a workaround after years of the original discovery of such important aspect of large web site development that requires integration of third party overrides, bootstrap overrides, complex component overrides at the very least there should be a defined structure / hierarchy that is logical and sound for accurately applying css and managment of it long term. I hope this gets addressed soon!

Lately I've been asked to create demos and prototypes and it makes it very complicated for me to have to document specific build instructions and explain perf issues to the third parties I support and that will be evaluating the prototypes to use in thier environments! Really puts a shadow of doubt in thier minds about the apps and what else might be funky.

kvinbabbar commented 4 years ago

Facing same issue.

Angular CLI: 8.3.25 Node: 12.13.1 OS: win32 x64 Angular: 8.2.14

mloffer commented 4 years ago

Confirmed that this behavior still exists in Angular 9.

Angular CLI: 9.0.5 Node: 10.15.3 OS: win32 x64 Angular: 9.0.5 Ivy Workspace: Yes