angular-cli: Stylesheet from (npm) linked package not loaded correctly

OS

Tested on both Windows 7 and Linux (Fedora 24)

Version

$ ng --version
angular-cli: 1.0.0-beta.22-1
node: 4.6.1
os: linux x64

The app was created using CLI.

Repro steps

  1. Install a package containing a stylesheet (say bootstrap-sass, actually any package will do) globally via npm.
  2. git clone https://github.com/twbs/bootstrap-sass.git into a working directory, cd to that working directory and perform npm link command.
  3. ng new project in another separate directory, cd to the newly create project directory and perform npm link bootstrap-sass. This will create a bootstrap-sass symlink in node_modules pointing to the local git repository.
  4. Modify angular-cli.json to reference the stylesheet in the linked package.
      "styles": [
        "../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss",
        "styles.scss"
      ],
  1. ng serve and observe that styles from bootstrap is not exported correctly in the index page.
  2. ng build and observe that the generated styles.bundle.js does not do “exports.push()”.

The log given by the failure

There was no error log, webpack declared the “bundle is now valid”.

Mention any other details that might be useful

Using normal npm install approach does not have this issue. i.e. after npm unlink bootstrap-sass && npm install bootstrap-sass then all is fine.

Use case: I have a forked gentelella repository locally to fix some of the issues I found, so I cannot just simply npm install it in my project. Using npm link approach as I outlined above should work. It seems angular-cli (or webpack, I am not sure) is being confused by symlink. As a temporary workaround, I replace the stylesheet reference in the angular-cli.json with an absolute path to the stylesheet file in the local git repo.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 11
  • Comments: 27 (12 by maintainers)

Commits related to this issue

Most upvoted comments

@filipesilva As mentioned in this comment the fix only appears to apply to SCSS/CSS/JS, but not to static assets like font files (used by font-awesome, material-design-icons, etc).

Should we open a separate issue for that?

Using @import "../node_modules/gentelella/src/scss/custom"; in the styles.scss as the workaround now. The sass preprocessor handles the symlink well.

I think I’ve also run into something related to this: in the “styles” section of angular.json, if I include a CSS file that is actually a symlink, angular builds the project OK and includes that symlinked CSS file, but if I make a change in the targeted CSS file, angular does not pick up the change and reload the new style.

Steps:

  • Create a new angular project, ng new
  • Take a CSS file that I’d like to share between angular projects, say “mystyle.scss”.
  • I keep the file in a shared location and then symlink it within each angular project and then point to the symlinked version in angular.json.
  • Angular correctly builds & serves the app using “ng serve” (good!)
  • Make a change to mystyle.scss
  • Angular does not reload styles after this change or any subsequent change.
  • If I replace the symlinked version with the actual file, angular notices changes in that file and reloads the styles appropriately.
  • I also have “preserveSymlinks”=true in angular.json and tsconfig.json.

I hit what I thought was a similar issue and used the shell script below to build and example environment to work in.

#!/bin/bash
#
# ngcli_bug3500.sh
#
# This creates an ng project and add a unit test to which fails
# if @angular/cli issue 3500 is unfixed 
#
#
# (C) Roger Gammans <rgammans@gammascience.co.uk>
# This file can be freely redistributed.

## Comment this out to use an already in scope @Angular/cli installation
npm i @angular/cli

npx ng new cli3500 --defaults
cd cli3500
mkdir foo
cat > foo/test.css <<EOF

.nothere {
    display: none;
}

EOF
ln -s foo bar
mv src/app/app.component.spec.ts src/app/app.component.spec.ts.orig
head -n -1 src/app/app.component.spec.ts.orig > src/app/app.component.spec.ts
cat >> src/app/app.component.spec.ts  << EOF

  it('should render check element invisibly', () => {
    /* This checks the access to the new css ; which should hide it
     */
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('div.nothere').offsetHeight).toBe(0);
  });
});

EOF

cat >> src/app/app.component.html << EOF
<div class="nothere">Some texts this is any.</div>
EOF

## Add './bar/test.css' to angular json
#  first write out a node script to
#  do the change then execute it.
cat > mod_ng_json.js <<EOF
'use strict';

function do_append(ary, value) {
    ary[ary.length] = value
}

const fs = require('fs');

// Read in angular.json
let rawdata = fs.readFileSync('angular.json.bak');
let cli_conf= JSON.parse(rawdata);

// Change it and write it out
do_append(cli_conf["projects"]["cli3500"]["architect"]["build"]["options"]["styles"],"./bar/test.css")
do_append(cli_conf["projects"]["cli3500"]["architect"]["test"]["options"]["styles"],"./bar/test.css")

fs.writeFileSync('angular.json',JSON.stringify(cli_conf,null,2));

EOF
mv angular.json angular.json.bak
nodejs mod_ng_json.js

#Run the app tests (one should fail if this bug is not fixed)
npx ng test

Using the created app I tracked the fact the the stylesheets where being loaded by webpack, but by their canonical absolute path.

This (eventually) lead me to looking at webpack bugs and I found this , https://github.com/webpack/webpack/issues/8824 , which then lead me to the webpack resolveSymlink option.

With a bit more digging I can make the test project I generated pass the tests by changing the options for the test command in angular.json (and other commands will need it as well) to add

        "test": {
          "options": {
            "preserveSymlinks": true,
           ...
         }
  }

It appears there might be some downside of symlink paths not being watched correctly with this option, and the webpack bug does suggest the issue could also be fixed by adding an extra reference to absolute canonical path to the webpack loader spec as well as the path ‘through’ the symlink.

Hope this help…

+1 same here

Now that https://github.com/angular/angular-cli/issues/3401 is done, it should be feasible to do something like what was originally requested:

"styles": [
  { "input": "../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss", "output": "bootstrap.css" },
  "styles.scss"
],

Can you see if this solves it?