Register to get access to free programming courses with interactive exercises

Basic Gulp functions Gulp

In the last lesson, we plugged in the parallel() function that's built into the Gulp package, which allowed us to combine several functions into one single task.

const { parallel } = require('gulp');

const sassCompile = (done) => {
  console.log('Compile SASS to CSS');

  done();
};

const pugCompile = (done) => {
  console.log('Compile Pug to HTML');

  done();
};

const imagesOptimize = (done) => {
  console.log('Optimize Images');

  done();
};

exports.default = parallel(sassCompile, pugCompile, imagesOptimize);

In addition to parallel() there are several other functions inside the Gulp package that will be covered in this lesson. There's no need to describe each function separately, so let's look at the most common ones that you'll use in your work. More information about the different functions can be found in the documentation of the Gulp package, a link to which can be found at the end of the lesson.

series()

The series() function is very similar in functionality to the parallel() function we learned in the previous lessons. But if there are two different functions, then they must have differences? And indeed they do! The difference lies in the way the functions are called within the task. There are two approaches here:

  • The parallel() function, as the name implies, executes functions in parallel/simultaneously. In the example above, the sassCompile(), pugCompile() and imagesOptimize() functions won't queue up or wait for each other to finish, but will start working together. This approach is convenient if the tasks are in no way related to each other and the result of one doesn't depend on the result of the other.

Parallel execution of Gulp tasks

  • In contrast to parallel execution, we also have series execution, which is implemented by the series() function. The point of this function is that until one function is finished, the other won't start. This is very important when using multiple subtasks, which directly affect what the next function will work with.

Consistent execution of Gulp tasks

In the screenshots, it's worth paying attention to when tasks are started. With parallel execution, Gulp shows all the tasks running simultaneously, and when using the series() function, the execution of a new task starts only after the previous one finishes.

src() and dest()

Many of the tasks in Gulp are related to file processing. Whether it's SASS, Pug, or another tool, they all need to be processed into a format that the browser understands. To do this, you must specify which file will be processed and where it should be moved after processing. Two functions are responsible for this in Gulp:

  • src() to specify the path to the file being processed
  • dest() to specify the path where to put the processed file

There are no particular surprises here. These functions are responsible for handling file paths and basic communication. In fact, they're much more flexible than they may seem at first, but the rest of the functionality, such as caching, is used very rarely and in only large projects. Let's look at a basic example of a file copying operation:

const { src, dest } = require('gulp');

const copyFile = () => {
  return src('src/sass/app.scss')
    .pipe(dest('build/styles'));
};

exports.copy = copyFile;

After completing the task, the src/sass/app.scss file will be copied to the build/styles/ directory

layout-project/
├── build/
│   ├── styles/
│   │   └── app.scss
├── src/
│   ├── sass/
│   │   └── app.scss
│   ├── pages/
│   │   ├── index.pug
│   │   ├── sections/
│   │   │   ├── head.pug
│   │   │   └── footer.pug
├── gulpfile.js
├── package.json
└── node_modules/

You don't need it there now because the build directory will get the processed files, but now you know exactly how they'll get there :)

Note that the done() function isn't called in this example, unlike in the previous examples. This is because we used the keyword return. You may have read more about the return keyword in the Introduction to Programming course.

Globs

In the example above, we had a clear path to the file that we wanted to copy. For small projects this can be a fairly simple and efficient solution, but often it's necessary to process not just one, but all files from a particular directory or even a directory tree. For example, we can have the following style structure

layout-project/
├── src/
│   ├── sass/
│   │   ├── global.scss
│   │   ├── mobile.scss
│   │   ├── desktop.scss

How can these files be processed correctly? There are two options:

  1. Process each file individually
  2. Process all files within one function

With the first option it's simple: we create three functions, combine them into a single task and execute:

const { src, dest, parallel } = require('gulp');

const copyGlobalScss = () => {
  return src('src/sass/global.scss')
    .pipe(dest('build/styles'));
};

const copyMobileScss = () => {
  return src('src/sass/mobile.scss')
    .pipe(dest('build/styles'));
};

const copyDesktopScss = () => {
  return src('src/sass/desktop.scss')
    .pipe(dest('build/styles'));
};

exports.copy = parallel(copyGlobalScss, copyMobileScss, copyDesktopScss);

If there are only three files, then this solution can be considered normal, but it's not a good thing. After all, the same operation is performed on each file, and only the file being processed changes.

To specify multiple files, we use special path templates, called Globs. This is a small package that converts templates to paths and is built into Gulp by default. You only really need to know a couple of tricks that you can use to select almost any files and in any quantity.

The first construction is the use of an asterisk *, it indicates that you should select anything that doesn't contradict the path specified. For example, we can replace the file name in the last example with an asterisk and then Gulp will select all three files: global.scss, mobile.scss and desktop.scss

const { src, dest } = require('gulp');

const copyScss = () => {
  return src('src/sass/*.scss')
    .pipe(dest('build/styles'));
};

exports.copy = copyScss;

You can make copying files even easier. Suppose the SASS files are in completely different directories, and we want to put them together into one. You need to go through all available directories, check if there is a file with the scss/sass extension, and copy it. This uses a special construction ** that which is aimed at going through directories. For example, you can modify the code as follows:

const { src, dest } = require('gulp');

const copyScss = () => {
  return src('src/**/*.scss')
    .pipe(dest('build/styles'));
};

exports.copy = copyScss;

Now all directories inside src will be checked for files with the extension .scss when the task starts. Here it's important to note that the search will be performed not only within the src subdirectories, but also within the src directory itself. For example, the following files will be selected:

  • src/styles.scss
  • src/project/app/styles/app.scss
  • src/sass/mobile.scss

and so on.


Note that: when using the method that searches for files in different directories, when you transfer them using dest() Gulp keeps the nesting that it had. For example, if you run the last example, the src/project/app/styles/app.scss file will end up in the build/styles/project/app/styles/app.scss path. This is an important feature to remember to avoid mistakes when working with the project.


This works fine, but there's one significant problem – there may be directories inside our src that we don't need to process files from. For example, directories with npm packages. To deal with this problem, Globs has a directory exclusion method which is specified with a logical negation sign - !. In this case, the desired paths and exceptions are specified as an array of strings. Exclude the src/project directory from copying:

const { src, dest } = require('gulp');

const copyScss = () => {
  // ['src/**/*.scss', '!src/project/**'] — string array
  // which excludes the src/project directory and all directories nested within it
  return src(['src/**/*.scss', '!src/project/**'])
    .pipe(dest('build/styles'));
};

exports.copy = copyScss;

It's important to note that the characters /** go at the end of the excluded directory. They say you need to exclude not only the directory itself, but also all the subdirectories in it.

Pipe()

Looking at the last examples, you might ask, "What's with the pipe?" Let's move on to this method:

Without going into the fine details, pipe() allows you to link read and write streams to each other. If we go back to the file copying example, it's through pipe() that we can get a file and give it to dest() for further processing.

The same will happen when processing files with plugins, such as when compiling SASS into CSS. To bind the whole chain at once, you need to use pipe().

In the context of working with the Gulp package, you can build a typical chain, or template, of tasks:

const task = () => {
  return src('the file we are working with')
    .pipe(pluginOne()) // Processing the first plugin
    .pipe(pluginTwo()) // Processing by the second plugin
    .pipe(pluginN()) // Processing another plugin
    .pipe(dest('the path where we put the processed file'));
};

Recommended materials

  1. Built-in functions in Gulp

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs
Layout Designer icon
Profession
Under development beginner
Layout with the latest CSS standards
start anytime 5 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.