18

Angular CLI provides the possibility to replace files when building the project. I would like to use this functionality to replace a SCSS file with default styling, with a SCSS file that contains customer specific CSS.

But Angular CLI seems not to replace the SCSS files. How could I achieve this?


What I have tried:

environment.default.ts

export const environment = {
  name: 'default'
};

environment.special.ts

export const environment = {
  name: 'special'
};

default/_scss-config.scss

@debug ('default'); // gets called but should never be called

special/_scss-config.scss

@debug ('special'); // never gets called

angular.json (only relevant parts)

  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "fileReplacements": [
          {
            "replace": "src/environments/environment.default.ts",
            "with": "src/environments/environment.special.ts"
          },
          {
            "replace": "src/scss/default/_scss-config.scss",
            "with": "src/scss/special/_scss-config.scss"
          }
        ],
        "stylePreprocessorOptions": {
          "includePaths": [
            "src/scss/default"
          ]
        }
      }
    }
  }

main.ts

import { environment } from './environments/environment.default';

console.log(environment.name); // 'special' --> replacement works!

Result:
File replacement for .ts files works, but not for .scss files, as the special debug statment never gets called, but the default does, even the file should have been repalced.

2
  • Show us the commands you've tried Commented Feb 17, 2019 at 9:52
  • @jo_va I think I already found the answer, but I added an minimal example. If you know a way to make this work, I would be happy to accept your answer. Commented Feb 18, 2019 at 7:22

2 Answers 2

44

Angular.io states that:

The main CLI configuration file, angular.json, [...] allows you to replace any file with a target-specific version of that file.

This is in fact the vision, but according to this GitHub thread, this is not true for now.
It seems up till now, only .ts and .html files are supported.

Therefore, currently the answer to the question is no, it is yet not possible to replace SCSS files.

But there is a workaround (see below).


Update Jan-2021: Still doesn't work. Tested with Angular 11.0.9.

TLDR:

  • Angular 11.x now errors on unsupported file types if you try to use the file replacement feature
    (the workaround described below still works, as it doesn't use the file replacement feature)

  • It only has file replacement support for the following types: .cjs, .js, .json, .mjs and, .ts

Background:
It seems the inital statement in the documentaion to support all file types was wrong. With Angular 11 a check was introduced, to error on unsupported file types.

fix(@angular-devkit/build-angular): add validation to fileReplacement…

fileReplacement is meant to replace compilation source files (JavaScript or TypeScript) with other compilation source files in the build. With this change we add validation to fail the build when the files have unsupported extensions.

So with Angular 11 two things changed. At first you have to use src and replaceWith instead of replace and with. Though this doesn't help as you will get Data path ".fileReplacements[1].replace" should match pattern "\.(([cm]?j|t)sx?|json)$"., if you use unsupported file types like .scss.


Update Feb-2020: Still doesn't work. Tested with Angular 9.0.0.


But there is a workaround:
You can use different configurations in angular.json to achieve the same goal - replacing a SCSS file.

folder structure:

src/
    scss/
        default/
            _scss-config.scss
        special/
             _scss-config.scss

src/scss/default/scss-config.scss

body { background-color: blue; }

src/scss/special/scss-config.scss

body { background-color: red; }

angular.json

<!-- language: lang-json -->

{
  [...]
  "architect": {
    "build": {
      "options": {
        "stylePreprocessorOptions": {
          "includePaths": [
            "src/scss/default"
          ]
        }
      },
      "configurations": {
        "default": {
          "stylePreprocessorOptions": {
            "includePaths": [
              "src/scss/default/"
            ]
          }
        },
        "special": {
          "stylePreprocessorOptions": {
            "includePaths": [
              "src/scss/special/"
            ]
          }
        }
      }      
    },
    "serve": {
      "configurations": {
        "default": {
          "browserTarget": "angular-scss-replacement:build:default"
        },
        "special": {
          "browserTarget": "angular-scss-replacement:build:special"
        }
      }
    }     
    [...]      
  }
}

style.scss or component.scss

@import 'scss-config';

/* use your SCSS variables and stuff as you normally would */

Note that you mustn't include the _ (underscore) from the filename in the import statement
(for more details read the Partials section)

How to use it:

// 'ng serve'-command uses default configuration as defined in angular.json > build 
ng serve

// default config creates blue background
ng serve --configuration=default


// specail config create red background
ng serve -c=special

(This solution is from the thread mentioned above - thx to richardtreier)


Drawbacks of this approach:

  • It forces you to have a specific folder structure to separate your different SCSS configurations
  • It might force you to move those folders out of your normal folder structure.
    For example, "includePaths": ["src/scss"] won't work with the folder structure mentioned above, since the SCSS configs can't be loaded separately.
Sign up to request clarification or add additional context in comments.

9 Comments

@OrangeDog: I tried the above approach in Angular 11 app and it is not working. Were you able to get it working in latest Angular 11 apps?
@suvenk no, 11 and 8 are different numbers
@OrangeDog: Ya I know. Do you know if there is any other way to achieve this in Angular 11 apps?
Did you build the correct configuration (for the above example it would be ng build -c special)? Works fine for me. Otherwise you may consider opening a separate question with some more details.
This "solution" (I guess you are refering to the workaround) doesn't replace anything. As said it doesn't use the Angular file replacement feature, this is the reason it works for SCSS files. It might be necessary to put some files outside the /default and /special folders. Another guess is, that you either screwed up the imports by creating the new folder structure or you still try to use Angualr file replacements feature, which in some Angular versions, doesn't care about the file name or extension. That said, it might need an extra question to really understand whats the problem here.
|
0

this is how I handle it...

                "configurations": {
                    "production": {
                        ...
                        "styles": [
                            {
                                "input": "src/theme/production-variables.scss",
                                "inject": true
                            },
                            {
                                "input": "src/production-global.scss",
                                "inject": true
                            }
                       ]
                        ...
                    },
                    "development": {
                        ...
                        "styles": [
                            {
                                "input": "src/theme/development-variables.scss",
                                "inject": true
                            },
                            {
                                "input": "src/development-global.scss",
                                "inject": true
                            }
                        ],
                        ...
                    },
                }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.