PatrickJS / PatrickJS-starter

MFE Starter

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

how to use sass files

gmchaturvedi1 opened this issue · comments

Kindly suggest how to use sass files for creating application

commented

Currently sass/scss support is not implemented in the project. But webpack makes it easy to do so.

Install sass-loader via npm and register the loader for *.scss files. Add the following somewhere in the module loaders, e.g. below this line:

    {
        test: /\.scss$/,
        exclude: /node_modules/,
        loader: 'style-loader!css-loader!sass-loader'
      },

The sass-loader transformes your scss files into valid css code, which are then consumed by the css-loader and style-loader. For more details see also: https://github.com/jtangelder/sass-loader

Still don't get it, @dotcs can you provide an example? I have a 'styles' folder under app. Something like this
app
|-styles
|--main.scss

After installing sass-loader and put above config code at webpack.config. I don't see main.scss gets mapped to css and be loaded in browser.

In webpack:

{
        test: /\.scss$/,
        exclude: /node_modules/,
        loader: 'raw-loader!sass-loader'
}

Then in your component:

@Component({
  styles: [ require('./filename.scss') ],
})

Angular2 expects a string in the styles array, because it modifies the string to encapsulate the styling. Using style-loader/css-loader loads the css and inject to the html, without encapsulating, and doesn't return a string, raw-loader just load the file as string and pass it to sass-loader, which also return a string.

What about global styles, ones not tied to components?

Using loaders: ["style", "css", "sass"] works but throws errors preventing the app to run.

Please use sass to raw and avoid style-loader unless you want global style support. There's another way to support global styles and still maintain the raw loader. By removing encapsulation in the top-level component and requiring the CSS that should be global.

If anyone else was a little confused to what @gdi2290 suggested:

import {ViewEncapsulation} from 'angular2/core';

@Component({
  selector: 'app',
  styles: [
    require('bootstrap.scss')
  ],
  encapsulation: ViewEncapsulation.None,
  template: ``
})
class App {}

Opened #199 to consolidate these issues.

@liampmccabe thanks for the heads-up. I was confused 😉

I created a scss wiki page if anyone wants to update it to be more clear
https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-include-SCSS-in-components

Tipe CMS

@gdi2290 - Is it possible to override bootstrap variables along with the implementation from your wiki?

@gdi2290 your wiki page works fine,

if you import in your sass file other css files you have the problem with the relative URLs in your CSS files. The avoid that do this

https://github.com/bholloway/resolve-url-loader#

in webpack.config.js do this

// SASS loader
{ test: /\.scss$/, 
  exclude: /node_modules/,  
  loaders: ['raw-loader', 'sass-loader', 'resolve-url']
}

@gdi2290
I don't like at all load my scss file in top level component by styles and encapsulation. Isn't there a possibility to load the compiled CSS file in the index.html file?

thx
Michael

@mburger81 you can import it as you normally would using the embedded stylesheets(see https://webpack.github.io/docs/stylesheets.html) then in your app.ts you would have

require("./app.scss");

@Component({
  selector: 'app',
  template:``
})

Tipe CMS

There are cases where you need global styles and also enjoy the benefits of encapsulated styles in components. I have adopted a policy of naming component sass files so they end with component.scss. Webpack can then choose the right loader chain like this:

{ test: /^(?!.*component).*\.scss$/, loaders: ['style', 'css', 'resolve-url', 'sass'] },
{ test: /\.component\.scss$/, loaders: ['raw', 'resolve-url', 'sass'] },

Of course, be sure to create a common or global entry point containing your global styles and load it in before your bundle containing angular so the css can be applied in the correct order.

@akeating Can you explain what you mean, in a different way? I don't quite understand what the benefit of having both of those loaders is. I would like to use global styles as well as encapsulated styles too. Also, can you give an example of your .scss file names to help clarify? Thanks.

Hey guys, my sass is working perfectly with my components, but I can't make it work with karma. what should I do?

@mburger81 that doesn't works, and 'resolve-url' should go before sass-loader, webpack loaders are loaded from right to left, so resolve-url fail with sass rules (however after change it to the correct way it doesn't work), the builded css leaves the url like the sass and file-loader (I use it) don't copy the assets.

I have sass working. I have a bootstrap.scss that I load as a global style, and then other styles for each component. The only issue now is that when I put variables in my component style sheets that I define in my global style they don't work.

Any ideas about how to get it all to work?

Thanks!

Scott

@scottmahr perhaps break your variables into a separate common file _variables.scss and import it as needed at the top of your component similarly to the way bootstrap does (obviously the path will be different):

// Core variables and mixins
@import "variables";
@import "mixins";

raw!sass pipe works fine for me but when I use UglifyJS plugin it breaks the styles...
I have opened a question on stack overflow, you can see more details there.

@akeating I've tried using your proposal for encapsulated styles in components

{ test: /\.component\.scss$/, loaders: ['raw', 'resolve-url', 'sass'] }

However, it's not resolving my url() paths. The final CSS simply has the same path as defined in the component's sass code.

Is there some additional config to go along with this?

@rjmarques check that your sass loader is configured to generate source maps (details https://github.com/bholloway/resolve-url-loader).

Changed it to

{ test: /\.component\.scss$/, loaders: ['raw', 'resolve-url', 'sass?sourceMap'] }

Still not working.

So far the only way I've been able to have the _url()_s working correctly was with

{ test: /\.component\.scss$/, loaders: ['exports-loader?module.exports.toString()', 'css', 'sass'] }

Sourced from here.

It's hard to say what your issue is exactly. I use resolve-url in conjunction with url-loader to setup my assets (file-loader would be fine too). The assets are emitted into the output directory or embedded right in the css file. Any urls are resolved relative to the output directory, which becomes your webroot. Obviously modify to suit your particular circumstances and build.
{ test: /.(png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/, loader: 'url-loader?limit=100000' }.

@rjmarques I reproduced this issue too. It looks like resolve-url-loader had problems with sass-loader#4.0.0, so upgrade to latest resolve-url-loader#1.6.0. This variation including resolve-url, worked as well:

{ test: /\.component\.scss$/, loaders: ['exports-loader?module.exports.toString()', 'css', 'resolve-url', 'sass?sourceMap'] }

Thanks for taking the time to follow up on this @akeating =)

Hopefully people will stumble upon this thread if they run into the same problems I, and others, did!

commented

I've implemented https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-include-SCSS-in-components already.

import { Component } from '@angular/core';
require('../../public/css/styles.scss');

@Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styles: [require('./app.component.scss')]
})
export class AppComponent { }

The app.component.scss is parsed correctly but styles.scss is still failed to load. If I change styles.scss to styles.css(surely, also change the style file name accordingly). Everything works fine. But it just rejected to load styles.scss

What about:

import { Component } from '@angular/core';
import '../../public/scss/styles.scss';

 @Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styles: [require('./app.component.scss')]
 })

 export class AppComponent { }

This is how I made mine work: https://github.com/rjmarques/angular2-typescript-recipe

commented

@rjmarques I copied your webpack settings, it solves my issue. Thank you. The key is the following

{
        test: /\.scss$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap!resolve-url!sass?sourceMap')
      },
      { 
        test: /\.scss$/,
        include: helpers.root('src', 'app'),
        loaders: ['exports-loader?module.exports.toString()', 'css', 'sass']
}

Thanks a lot for your help.

@rjmarques I use your method

{ test: /\.scss$/, exclude: /node_modules/, loaders: ['exports-loader?module.exports.toString()', 'css', 'sass?sourceMap'] }

It work well but file are renamed and put at the root of the dist folder:

Exemple
//file name src/app/HomePage/HomePageComponent.scss div { background-image: url('./images/header.png'); }
Will take the './images/header.png' and copy it to 'dist/1dba29a2fdaef4bf64aaa025742982d7.png'.

I was wondering if there is way to configure this so the file are copied to something like:

dist/app-assets/HomePage/images/header.png

I am sure there is a way but I am fairly new to all this (all the frontend tools, I am a PHP/Symfony backend developer).

Thanks !

p.s. Best thing would be to have the md5 file value in the name file caching (cdn) would not need to be purge

dist/app-assets/HomePage/images/header.{md5FileValue}.png

@mpoiriert

When defining your webpack loaders:

{
    test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
    loader: 'file?name=app-assets/[path][name].[hash].[ext]'
}

Note this will copy the full path of the image. So you'll have:

dist/app-assets/src/app/HomePage/images/header.hash12345.png

If you don't want the hash remove the [hash] param.

For more info, have a look at: https://www.npmjs.com/package/file-loader

Hope this helps!

I have an issue when I use sass files and use the @extend to extend a class from a library (materialize-css). I extend the classes of the libraries in many components and because of the raw-loader it gets copied to each and every component in the bundle. It blows my bundle file from 1MB to 5MB just when I use the styles. I don't want to use the classes of the external library on my html and would like to use the @extend syntax. I opened a question on stack overflow as well: angular2 webpack large bundle size with sass

Do i miss something? can anyone help ?

@MFateen - did you fix the issue with running karma? I have the same issue - would appreciate any help or pointers

@kingsleyh in a matter of fact yes, I only needed to add to my module: { preLoaders: [ in webpack.test.js

{
    test: /\.scss$/,
    exclude: /node_modules/,
    loaders: ['raw-loader', 'sass-loader']
  }

hmm still not working for me - anyone know what this issue might be?

23 08 2016 16:38:12.947:INFO [karma]: Karma v1.2.0 server started at http://localhost:9876/
23 08 2016 16:38:12.951:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
23 08 2016 16:38:13.084:INFO [launcher]: Starting browser PhantomJS
23 08 2016 16:38:14.511:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#ncsROZnaHSN1IIn3AAAA with id 83441766
23 08 2016 16:38:15.172:WARN [web-server]: 404: /assets/scss/styles.scss
PhantomJS 2.1.1 (Mac OS X 0.0.0) AppComponent should have a title FAILED
        Failed: Uncaught (in promise): Failed to load assets/scss/styles.scss
        invoke@spec-bundle.js:6807:35
        run@spec-bundle.js:6700:51
        spec-bundle.js:7055:62
        invokeTask@spec-bundle.js:6840:44
        runTask@spec-bundle.js:6740:59
        drainMicroTaskQueue@spec-bundle.js:6958:44
        run@spec-bundle.js:4087:30
        spec-bundle.js:4100:32
        flush@spec-bundle.js:4455:12
        TypeError: undefined is not an object (evaluating 'fixture.componentInstance') in spec-bundle.js (line 58282)
        spec-bundle.js:58282:30
        spec-bundle.js:22544:29
        invoke@spec-bundle.js:6807:35
        run@spec-bundle.js:6700:51
        spec-bundle.js:7055:62
        invokeTask@spec-bundle.js:6840:44
        runTask@spec-bundle.js:6740:59
        drainMicroTaskQueue@spec-bundle.js:6958:44
        run@spec-bundle.js:4087:30
        spec-bundle.js:4100:32
        flush@spec-bundle.js:4455:12
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.103 secs / 0.128 secs)

its like its missing some of the test dependencies - this is my test:

import {
  describe,
  it,
  expect,
  inject,
  injectAsync,
  beforeEach,
  TestComponentBuilder,
  ComponentFixture
} from 'angular2/testing';

import { AppComponent } from './app';

describe('AppComponent', () => {
  let fixture: ComponentFixture;

  beforeEach(injectAsync([TestComponentBuilder], tcb => {
    return tcb.createAsync(AppComponent)
      .then(f => fixture = f);
  }));

  it('should have a title', () => {
    // given a component instance
    let appCmp = fixture.componentInstance;

    // when we trigger the change detection
    fixture.detectChanges();

    // then we should have a name
    let element = fixture.nativeElement;
    expect(element.querySelector('h1')).toHaveText('Team Chemistry');
  });
});

if I comment out fixture.componentInstance - it errors on the fixture.detectChanges() and if I comment that out to - it errors on fixture.nativeElement

@kingsleyh check the angular2 version you are using because in the latest releases you don't write these imports anymore

@kingsleyh you're on RC-5 right? I had to change a few things when migrating from RC-4.

Have a look at:

I'm using: "angular2": "^2.0.0-beta.17" - not sure how old that is.

I think the problem is that the scss is not being found when running the test with Karma. I'm not sure if the scss files need to be somehow moved into place.

The tests pass if I comment out the styleUrls:

import { Component, ViewEncapsulation } from 'angular2/core';

@Component({
    selector: 'app',
    styleUrls: ['./assets/scss/styles.scss'],
    encapsulation: ViewEncapsulation.None,
    template: require('./app.html'),
})

export class AppComponent {
}

I'm my main webpack.conf.js I copy the assets into place:

plugins: [
    // Copy static assets to the build folder
    new CopyWebpackPlugin([{from: 'src/assets', to: 'assets'}]),
    // Generate the index.html
    new HtmlWebpackPlugin({template: 'src/index.html'})
]

I tried putting that in to the webpack.test.config.js but doesnt seem to help

@rjmarques thanks - the 2.0.0-beta.17 seems to be the latest available npm package for angualr2 - so I guess i'm on the bleeding edge. It doesn't seem to have any of the TestBed support you have in your version.

@kingsleyh the 2.0.0-rc.5 (2016-08-09) is the latest available.
please see https://github.com/angular/angular/blob/master/CHANGELOG.md

@kingsleyh

https://github.com/angular/angular/blob/master/CHANGELOG.md

Isn't 2.0.0-beta.17 from back in April?

Here's my package.json

What specific package are we talking about?

hmm - I'm a bit lost :( - I think I must have done npm install angular2 - which has given me the latest available npm package of angular2 - which is the beta.17 - which is from back in April. why has your package.json got so many different parts of angular some at rc4 and some at rc5 - isn't there a single npm for the rc versions? - and should I just copy your dependencies to get mine working?

Maybe follow the Tour Of Heroes?

On Tue, Aug 23, 2016, 13:31 Kingsley Hendrickse notifications@github.com
wrote:

hmm - I'm a bit lost :( - I think I must have done npm install angular2 -
which has given me the latest available npm package of angular2 - which is
the beta.17 - which is from back in April. why has your package.json got so
many different parts of angular some at rc4 and some at rc5 - isn't there a
single npm for the rc versions? - and should I just copy your dependencies
to get mine working?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#136 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABeg9FLlLBdQLBVtb-p_ZqiAeICRxVuvks5qiyBHgaJpZM4GsPDM
.

hmm - so far I'm completely underwhelmed with Angular2 - it's so hard to get going and confusing with so much change going on. I think I might go back to Angular1 or React and come back to Angular2 next year when it's more stable

@kingsleyh I can pair with you this Saturday to update your project to the latest version so you're not discouraged about Angular2

@rjmarques thanks for the link
@gdi2290 - the main issue I'm struggling with is the testing. Thanks for the offer - If you don't mind that would be awesome.

commented

Thanks to @akeating and @gdi2290 for all the advice above. Works great.

Has anyone been able to get scss files loaded this way through styleUrls to work with HMR so only the CSS gets reloaded? (In my testing this works with scss files included at a global scope, but not with ones included with components)

Hey, I am on the initial release version with the following returned from ng -v
angular-cli: 1.0.0-beta.14 node: 6.6.0 os: darwin x64
I am creating my project with
ng new projectname
The only webpack.config.js files I am seeing are under ./node-modules/... I am a little slow to touch those files. Should I be seeing a copy of this file somewhere else? Do i need to create it? Any help appreciated.

@nbunney: with:

  • angular-cli: 1.0.0-beta.14
  • node: 4.5.0
  • os: darwin x64

it just works out of the box:

./semiAutomatic.component.ts

..
@Component({
    selector: "semi-automatic-overview",
    styleUrls: ["./semiAutomaticOverview.scss"],
    templateUrl: "./semiAutomaticOverview.view.html"
})
export class SemiAutomaticOverviewComponent
..

./semiAutomaticOverview.scss

.semiAutomaticOverview {
    color: green;
    .dropdown-menu {
        background-color: green;
        color: yellow;
    }
}

scss styling ends up being written to main.bundle.js as a string of css :-)

Has any one used scss with ngc? All the lines of @import in component.scss report "Resource not found" error. Any suggestion or work around to make scss work with ngc?

Nice! Thanks. Absolutely loving Angular2 so far.

@teeSee I think all you need for .scss (instead of .sass) is

1st rename styles.sass to styles.scss

Update angular-cli.json

  "styles": [
    "styles.scss"
  ],
  "defaults": {
    "styleExt": "scss",
    "prefixInterfaces": false
  }

I am not able to use variables in my scss file. I have done all configurations as mentioned at: https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-include-SCSS-in-components. Please see my issue here: #1152 TIA

@VishalGulati it will be easier to narrow down the problem if you post the error you're getting

I didn't exactly follow the same config as you posted. However I'm able to use variables: https://github.com/rjmarques/angular2-typescript-recipe/blob/master/public/scss/globals.scss

commented

hi @rjmarques. I'm wondering if i can use sass variables in an agular 2 component. something like:

@Component({

  selector: 'my-component',

  template: `
    <div>
      <div class="test-div">test div 1</div>
    </div>
  `,

  styles: [
    `
    @import "variables";

    .test-div{
      border: 1px solid $test-color;
    }
  `]

})

my file _variables.scss:

$test-color: green !default;

it seems whatever I try the sass variables arent recognised.
Any help much appreciated.

Hey @tim-csaky-qhr =)

The sass used in my simple nav component uses a variable: $sideSpace

The variable is defined in the global's file.

At first glance your example looks fine. I'm not using inline component styling, however. I have files for everything.

What error(s) are you getting? Is your webpack sass loader definition the same/similar to mine?

commented

hi there @rjmarques and @tinchou
Ahhh I see now!
thanks for your help.
that sounds like a good set-up.

i need to link to the variables from a sass file. so use the styleUrl[].

@Component({

  selector: 'my-component',

  template: `
    <div>
      <div class="test-div">test div 1</div>
    </div>
  `,
  styleUrls: ['local_sass_file.scss'],

})

local_sass_file.scss contains:

// variables:
@import "../../assets/css/variables";

my file global _variables.scss contains:
$test-color: green !default;

now if i can understand the rest of angular2 i'll be all set!

@kingsleyh , @gdi2290 have you be able fix the issue? I have exact issue with the test like you. Thanks

I'm not sure if it's possible, but I wonder if anyone success combined SASS SourceMaps and Angular 2 ViewEncapsulation together

I followed the exact steps outlined in the Wiki entry (https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-include-SCSS-in-components) and I just get an error like the compiler is trying to reading comments like they're CSS:

ERROR in ./src/styles/styles.scss
Module build failed:
/* this file will be extracted to main dist folder and is imported in index.html */
^
      Invalid CSS after "...load the styles": expected 1 selector or at-rule, was "var content = requi"
      in /Users/stephen/repos/chanel-elevator-web/src/ipad/src/styles/styles.scss (line 1, column 1)
 @ ./src/app/app.module.ts 16:0-31
 @ ./src/app/index.ts
 @ ./src/main.browser.ts
 @ multi (webpack)-dev-server/client?http://localhost:3000 ./src/main.browser.ts

I'm trying to apply this globally, so my app.component.ts looks like this: (extract)

@Component({
  selector: 'app',
  encapsulation: ViewEncapsulation.None,
  styleUrls: [
    '../styles/styles.scss'
  ],

Am I doing something wrong?

Ah, I think I resolved it. The starter project includes an additional rule (in webpack.common.js) for scss files:
```
/*
* to string and sass loader support for *.scss files (from Angular components)
* Returns compiled css content as string
*
*/
{
test: /.scss$/,
use: ['to-string-loader', 'css-loader', 'sass-loader'],
exclude: [helpers.root('src', 'styles')]
},

Removing this rule made it work again. Perhaps the Wiki should include mention of this?

Someone needs to update the wiki entry again since it's no longer working with the current version