Watch and compile entire folder with node-sass? - css

Compass has a lovely command that will watch and compile all scss in a given directory:
compass watch *foldername*
However, the Ruby-based compass is kind of slow and the C-based SASSC, wrapped in the form of node-sass, is much faster. Thing is, I haven't been able to replicate this seemingly simple feature using node-sass.
I followed the directions given here: http://benfrain.com/lightning-fast-sass-compiling-with-libsass-node-sass-and-grunt-sass/, which do a great job of setting up node-sass with grunt to watch for file changes, but it doesn't seem to support watching and converting an entire folder, agnostic of the file names within.
I've tried changing the
sass: {
dist: {
files: {
'css/styles.css': 'sass/styles.scss'
}
}
}
values to the folders, amongst many other things, and nothing seems to work. I'll admit that I don't really know anything about grunt. Is there a way to replicate
compass watch *folder*
or
sass --watch *folder*:*folder*
that I haven't tried, or does this not exist?

Yaniv was on the right track, but the magic seemed to be in "expand". Here's what ended up working:
sass: {
dist: {
files: [{
expand: true,
src: ['sitecontent/**/*.{scss,sass}'],
ext: '.css'
}]
}
}
This compiles all sass files in the sitecontent folder and all subfolders and puts the css next to the sass file - it doesn't compile them to some other folder.

You will need to use grunt-sass in combination with grunt-contrib-watch to get the same affect. The ruby version uses a separate gem to accomplish the file watching functionality, so you can imagine how difficult that is to do cross platform in C++.

You can use something like this:
sass: {
dist: {
files: [{
src: ['*.scss'],
dest: '../public',
ext: '.css'
}]
}
}
Hope that was what you were looking for

Related

Add hash to images in css webpack

Is there a way to add hash values to images that are referenced in CSS when you compile using Webpack?
I'm using React, and have separate scss files for each component file (e.g header.js & header.scss). Within some of the scss files, I have a background image. However, my server has super high caching levels, and is caching the images within the compiled css files.
What I'd like to do is, during the css compilation, add a hash value to each image reference, which would update on every build. So for example, it would compile to this:
.background-class {
background-image: url('images/my-image.jpg?0adg83af0');
}
I've tried to use the url-loader, but because these images aren't being referenced in the JS files, I don't think they're being picked up?
I ended up using a combination of PostCSS and PostCSS CacheBuster. If anyone wants to add this to their webpack setup, you need to run npm i postcss-loader postcss-cachebuster, then in your webpack.config.js, add const PostCssCacheBuster = require('postcss-cachebuster'); to the top of your file, and add the following loader config in between css-loader and sass-loader (obviously if you use this setup):
loader: 'postcss-loader',
options: {
sourceMap: true,
plugins: () => [
PostCssCacheBuster({
imagesPath: "/src/Frontend",
cssPath: "/" + distributionPath,
supportedProps: [
'background',
'background-image'
],
paramName: 'v='
})
]
}
},

Why Webpack's sass-loader is minimizing CSS in production mode?

I was setting the Webpack loaders config for .css and .scss files, I noticed that when using --mode production I'm getting minimized CSS as the final output without even using a minimizer explicitly, here's my loaders config:
{
// Match .css or .scss
test: /\.s?css$/,
use: [
isProd
// In production extract the CSS into separate files
? {
loader: MiniCssExtractPlugin.loader,
options: {
hmr: !isProd
}
}
// In development inject the styles into the DOM
: 'style-loader',
{
loader: 'css-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
}
I'm using sass-loader with node-sass and mini-css-extract-plugin to extract the CSS into separate files, which suggests using optimize-css-assets-webpack-plugin for minimizing the CSS by overriding optimization.minimizer, but I'm already getting minimized output without installing this plugin.
To find what's causing this behavior I tried processing CSS files with and without sass-loader and I found out that sass-loader might be causing this behavior but it doesn't have any option for minimizing the CSS.
So what's causing this behavior? And do I even still need optimize-css-assets-webpack-plugin if my CSS files are minimized?
Option outputStyle in sass-loader options determines the output format of the final CSS style. Default: nested.
For more detailed https://github.com/sass/node-sass#outputstyle
To disable minification, set this option to expanded:
{
loader: 'sass-loader',
options: {
sassOptions: {
outputStyle: 'expanded'
}
}
}
For minify css i reccomend plugin css-nano. It is flexible in settings. It's good work with postcss-loader.
According to the webpack docs,
webpack v4+ will minify your code by default in production mode.
So it's not sass-loader doing the minification, it's just that removing that means webpack isn't processing your SCSS into CSS and therefore not creating a file to be minified.
I'd say if you're happy with simple minification the default is probably fine for production. Other tools might give you more control over the final output including things like source maps, removing duplicate rules, dumping old prefixes, etc.

SASS compile expanded and compressed CSS and rename the output

I am using the command line sass --watch style.scss --style compressed to output a compressed CSS version of my SCSS style sheet.
Is there a way to output one expanded and one compressed CSS file, calling them respectively style.css and style.min.css?
I read the documentation without finding any information on this.
Your best bet would be to go with a task manager like Gulp or Grunt. Then you can specify two separate task for SASS and run grunt compile (using the Grunt example below). One for compressed and one for expanded. Otherwise I would just run another command on the terminal if you don't wan to mess with the config.
sass: {
expanded: {
options: {
style: 'expanded'
},
files: {
'css-expanded/*.css': 'sass/*.scss'
}
}
compressed: {
options: {
style: 'compressed'
}
files: {
'css-compressed/*.min.css': 'sass/*.scss'
}
}
grunt.registerTask('compile': ['sass:expanded', 'sass:compressed']);
You could run two terminal windows, each with one watcher in it. In one you would run
sass --watch style.scss:style.css --style nested
and in the other you would run
sass --watch style.scss:style.min.css --style compressed
I am unaware of a method to do this in one line.

Relative paths in CSS and Grunt minification?

Before I ask this question I want to point out that there are several similar questions posted here on StackOverflow, but none of them provide an accurate solution to the problem.
The problem
I have a workflow setup where Grunt combines and minifies multiple css files into one single file for a production environment.
The problem I'm facing is that font and image paths are breaking after running Grunt, as they're still pointing towards their existing relative file paths.
As an example:
Within static/homepage/startup/common-files/css/icon-font.css I have the following CSS rule:
#font-face{font-family:Flat-UI-Icons;src:url(../fonts/Startup-Icons.eot);
In my Gruntfile, I specify that I want the output of my minified css file to be style.min.css located at static/css/custom/homepage/. The problem with this is that the filepath changes, resulting in all font and image dependencies to no longer be found and return a 404 status in the browser.
What I've done to try solve this
I've figured that there are 2 options to fix this issue:
Copy all dependant files so that they're relative to the new directory wherestyle.min.css resides. The downside to this is that it could quickly become messy and ruin my project folder structure!
Change the paths manually by hand. But then again, what's the point in this? Grunt was designed for automating tasks!
Does anybody know how to fix this problem? I've wasted nearly 10 hours on this and I'm starting to give up. People have claimed to have fixed the issue over at the Github issue page, but nobody really says how they fixed it.
EDIT:
I've looked through the clean-css library source code and it seems that you can pass a relativeTo property to the minifier object. I've had a mess around with this but I'm still stuck. I'll report back if I get any further with this.
EDIT:
Okay I've finally found some documentation which explains what relativeTo (and other) properties do. I'm still stuck on exactly what my configuration should be for my file structure though....
relativeTo - path to resolve relative #import rules and URLs
root - path to resolve absolute #import rules and rebase relative URLs
roundingPrecision - rounding precision; defaults to 2; -1 disables rounding
target - path to a folder or an output file to which rebase all URLs
Here's my Grunt configuration file for reference:
module.exports = function(grunt) {
grunt.initConfig({
concat: {
homepage: {
src: [
'static/homepage/startup/common-files/css/icon-font.css',
'static/homepage/startup/flat-ui/bootstrap/css/bootstrap.css',
'static/homepage/startup/flat-ui/css/flat-ui.css',
'static/homepage/static/css/style.css'
],
dest: 'static/css/custom/homepage/compiled.css',
}
},
cssmin: {
homepage: {
src: 'static/css/custom/homepage/compiled.css',
dest: 'static/css/custom/homepage/style.min.css'
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks("grunt-css-url-rewrite");
grunt.registerTask('build', ['concat', 'cssmin']);
grunt.registerTask('default', ["build"]);
};
Thanks.
Create a less file in static/css/custom/homepage as styles.less
#import your css relatively:
#import "../../../homepage/startup/common-files/css/icon-font.css";
#import "../../../homepage/startup/flat-ui/bootstrap/css/bootstrap.css";
#import "../../../homepage/startup/flat-ui/css/flat-ui.css";
#import "../../../homepage/static/css/style.css";
Then in your gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
less: {
dist: {
options: {
compress: true,
sourceMap: false,
// Add any other path/to/fonts here
paths: ['static/homepage/startup/common-files']
},
files: {
'public/css/dist/style.min.css': 'public/css/default/styles.less'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks("grunt-css-url-rewrite");
grunt.registerTask('build', ["less:dist"]);
grunt.registerTask('default', ["build"]);
};

Include images as Inline in sass without Compass?

I want to add images as base64 in sass. I have been locking at Compass but it feels way to bulky and really not what I'm looking for. Is there a good way to include images or other files inline in css without using compass?
If you use grunt, you can just use the grunt-data-uri task in order to achieve the conversation of regular url() string to base64.
dataUri: {
dist: {
src: ['dist/styles/*.css'],
dest: 'dist/styles/',
options: {
target: [
'img/low-res/embeded/*.*'
],
fixDirLevel: true
}
}
},
Essentially, the task will look for every images contained inside the embeded folder in your .css. From there, it will convert the url() into base64.
Compass is Open Source, just get the part of the code that suit you.
Here is the ruby source on Github

Resources