Error: Expected "styleUrls" to be an array of String

204 Views Asked by At

Getting this error when I am using dynamic styleUrls.

var dynamic = environment.booleanCondition ? '-new' : '';

@Component({
  selector: 'app-some-thing',
  templateUrl: './some-thing.component.html',
  styleUrls: [require(`./some-thing${dynamic}.component.scss`).default]
})

I am facing this issue with ng serve

Error: Expected "styleUrls" to be an array of String

After recompiles, error vanishes and application works fine but it throws different error on terminal.

error TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try npm i @types/node and then add node to the types field in your tsconfig.

But even after installing @types/node and adding node, it still don't resolves my previous issue of "styleUrls" to be an array of String. I have seen this issue posted many times before but none of fixes seems to work for me.

1

There are 1 best solutions below

4
Nehal On

Updated answer:

The OP updated the question that the variable from environment.ts file determines which scss file to use. In that case, there are few ways to pick up the file to use:

Option 1:

Copy targeted file to a main file via package.json command (independent of environment.ts)

Make the main scss file empty, so that desired css can be copied into it. In package.json, create script like following:

copy-old-scss: 'cp .src/{path-to-your-old-scss-file}/old-file.scss ./src/{path-to-main-scss-file}/something.component.scss'
copy-new-scss: 'cp .src/{path-to-your-new-scss-file}/old-file.scss ./src/{path-to-main-scss-file}/something.component.scss'

Execute these script before running your build command pipeline per env:

'dev':
   - step:
     script:
       - npm install --quiet
       - npm copy-old-scss
       - npm run build

'prod':
   - step:
     script:
       - npm install --quiet
       - npm copy-new-scss
       - npm run build

Option 2:

Use angular.json fileReplacements feature as outlined in this answer

angular.json:

    "production": {
              "optimization": true,
              ...
              ...
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                },
                {
                  "replace": "src/.../something.component.scss",
                  "with": "src/.../something-new.component.scss"
                }
              ],

Original answer:

Instead of doing such non-standard Angular thing, why don't you take a more conventional approach, where you control all of css from one file. If I had to the option, I would do it this way.

  1. Modify the flag to boolean, let useNewCss = booleanCondition;
  2. Combine both scss file into one, but within the file maintain specific section for old css and new css:

something.component.scss:

.old-css {
   // all css from my old file goes here
}

.new-css {
  // all css from my new file goes here 
}

  1. Use ngClass to wrap the whole html code within desired css class

something.component.html:

<div [ngClass]="{'old-css': !useNewCss, 'new-css': useNewCss }">
  <!-- All html code goes here -->
  ...
  ...
  ...
</div>