Correct way to use Font Awesome SCSS in a Yeoman's Angular project - gruntjs

I created an Angular project using Yeoman's generator, and now I am trying to add the Font Awesome to the project. I installed it using Bower using
bower install fontawesome --save
then it automatically added to my app/index.html the following code:
<!-- build:css(.) styles/vendor.css -->
<!-- bower:css -->
<link rel="stylesheet" href="bower_components/fontawesome/css/font-awesome.css" />
<!-- endbower -->
<!-- endbuild -->
But I didn't want to use it as CSS, but as a SCSS import (to be able to change the URL of font files). So I deleted the above code from the HTML page and added the proper code into app/styles/main.scss:
$icon-font-path: "../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/";
$fa-font-path: "../bower_components/fontawesome/fonts/"; // <==== here
// bower:scss
#import "bootstrap-sass-official/assets/stylesheets/_bootstrap.scss";
#import "fontawesome/scss/font-awesome.scss"; // <==== and here
// endbower
Then I run grunt build, but something (Grunt?) edited my files back to the original ones. The index.html got the <link> again and mine main.scss was kept only with the Bootstrap import.
Ok, we are almost there.
So I looked at the Bootstrap's bower.json and compared to the Font Awesome's bower.json and I saw the following difference:
// Bootstrap
"main": [
"assets/stylesheets/_bootstrap.scss", // it's SCSS
...
],
// Font Awesome
"main": [
"./css/font-awesome.css", // it's CSS
...
],
Then I found a way to properly (not sure) override the Font Awesome's bower configuration using my app's bower.json, and added the following code into it
"overrides": {
"fontawesome": {
"main": [
"./scss/font-awesome.scss", // now it's SCSS
"./fonts/*"
]
}
}
Question: Is this the correct way to use Font Awesome as a SCSS import and avoid Grunt of changing my files when building the project? By overriding its default "main" property?

Judging by your question I think you may be new to the web frontend build process. Unfortunately it can be a headache at times.
First off, note that SCSS != CSS and browsers do not know how to use SCSS. Including <link rel="stylesheet" href="main.scss"> in your HTML <head> tag will not work. We can enjoy the various perks of SCSS (e.g. variables, imports, etc.) during development, but to use these styles in the browser we must transpile SCSS into CSS (which the browser recognises).
To make developer's lives easier, it is common for seed projects (such as the one you are using) to include some kind of automated build process which includes transpiling SCSS into CSS. The build process is typically executed via a task runner, such as Grunt or Gulp. These seed projects/templates also typically include a task to inject your project's dependencies (as declared in your bower.json file) into your index.html automatically. A tool called wiredep is used to read through your bower.json files to determine these dependencies, in particularly, it will look for the 'main' attribute to determine which files a particular package requires. It will then inject the appropriate <script/> and <link> tags.
To explain this further, when you execute bower -install font-aweseome --save a few things happen:
The package is downloaded and added to your project (usually to bower_components/).
An entry is added to your bower.json file adding the package to your project's dependencies.
Each package includes its own bower.json file which describes its various properties, the most important of which (after name) is main. You can see the font-awesome bower.json file here. As you can see, it's main attribute references several files. These are the files that wiredep uses to determine which <script/> and <link> tags to inject into your index.html.
By specifying an override in your project's bower.json like this:
"overrides": {
"fontawesome": {
"main": [
"./scss/font-awesome.scss", // now it's SCSS
"./fonts/*"
]
}
}
You are specifying to wiredep that ./scss/font-awesome.scss and ./fonts/* are the files required by your project, and to ignore those listed in the font-awesome bower.json file.
Regarding SCSS: take a look at the Sass guide, in particular the section on imports. The Sass #import lets you split your styles across several smaller SCSS files (partials) that, upon transpilation, are combined and included into a single (optionally minified) CSS file. This includes any third party SCSS files that you import into your main.scss. For example, if you imported font-awesome.scss into your main.scss file, then transpiled it into CSS, the resulting CSS file would include all styles contained within font-awesome.scss.
To include and customize a third party SCSS file, what I do is:
Specify an import in my own custom main.scss file.
Make any customizations to variables I want.
Transpile main.scss into CSS.
Include a <link> tag to the transpiled CSS file in my index.html file.

Related

Adding CSS to webpack build

I have a fairly simple webpack project - built using the Webpack guide. See https://github.com/timburgess/webpack-postcss-tailwind
There is a style.css in the src directory but there is no .css being added to the /dist directory on build.
Reading further, any css should be added as an inline style and that's not occuring.
Resolved with https://github.com/webpack-contrib/mini-css-extract-plugin per Richards answer.
Webpack will bundle the css files referenced via import statements in your source javascript files into the output javascript file (bundle.js). You'll see the classes being applied to the webapp at runtime via inline <style> tags applied dynamically to the html.
Many developers do not think this behaviour appropriate and will use a special plugin to get webpack to produce seperate bundled .css files that you then reference in your html using the traditional (and caching friendly) <link rel="stylesheet" type="text/css" href="bundle.css"> tag. See:
https://github.com/webpack-contrib/mini-css-extract-plugin

Bundle sass files into single sass file

TL;DR: My question is how to bundle some of my sass files into single sass file?
I've been developing an Angular component library and I package it with ng-packagr. Let's call it #my-lib/ngx-components.
Consumers of my lib will import my components like #my-lib/ngx-components/navbar.
I decided to add theming support to components.
For example, I have a navbar component with default colors (background, text, hover etc.) I want consumers of my library to be able to override these colors with their own theme. That's why I've written a mixin which takes a $theme input and override some css rules as follows (this is a basic version of what I have)
_navbar-theme.sass
#mixin navbar-theme($theme)
$primary-color: map-get($theme, primary-color)
$secondary-color: map-get($theme, secondary-color)
$color: map-get($theme, color)
.navbar
background-color: $primary-color
color: $color
&:hover
background-color: $secondary-color
Each component has its own *-theme.sass file.
I also have global _theming.sass file which imports all of these as follows
_theming.sass
#import './components/navbar/navbar-theme'
#import './components/button/button-theme'
#import './components/dropdown/dropdown-theme'
I want to export this _theming.sass file from my lib, so people can import this file in their own sass file as #import '~#my-lib/ngx-components/theming' and start using all of the mixins available.
If they want to have custom navbar, button etc, they should be able to use those mixins with single import.
I tried to make it look like angular-material theming setup.
At first, I have tried node-sass which is already in my dependencies. But, it tries to build sass into css so it omits mixins in the output file.
Then, I looked at what angular-material has done. They use scss-bundle
I thought "this is exactly what I want." However, it requires scss files, not sass files. It cannot read sass files.
Then, I thought "Okay, I can give up on sass and start using scss. How do I convert all those files to scss without going through them by hand". Then, I found sass-convert. In this question it was said that I can use it within command line. However, when I install sass-convert with npm globally, it didn't give me a command line executable. I think I need Gulp to use it.
I've been avoding to use Gulp from the beginning, because it means another tool to learn and it adds complexity to codebase.
At this point, I feel like "Hal fixing light bulb"
TL;DR: My question is how to bundle some of my sass files into single sass file?
Also, If you can come up with a solution that requires webpack, that's fine too.
Let's through your opinion or questions:
I want to export this _theming.sass file from my lib, so people can
import this file in their own sass file as #import
'~#my-lib/ngx-components/theming' and start using all of the mixins
available. If they want to have custom navbar, button etc, they should
be able to use those mixins with single import.
You need to know, what is your target audience. Mostly people using angular cli for create their app like template scratch.
So you need provide css bundle (people just want import your css) and sass bundle (who want to use your object or your mixin).
I want to export this _theming.sass file from my lib, so people can
import this file in their own sass file as #import
'~#my-lib/ngx-components/theming' and start using all of the mixins
available. If they want to have custom navbar, button etc, they should
be able to use those mixins with single import.
I tried to make it look like angular-material theming setup.
Firstly, you need to know that #angular/material doesn't export sass (they use scss) but they export css thene compiled by scss-bundle (as you mention it) see their code and documentation theme.
I thought "this is exactly what I want." However, it requires scss
files, not sass files. It cannot read sass files.
I would like quote this answer:
Sass is a CSS pre-processor with syntax advancements. Style sheets in
the advanced syntax are processed by the program, and turned into
regular CSS style sheets. However, they do not extend the CSS standard
itself.
It is better you need transfer your code from sass to scss (by yourself), it would not much to do it (I think, I always write scss instead sass file).
Solution:
1. Provide css and sass (scss better)
When you deliver your component libs, You have to provide css and scss. Beacuse angular cli doesn't provide scss loader by default.
Don't use sass file, use scss file see my refer answer on top.
scss-bundle + webpack
Since you have to provide css, you can you webpack shell plugin to bundle scss. Scss have provide cli, if you want to use cli.
2. Structure your scss
Okay, let's take sample from bootstrap#4 module for this case. Bootstrap use structure like this (Documents):
scss
|-- _variables.scss
|-- _mixins.scss
|-- _functions.scss
|-- ...
|-- index.scss
inside index.scss will have like this:
#import 'variables'
#import 'mixins'
#import 'functions'
...
so, this scss you have to deliver beside css. Like bootstrap do, then mixin will available to consumer. Also this good approach when consumer to find scss file in scss folder (easy to pointing which is scss put in).
UPDATE
For bundle to single file you have to create task runner to do it. In your case you want to use webpack, you can create a plugin to do it.
Here example plugin:
scss-bundle-plugin.js
call to you config webpack:
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new SCSSBundlePlugin({
file: path.join(__dirname, 'src/index.scss')
})
],
To try playground, checkout hello-world-loader then:
# install dependency
npm install
# try play ground
npm run webpack
it will create file _theme.scss at ./dist.
My advice don't use webpack, use task runner instead (gulp or grunt) for this simple case. Webpack too advance and hard to write task.
There is also a widely used package, called scss-bundle.
It is quite simple to use, you just create a config file with all relevant configuration and then run scss-bundle.
This for example will use all scss files, imported in entry.scss and move it to out.scss. All imports will be resolved, except for angular themes in this example, like #import '~#angular/material/theming';.
scss-bundle.config.json:
{
"bundlerOptions": {
"entryFile": "my-project/src/entry.scss",
"outFile": "dist/out.scss",
"rootDir": "my-project/src",
"project": "../../",
"ignoreImports": [
"~#angular/.*"
],
"logLevel": "debug"
}
}
My solution for scss / sass files
I've used small module bundle-scss
It bundles files by file name mask. So you need to pass correct mask like ./src/**/*.theme.scss specify destination file and maybe your custom sort-order
You don't have to create one entry point file with all imports. bundle-scss will get all files by mask analyze all imports and include this files as well

Angular - including CSS file in index.html

I'm trying to use the angular2-busy library in an angular project created with the CLI, but am having an issue importing the stylesheet:
<link rel="stylesheet" href="/node_modules/angular2-busy/build/style/busy.css">
The browser is telling me that it cannot find the file, even with the correct path. I also checked that the file exists, and it does. When I take out the rel="stylesheet" I don't get the error, but then the animations don't work.
Here is the package I am trying to use, if anyone is curious:
https://www.npmjs.com/package/angular2-busy
Angular CLI have it's own way to initialize your global css/js.
They are located in .angular-cli.json configuration
Locate "styles": and add your css there
Example :
"styles": [
"../node_modules/angular2-busy/build/style/busy.css",
"styles.css"
],
Hope that helps.
Basically there are three different ways to do that :-
By adding it to the "styles" array in angular-cli.json file as is shown by #penleychan in his answer.
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
]
You can directly import the css file into styles.css file (or any other css file) that is included in "styles" array in angular-cli.json file by adding the #import statement at the top of that file.
#import "~bootstrap/dist/css/bootstrap.min.css";
Include the css file in index.html page by adding a link element.
<link rel="stylesheet" type="text/css"
href="node_modules/bootstrap/dist/css/bootstrap.min.css"
/>
You can find a more elaborated explanation and a few more alternatives at this link
How to Use Angular with Linked Cascading Style Sheets (CSS)
Always use LINKED CSSS rather than the compiled and embedded JavaScript memory version of CSS Google Angular uses. Why? Linked <link> external CSS is superior in every way to embedded CSS, mainly because linked CSS is cached across thousands of page views, visits, and users online, saving you huge bandwidth values with increased CSS rendering speed in the browser, while implementing simpler, faster CSS management, overall.
HOW TO FIX ANGULAR FOR LINKED CSS
In angular.json delete all the references to CSS files under "styles". It should look like this now:
"styles": [],
Move your CSS files to the"src" folder inside your project, then add links <link> to your external CSS files inside index.html. Add in your link paths to your CSS file starting at the "src" folder and including the "styles" folder or any folder system you desire (see below). You can store your css wherever you want in your project now as long as those folders of files are under your "src" root folder. My physical CSS files in my project for the path below now sit under "src/styles". So the link path should just be my "styles" folder plus the file name:
<link href="styles/mystyles.css" rel="stylesheet" />
Any CSS files for bootstrap, font-awesome, etc. that you want in your project have to be manually copied from your "node_modules" folder in your project into a folder under your "src" folder, just like in the location used for the CSS file above in #2. Or, you can reference them from some fully qualified url online. If you want to create a link to them as above in "index.html", or import them into the html file directly (example below), that will also work. If you were importing them before from the "node_modules" folder that will not work as the Angular CLI or webpack resolved those paths by compiling your CSS imports into JavaScript. After you move those CSS files and link or import them from the src folder, they will not be compiled into Angular JavaScript now. When using #import, be sure to drop your bootstrap and font-awesome CSS files in the same "src/styles" folder as your main style sheet and import them into that stylesheet like this:
<style type="text/css">
#import "bootstrap.min.css";
#import "font-awesome.min.css";
</style>
In the same angular.json file above, under the "assets" JSON setting, add a reference to the location of your CSS files in #2 and #3 so the builder can copy them into your dist folder. Any CSS files linked or imported from that folder will get moved by the "dist" folder system when Angular is compiled. Note the new styles path at the bottom. If you have CSS in other folders you can add them here as well. This tells the builder to create the CSS directories in the "dist" folder Angular uses and copy all the CSS files inside them, so when you build for production your index.html links point to the right CSS files on the server:
"assets": [
"src/favicon.ico",
"src/assets",
"src/api",
"src/styles"
],
You now have a powerful set of link elements to all your CSS in the head of your index.html file and can edit them in the Angular project like you normally do, knowing they will work in both the Angular development test server and in your dist production copy. Your website will also benefit from browser caching of CSS one time in memory and permanent file caches.
It took me a day to dig through documentation and testing to figure out what should have been a natural part of any simple website API with linked CSS. I'm sorry Google Angular made this so convoluted. But this change works great!
This simply removes your CSS from the compile and build angular system that pushes all your CSS into a JavaScript file, which simply embedded your CSS into an inline style sheet block in the memory of your browser and head of your HTML page. Using your own linked CSS html tags is far superior and allows better caching and control of CSS cascade rules.
Good Luck!
Try
<link rel="stylesheet" href="node_modules/angular2-busy/build/style/busy.css" >
You are missing the self closing / at the end of your code. It's possible the browser is not fixing this for you.
<link rel="stylesheet" href="/node_modules/angular2-busy/build/style/busy.css" />
Also removing rel="stylesheet" would definitely not fix the problem since the browser needs to know exactly what kind reference you are referring to.
If fixing the closing tag does not work then your path is wrong. You can also try adding a ../ to the beginning of your path. This will make it relative to the folder the site is in.
<link rel="stylesheet" href="../node_modules/angular2-busy/build/style/busy.css" />

Compile css and sass files to single css file using gruntjs

I have a bootstrap.css file which I want to compile with my custom styles from style.sass into single output file, for example - style.css.
For sass compilation I use gruntjs with grunt-contrib-sass extension. My Gruntfile.js config for sass looks like this:
sass: {
dist: {
options: {
//style: 'compressed',
style: 'expanded',
lineNumbers: true
},
files: {
'build/styles/style.css': 'src/styles/style.sass'
}
}
}
I've tried to import bootstrap.css into sass file, but instead it only generates next code in output css (which is correct behavior http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import):
#import url(bootstrap.css);
.....
/*my style.sass rules*/
I even tried to list multiple files in order of concatination and processing, like in uglifier settings:
files: {
'build/styles/style.css': ['src/styles/bootstrap.css', 'src/styles/style.sass']
}
But this only adds bootstrap.css into final style.css file ignoring style.sass existence.
As I'm new in gruntjs, I can't figure out how this should be done properly.
The Grunt configuration is correct. The reason your file is not being imported is because of the way SASS is designed to work.
The SASS documentation states:
By default, it looks for a Sass file to import directly, but there are a few circumstances under which it will compile to a CSS #import rule:
If the file’s extension is .css.
If the filename begins with http://.
If the filename is a url().
If the #import has any media queries.
Since the file you are importing has a .css extension it will therefore not be imported directly but remain a standard CSS #import.
You have three options to resolve this:
Rename the included file to _bootstrap.scss. (If you don't add the underscore a bootstrap.css will be created along with your main output file which is unnecessary.)
Include the Bootstrap SCSS source as a dependency of your project and build against that. Install the Bootstrap source using Bower by typing $ bower install bootstrap-sass-official in your project root folder. (For instructions on setting up Bower see the Bower website.) Then you can replace your import above with #import 'bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap';.
Use a concatenation library such as grunt-contrib-concat to combine Bootstrap.css and your main style sheet during your build process.
This first option is fine if you downloaded the bootstrap CSS file into your project manually, however, if you are including it as a dependency with npm/bower it is not ideal.
I would recommend the second option since building Bootstrap from source will not only solve your problem but allow for customization of Bootstrap variables to fit your theme rather than overwriting them with subsequent style rules as well. The only downside is that your build process might be slightly longer due to the rather large SASS build of the Bootstrap source.

How can I customise Bootstrap without losing the changes?

I'm using Bower to manage Bootstrap and would like to make some changes (colours, font size etc) to the default Bootstrap look and feel. Here's my workflow:
Edit bower_components/bootstrap/less/variables.less
Recompile bootstrap using grunt build
The problem is that I want to be able to upgrade bootstrap when a new version comes out and presumably I'll lose my changes to variables.less.
Is there a way I can keep my changes outside of bower_components and also avoid having bower_components in source control since it's 122MB?
you can create a variables-custom.less and import it into theme.less like this:
//
// Load core variables and mixins
// --------------------------------------------------
#import "variables.less";
//import custom-variables after variables so the values will override.
#import "custom-variables.less"; //only has variables that have changed.
#import "mixins.less";
IMO this is a little bit better than the first solution because you wont have to load two (almost) identical CSS files on the client.
I'm sorry I cant help you with what to to about Bower and your source control as I do not use Bower
Here's the solution which worked for me:
Use bower to install all UI packages e.g. bower install bootstrap chosen
Create a separate folder less which contains all the LESS modifications. This article was very helpful here.
Here's my less/styles.less file:
#import "../bower_components/bootstrap/less/bootstrap.less";
#import "../bower_components/bootstrap-chosen/bootstrap-chosen.less";
//My custom variables - overrides the bootstrap variables file
#import "variables-custom.less";
Use grunt to monitor changes within the less folder and compile them into .css
Here's my Gruntfile.js (thanks to this answer):
module.exports = function(grunt) {
grunt.initConfig({
less: {
development: {
options: {
paths: ["./less"],
yuicompress: true
},
files: {
"./static/css/styles.css": "./less/styles.less"
}
}
},
watch: {
files: "./less/*",
tasks: ["less"]
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
};
This is indeed the best customization method. You create a theme.less and pull in original Bootstrap files (which can get upgraded in the future) and in the same file you call your own custom overrides. Either you #import them from a custom file which is not in the Bower directory or you just write your custom rules in your theme.less itself. You'll find this technique explained in this tutorial as well.
With Grunt, custom setups can get tricky. But with Brunch it's a piece of cake (yes!) and all pretty much goes automatically. Your grandma could do it.
As for avoiding the inclusion of bower_components in source control: with Git it's easy. You just check-in your bower.json but make sure to add /bower_components to your .gitignore file.
You should just create your own style sheet, use both with your custom one listed secondly. That way you can make changes but not change bootstrap at all.
Also, when you update, you keep your style sheet the same.
This allows you to change bits and pieces of Bootstrap but not actually changing the file, you're overriding it.
To be clear, your second CSS file would be SIGNIFICANTLY smaller... Only putting things your needed to change in it.

Resources