You'll focus on being more productive instead of busy.
From this post you'll learn...
- How to write and run Gulp tasks.
- How to use Gulp to automate:
- Compiling your SASS.
- Minifying your CSS files.
- Adding prefixes for major browsers such as
-webkit-
and-moz-
. - Watching for file changes.
- Adding
@font-face
rules to your CSS.
- Using Node.js and npm to install Gulp plugins.
- How to integrate Gulp tasks with Visual Studio's Task Runner.
What is Gulp?
Gulp is a task runner written in JavaScript.
Task runners are commonly used to run and automate a sequence of tasks.
Example of tasks include: minifying your JavaScript files, SASS compilation to CSS, and automatically refreshing your browser upon code changes.
You write a JavaScript file which contains your tasks. Then Gulp uses plugins to perform your development tasks. You can chain these plugins to perform more complex actions.
var gulp = require('gulp');
var less = require('gulp-less');
var minifyCSS = require('gulp-csso');
gulp.task('css', function(){
return gulp.src('css/*.less')
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest('build/css'))
});
gulp.task('default', 'css');
For us, this means little code and work is required to be able process and output our files in the format we want.
At the time of writing there are 3686 plugins available.
In addition, Gulp integrates well with Visual Studio's Task Runner Explorer.
Gulp or Grunt
You'll often find that it's not which is better, but what are your experiences and preferences.
Each task in Grunt accesses files separately to be able to process them. Gulp uses streams, meaning the files stay in memory until after we've finished modifying them.
You'll find that Gulp is one of the most popular task runners available today.
Alternatives for Processing SASS?
Node Package Manager
As an alternative, developers use node package manager (npm) to run tasks. There are a large number of packages to allow you to do what you want. This can also be integrated with Visual Studio.
You write your scripts in your package.json
file:
"name": "asp.net",
"version": "1.0.0",
"devDependencies": {
"jshint": "latest"
},
"scripts": {
"lint": "jshint *.js"
}
You use the npm run
command to execute the script:
npm run lint
Webpack
You may notice module bundlers such as Webpack being used more often. Webpack is not a task runner, but it can be used to accomplish all of the tasks mentioned above: SASS, minify CSS and add vendor prefixes
Webpack has become one of the favourites and is highly used. But Webpack has a steeper learning curve compared to Gulp. It also requires applications to be written in a modular way, which is not always possible, especially if you're not familiar with the latest JavaScript frameworks.
Choose a tool that allows you to do the things you need to do easily and efficiently. Beyond the investment of time required in learning a new tool, your choice should allow your projects to be extensible, easy to maintain, and understood by other developers within your team.
Performing Tasks with Gulp
Install Node.js. Use the default installation settings because you also need to install node package manager.
Run the commands to ensure the installation was successful:
node -v
npm -v
Node package manager uses a file called package.json
to store a list of all your locally installed node packages.
Make sure you are in the web projects root directory. All upcoming commands will be run from this directory.
You can run the following command to create your package.json file:
npm init --yes
This will generate a default package.json
file, which you can edit through Visual Studio or any other text editor.
Or you can create one manually, which must contain at least the name
and version
properties:
{
"name": "asp.net",
"version": "1.0.0"
}
Installing Gulp
Run the following command:
npm install --save-dev gulp
After running the above command, a new folder called node_modules
will be created.
The --save-dev
option tells npm to add Gulp to our devDependencies
list in our package.json file. devDependencies
are modules which are required during development. Other examples of devDependencies
include: JSHint, Grunt, Browsersync and TypeScript.
Libraries listed in both dependencies
and devDependencies
will be downloaded by running npm install
.
By default,
npm install
will install all modules listed as dependencies in package.json.
With the
--production
flag (or when theNODE_ENV
environment variable is set to production), npm will not install modules listed indevDependencies
.
Installing SASS and Other Plugins
From the root of your project, run the following command:
npm install --save-dev gulp-sass gulp-rename gulp-postcss autoprefixer cssnano
Once these are installed you'll see them in your package.json
file.
gulp-sass will take our SCSS files and convert them to CSS and gulp-rename will rename our files.
What is PostCSS?
We've introduced PostCSS. PostCSS allows you to modify your CSS using a variety of plugins. At the time of writing, PostCSS has more than 200 plugins. These plugins can be integrated with Gulp and injected into the pipe.
We will use autoprefixer to add vendor prefixes, such as -webkit-
and -moz-
. This means we don't have to write them ourselves. We will also use cssnano to minify our css.
Envato Tuts+ has some great articles on what PostCSS is and the benefits it can provide.
In a nutshell, PostCSS takes CSS and turns it into a form of data that JavaScript can manipulate. JavaScript-based plugins for PostCSS then perform said code manipulations.
Writing the Styles Task
We need to create a new JavaScript file called gulpfile.js
and add it to the root of the web project:
We now begin writing our styles task:
var gulp = require('gulp'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
postcss = require('gulp-postcss'),
cssnano = require('cssnano'),
autoprefixer = require('autoprefixer');
var paths = {
styles: './Styles/**/*.scss',
css: './wwwroot/css/'
};
gulp.task('styles', function () {
var plugins = [
autoprefixer(),
cssnano()
];
return gulp.src(paths.styles)
.pipe(sass())
.pipe(postcss(plugins))
.pipe(rename(function (path) {
path.basename = path.basename.toLowerCase() + '.min'
}))
.pipe(gulp.dest(paths.css));
});
We've including the modules we are going to use in our tasks.
We've named our task 'styles' and provided it with a function that will convert our SASS to CSS. The src
path contains a globbing pattern that tells Gulp to take all files with a .scss
extension inside of our Styles folder, and inside any of its subdirectories, and add them to the pipe ready to process.
We've used the default configuration from Autoprefixer.
Autoprefixer uses Browserslist, so you can specify the browsers you want to target in your project by queries like last 2 versions or > 5%.
If you want to override the defaults and instead specify the browsers you want to target, like the last 2 versions, you pass in an object with a browsers property:
var plugins = [
// passing options to autoprefixer
autoprefixer({ browsers: 'last 2 major versions' }),
cssnano()
];
There are many options to choose from and a variety of ways to target specific browsers.
We rename our files to include the .min
suffix.
We save our processed files to the /wwwroot/css/
directory.
Testing the Task
Running the below command from the root of our web project will run our styles task:
gulp styles
The Watch Task
The 'watch' task looks for changes to files and then responds by executing a function:
gulp.task('watch', function () {
gulp.watch(paths.styles, ['styles']);
});
The .watch()
method is going to look for all files ending in a .scss
inside the Styles folder or any of its subdirectories. The second parameter is the name of the task we want to run when those files change. We want to run a single task so we've used the syntax:
gulp.watch(paths.styles, ['styles']);
To run multiple tasks we add additional names in the array of task names:
gulp.watch(paths.styles, ['styles', 'styles2']);
Running the Watch Task
Run the following command to test your watch task:
gulp watch
Make changes to your .scss
files and check the updates are visible in your .css
files.
You can stop the watch task by pressing the Ctrl + C
keys.
We like to run our watch task each time we open our web project. We can do this with Visual Studio's Task Runner.
Right click on your gulpfile.js
file and select Task Runner Explorer:
Right-click your watch task and select Bindings - Project Open.
The watch task will run automatically after you open the project.
Update Node Version in Visual Studio
If you're trying to run your watch task with Visual Studio's Task Explorer you may encounter the following error:
You'll need to update a few things to be able to fix this.
First modify where Visual Studio looks for Node.js.
Select Tools – Options.
Expand Projects and Solutions, then expand Web Package Management and select External Web Tools.
Move the $(PATH)
path above the $(VSINSTALLDIR)\Web\External
path:
Run the following commands to re-install gulp-sass
:
npm uninstall --save-dev gulp-sass
npm install --save-dev gulp-sass
On the Task Runner Explorer, select the refresh icon and the Explorer will show your tasks.
Handling the Watch Task errors
When there is an error in your SASS code, Gulp will throw an error and the watch task will stop running. You will need to fix all errors and start the Gulp watch task again. The biggest problem is realizing there is an error and the task has stopped running. You'll continue writing your code and debugging your application, only to realize later that your changes are not shown on your web application.
We can change this by adding a Gulp plugin called gulp-plumber.
Install gulp-plumber:
npm install --save-dev gulp-plumber
After installation, we can add it to our styles task:
var gulp = require('gulp'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
postcss = require('gulp-postcss'),
cssnano = require('cssnano'),
autoprefixer = require('autoprefixer'),
plumber = require('gulp-plumber'); // include plumber
return gulp.src(paths.styles)
.pipe(plumber()) // add plumber to pipe
.pipe(sass())
.pipe(postcss(plugins))
.pipe(rename(function (path) {
path.basename = path.basename.toLowerCase() + '.min'
}))
.pipe(gulp.dest(paths.css));
Using Google Fonts
The Post CSS plugin Font Magician will generate our font-face
rules when we use Google Fonts.
Want to use Google Fonts? I'll add them for you. Want to use the visitor's local copy of a font? Done. Want to host your own fonts? Just tell me where they are, and I'll do the rest.
npm install postcss-font-magician --save-dev
var gulp = require('gulp'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
postcss = require('gulp-postcss'),
cssnano = require('cssnano'),
autoprefixer = require('autoprefixer'),
plumber = require('gulp-plumber'),
fontmagician = require('postcss-font-magician'); // add postcss-font-magician
Because we'll be using Font Magician, we do not want cssnano to optimize font values:
gulp.task('styles', function () {
var plugins = [
autoprefixer({ browsers: 'last 2 major versions' }),
cssnano({ minifyFontValues: false }), // add optimization option
fontmagician() // add fontmagician
];