Returning reset css styles. Is it worth using CSS Reset?

Hello everyone, friends! Today we will take a closer look at what Gulp is and how it can be used to automate the work of a Front-end developer. As a result of the lesson, we will assemble a serious and impressive working Front-end environment for web development using Gulp.

Video lesson:

Cool

Stammer

  • Tutorial on upgrading Gulp to version 4: Check out the Gulp 4 tutorial
https://github.com/agragregra/gulp-lesson

Gulp is a tool that helps automate routine web development tasks. Gulp is designed to solve problems such as:

  • Creating a web server and automatically reloading the page in the browser when saving the code, monitoring changes in project files;
  • Using various JavaScript, CSS and HTML preprocessors (CoffeeScript, Less, Sass, Stylus, Jade, etc.);
  • Minification of CSS and JS code, as well as optimization and concatenation of individual project files into one;
  • Automatic creation of vendor prefixes (prefixes to the name of CSS properties that browser manufacturers add for non-standard properties) for CSS.
  • Managing files and folders within the project - creating, deleting, renaming;
  • Launching and monitoring the execution of external operating system commands;
  • Working with images - compression, creating sprites, resizing (png, jpg, svg, etc.);
  • Deploy (send to an external server) a project via FTP, SFTP, Git, etc.
  • Connecting and using an unlimited number of Node.js and Gulp utilities, programs and plugins in a project.
  • Creation of various project maps and automation of other manual labor.

It's safe to say that Gulp and the many utilities written for it are suitable for solving almost any problem when developing a project of any complexity - from a small website to a large project.

Any project using Gulp has a file in the root gulpfile.js, which contains a set of project management instructions. I would like to say right away that writing instructions for Gulp is not programming, although they are written in JavaScript. Don’t be afraid of large gulpfile.js, basically all the instructions are the same and have common features. By the time you read this guide, you should have no questions about Gulp, as the build system is simple. But if you still have questions, be sure to write in the comments.

Installing Gulp

Attention! If you are a user of the latest version of Windows, I recommend using the Bash terminal for web development. In this case, there is no need to download the installer from Nodejs.org. Use this guide: .
If you have problems completing the tutorial using Gulp 4, I recommend rolling back to version 3, going through the entire tutorial, and only then updating package.json to version 4. For better understanding. You can roll back the version in the package.json file. Instead of "gulp": "^4.x.x", write the version "^3.9.1", delete the "node_modules" folder and install the packages again " npm i".

To work with Gulp, you must have Node.js installed. Installing Node.js for various platforms is quite simple - download the Node installer for your operating system and install. I recommend installing the latest version of Stable. For Linux and latest Windows users, I have prepared a separate installation guide: Using the Linux Subsystem for Web Development in Windows 10.

Once Node is installed, you can begin installing Gulp. Open a terminal (right-click on the folder while holding Shift > Open Linux Shell Here) and run the following command:

Npm i gulp -g

For Mac and Linux users and Ubuntu bash on Windows, global installation with the -g switch must be performed with superuser rights, sudo, For example:
sudo npm i gulp -g.

From this command we see that the package manager is launched npm(Node Package Manager), which installs Gulp on the system with the install command. Key -g indicates that the package will be installed on the system globally, that is, on the system, and not in the project folder. Without the -g switch, the package is installed in the folder in which the current commands are executed, so be careful.

Creating a Gulp Project

Let's create an example project folder to work with, let it be, for example, the folder myproject.

Very important! Do not create Russian-language project folders and make sure that the path to the project folder does not contain Cyrillic characters, that is, it is not written in Russian. Otherwise, you may have problems running various Gulp utilities. Your user's folder should also not be in Russian. Everything is in Latin letters only.

Now let's open a terminal in the project folder. For Windows users, just hold down Shift and open the context menu. There will be an option “Open Linux shell here”. The Linux shell must be pre-installed, see tutorial: Using the Linux Subsystem for Web Development on Windows.

Npm init

Following the instructions, let's fill in the meta information about our project:

As a result of this simple initial setup of our new Gulp project, a new file will be drawn in the myproject folder package.json.


The package.json file is our project's manifest file, which describes, in addition to the information that we entered in the terminal, also information about the packages used in our project.

For example, if we install Gulp in a project with the key --save-dev, then the package and version used will be automatically added to our package.json. Such accounting will allow you to quickly deploy a new project using an existing package.json and install the necessary modules with dependencies that are specified in package.json in new projects.

Let's install Gulp in our project:

Npm i gulp --save-dev

What we see from this line: npm installs the gulp package in the current myproject folder (because there is no -g switch to install the package globally on the system) and saves the package name with the version in the package.json file:


In addition, we have a folder node_modules, which now contains the gulp package installed and the necessary dependencies. All modules and dependencies that we will install into the project will automatically be dumped into this folder. There can be a lot of folders with dependencies, despite the fact that we have not installed that many packages. This is due to the fact that in addition to the main packages, programs necessary for the correct operation of the main package are installed. There is no need to clean or delete anything from the node_modules folder. Additionally, you may have an additional file package-lock.json. There is nothing wrong with this, it is a service file that you can simply ignore.

Directory structure in projects

Working with various plugins, programs and scripts, be it a jQuery plugin, a module for a CMS, a web project or some other software, you probably noticed that all projects have a similar directory structure, for example, most projects have a folder dist And app. Let's create the initial structure of our learning project. As a result, we must create the following structure in our project myproject (all files that did not exist will be created empty for now):

  • myproject/
    • app/
      • css/
      • fonts/
      • img/
      • js/
      • sass/
      • index.html
    • dist/
    • node_modules/
    • gulpfile.js
    • package.json
This structure is found quite often, in almost all projects, but this is not an axiom and some projects may have a completely different structure. For this article we will use exactly this project structure.

Here we see the folder app/, which will contain all the source materials of the project - original CSS, Sass, js library files, original images. In general, this is the source folder for our project.

Folder dist/ will contain a finished product, optimized, compressed, combed. This is the production folder.

gulpfile.js

Now let's open it in the code editor gulpfile.js and write into it:

Var gulp = require("gulp");

With this line we connect Gulp to our project using the function require. This function connects packages from the node_modules folder to our project, assigning them to a variable. In this case, we create a variable gulp.

Gulp.task("mytask", function() ( console.log("Hi, I'm a task!"); ));

mytask is the name of the command that you will call in the location you need in gulpfile.js. In addition, you can execute the task directly on the command line by writing:

Gulp mytask

gulpfile.js:


Result of the command gulp mytask:


If you are using Gulp 4 and you get an error about the task being unable to complete, you can add async before function() and execute the code asynchronously: var gulp = require("gulp"); gulp.task("mytask", async function() ( console.log("Hi, I'm a task!"); ));

This is, of course, a very simple basic example of creating a task. As a rule, tasks are somewhat more complex and include some additional commands:

Gulp.task("mytask", function () ( return gulp.src("source-files") // Selecting source files for processing by the plugin.pipe(plugin()) // Calling the Gulp plugin to process the file.pipe(gulp .dest("folder")) // Output the resulting file to the destination folder (dest is the destination)))

  • gulp.src- selection of project source files for processing by the plugin;
  • .pipe(plugin())- calling the Gulp plugin to process the file;
  • .pipe(gulp.dest("folder"))- output the resulting file to the destination folder (dest - destination).

This is the Gulp base, now you can create instructions. First, let's create a handler that will compile Sass files into CSS (CSS preprocessing).

Gulp Sass

Let's install the package gulp-sass to our project, saving the version and name in package.json.

Please note that any Gulp packages, for any task, are easy to Google and have quite comprehensive instructions for connecting on their homepages and in the documentation.
npm i gulp-sass --save-dev

Var gulp = require("gulp"), sass = require("gulp-sass"); //Connect Sass package

Let's create a file in the app/sass folder main.sass, set the body background to black and write a handler for it in gulpfile.js


gulpfile.js:

Var gulp = require("gulp"), // Connect Gulp sass = require("gulp-sass"); //Connect the Sass package gulp.task("sass", function())( // Create a task "sass" return gulp.src("app/sass/main.sass") // Take the source.pipe(sass()) // Convert Sass to CSS using gulp-sass .pipe(gulp.dest("app/css")) // Upload the result to the app/css folder));

After this, it would be logical to execute our new task in the terminal sass:

Gulp sass

As a result of executing this command, a file will appear in the app/css folder main.css.


From the same miracles, my friend. As you can see, everything is simple :-)

Selecting files for gulp.src

Basically, we have covered everything there is to know about Gulp, now we will delve into every detail of what was outlined above.

The selection of files in the example above is quite simple; we took the file directly: gulp.src("app/sass/main.sass"). But files can also be selected by template. The file selection pattern is called glob- https://en.wikipedia.org/wiki/Glob_(programming) . Let's take a closer look at all the possibilities for selecting files for processing.

Most Common Sampling Patterns

  • *.sass- selects all files that have a specific extension (in this case, .sass) in the root folder project.
  • **/*.js- selects all files with the extension .js in all project folders.
  • !header.sass- excludes the file from the general selection
  • *.+(scss|sass)- specifies a complex pattern for several file types, separated by a vertical bar. In this example, the selection will include any sass and scss files in the project root.

Let's make some changes to the task sass and make it more universal:

Gulp.task("sass", function())( return gulp.src("app/sass/**/*.sass") // Take all sass files from the sass folder and child ones, if any.pipe(sass( )) .pipe(gulp.dest("app/css")) ));

The fact is that taking directly one separate file is not always convenient, since in the folder sass There may be other files with the sass extension that can be used in the project.

Please note that sass files that are intended to be imported into other files as part of a common file begin with an underscore _part-1.sass. Such files do not participate in compilation as separate files, but are added via @import to the main files.

Monitoring changes in files (Gulp Watch)

Gulp supports the method watch to check saved files and has the following syntax:

Gulp.watch("watch-files", ["task1", ​​"task2"]);

If, for example, we want to monitor all changes in the sass files of our project, we can use the following construction:

Gulp.watch("app/sass/**/*.sass", ["sass"]);

What we see: Gulp watches all sass files and when saved, executes a sass task that automatically compiles them into css files.

Also, we can create a separate task to monitor all the necessary files

Gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", ["sass"]); // Watching sass files // Watching other file types ) );

For Gulp 4 the code will look like this: gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); ));

If we run in the console gulp watch then Gulp will automatically watch for all changes in sass files when saving and compile them into css.

It would be nice, in addition to this beauty, to automatically reload the page when there are changes in files. For this task, Browser Sync is suitable for us.

Automatic page refresh using Bbrowser Sync

Browser Sync is an excellent solution for LiveReload pages when saving files. Moreover, the reload occurs not only in one browser, but also in all browsers on the network, be it mobile devices or other computers on the same Wi-Fi network.

We already know how to install add-ons for Gulp, so let's install Browser Sync in our project:

Npm i browser-sync --save-dev

And, of course, we’ll include it in the gulpfile.js file, as we did earlier with the gulp-sass package.

Var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync"); // Connect Browser Sync

Create a task for Browser Sync:

Gulp.task("browser-sync", function() ( // Create a task browser-sync browserSync(( // Execute browser Sync server: ( // Define server parameters baseDir: "app" // Directory for the server - app ) , notify: false // Disable notifications ));

Great! Our server is ready for operation and automatic reloading. Now let's follow the changes in Sass. If the Sass file is updated, we automatically inject the modified CSS file into the HTML:

Gulp.task("sass", function())( // Create a Sass task return gulp.src("app/sass/**/*.sass") // Take the source.pipe(sass()) // Transform Sass in CSS using gulp-sass .pipe(gulp.dest("app/css")) // Upload the result to the app/css folder .pipe(browserSync.reload((stream: true))) // Update the CSS on the page when change ));

All we have to do is run the browser-sync task before it starts gulp watch. Let's modify the task a little watch by adding execution browser-sync And sass before launch watch:

Gulp.task("watch", ["sass", "browser-sync"], function() ( gulp.watch("app/sass/**/*.sass", ["sass"]); // Monitoring sass files // Monitoring other file types ));

Please note that we perform tasks ["sass", "browser-sync"] before launch watch, since their execution is necessary for us to correctly display changes at the time of server startup.
For Gulp 4, it would be more logical to write this and execute the entire structure in the default task: gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel(" sass")); )); gulp.task("default", gulp.parallel("sass", "browser-sync", "watch"));

Let's place the watch task after all other tasks and as a result we will get this gulpfile.js for Gulp 3:

Var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync"); // Connect Browser Sync gulp.task("sass", function())( // Create a Sass task return gulp.src("app/sass/**/*.sass") // Take source.pipe(sass() ) // Convert Sass to CSS using gulp-sass .pipe(gulp.dest("app/css")) // Upload the result to the app/css folder .pipe(browserSync.reload((stream: true))) // We update the CSS on the page when it changes)); gulp.task("browser-sync", function() ( // Create a task browser-sync browserSync(( // Execute browserSync server: ( // Define server parameters baseDir: "app" // Directory for the server - app ), notify: false // Disable notifications )); gulp.task("watch", ["sass", "browser-sync"], function() ( gulp.watch("app/sass/**/*.sass", ["sass"]); // Monitoring sass files // Monitoring other file types ));

This is the code for Gulp 4:

Var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync"); // Connect Browser Sync gulp.task("sass", function())( // Create a Sass task return gulp.src("app/sass/**/*.sass") // Take source.pipe(sass() ) // Convert Sass to CSS using gulp-sass .pipe(gulp.dest("app/css")) // Upload the result to the app/css folder .pipe(browserSync.reload((stream: true))) // We update the CSS on the page when it changes)); gulp.task("browser-sync", function() ( // Create a task browser-sync browserSync(( // Execute browserSync server: ( // Define server parameters baseDir: "app" // Directory for the server - app ), notify: false // Disable notifications )); gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); // Monitoring sass files )); gulp.task("default", gulp.parallel("sass", "browser-sync", "watch"));

In order to monitor changes in the browser, we will make the appropriate markup in the index.html file of the app directory with the connection of the style file main.css:

Document

Let's run the "gulp" command in the terminal. The result is fascinating:


Let's figure out what's happening in the console (the picture may vary depending on the software version):


After we are happy with the result, a very expected question arises - how, exactly, to update the page while saving HTML and JS?

And we are up to this task. Create a file in the app/js folder common.js. This is the main custom JS file in our project. Let's modify the code:

Code for Gulp 3:

Gulp.task("watch", ["sass", "browser-sync"], function() ( gulp.watch("app/sass/**/*.sass", ["sass"]); // Monitoring sass files in the sass folder gulp.watch("app/*.html", browserSync.reload); // Monitoring HTML files in the project root gulp.watch(["app/js/common.js", "app" /libs/**/*.js"], browserSync.reload); // Monitoring the main JS file and libraries ));

Code for Gulp 4 (here it is better to add an additional task for processing HTML and JS):

Gulp.task("scripts", function() ( return gulp.src(["app/js/common.js", "app/libs/**/*.js"]) .pipe(browserSync.reload(( stream: true ))) )); gulp.task("code", function() ( return gulp.src("app/*.html") .pipe(browserSync.reload(( stream: true ))) )); gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); // Monitoring sass files gulp.watch(" app/*.html", gulp.parallel("code")); // Watching HTML files in the project root gulp.watch(["app/js/common.js", "app/libs/**/* .js"], gulp.parallel("scripts")); // Monitoring the main JS file and libraries )); gulp.task("default", gulp.parallel("sass", "browser-sync", "watch"));

Here we use the browserSync.reload function, which was kindly provided to us by the Browser Sync package. Please note the selection of tracking files.

In principle, we already have a fairly advanced working environment. But moving on, this is not all that Gulp is capable of.

JavaScript optimization

Let's look at how you can optimize your project's JS files. Most often, libraries and third-party jQuery and JavaScript plugins need optimization. Let's create in a folder app pack libs, which will contain the libraries necessary for the project. We will place all libraries in separate folders. To install new libraries, I recommend using Bower.

Install Bower:

Npm i -g bower

Please note that Bower requires Git to be installed. If you are using the Ubuntu bash shell on Windows, you do not need to install Git.

Now let's create a file in the project folder .bowerrc, in which we write:

("directory": "app/libs/")

If you are a Windows user, you won't be able to just create a file starting with a dot. In this case, you can simply put a period at the end of the file and press Enter: .bowerrc.

With this setting we specify the default path for installing plugins using Bower.

Let's install jQuery and Magnific Popup, for example:

Bower i jquery magnific-popup

Please note that all (or almost all) plugins have a dist folder, we talked about this earlier. This folder contains ready-made production files, which we will use in our project.

Let's create a task scripts, which will collect all JS library files into one and minify the file. To do this, install 2 packages: gulp-concat and gulp-uglifyjs.

Npm i --save-dev gulp-concat gulp-uglifyjs

Let's include new libraries in gulpfile.js:

Var gulp = require("gulp"), // Connect Gulp sass = require("gulp-sass"), // Connect the Sass package, browserSync = require("browser-sync"), // Connect Browser Sync concat = require ("gulp-concat"), // Connect gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"); // Connect gulp-uglifyjs (for JS compression)

We create a task to build and compress all libraries (before watch):

Gulp.task("scripts", function() ( return gulp.src([ // Take all the necessary libraries "app/libs/jquery/dist/jquery.min.js", // Take jQuery "app/libs/magnific -popup/dist/jquery.magnific-popup.min.js" // Take Magnific Popup ]).pipe(concat("libs.min.js")) // Collect them in a heap in a new file libs.min.js .pipe(uglify()) // Compress the JS file.pipe(gulp.dest("app/js")); // Upload to the app/js folder));

Let's check how our new task works scripts by running in the terminal:


Executing a task scripts can be run before executing watch. Gulp 3:


For Gulp 4 the code will look like this - add a task to parallel execution scripts(some structure has already been set earlier): gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); // Observation for sass files gulp.watch("app/*.html", gulp.parallel("code")); // Monitoring HTML files in the project root gulp.watch(["app/js/common.js", " app/libs/**/*.js"], gulp.parallel("scripts")); // Monitoring the main JS file and libraries )); gulp.task("default", gulp.parallel("sass", "scripts", "browser-sync", "watch"));

Next, you can connect all the necessary CSS library files to the project. In our case, only one library needs to be included - this is Magnific Popup. Let's do it through @import in Sass file sass/libs.sass:

@import "app/libs/magnific-popup/dist/magnific-popup.css" // Import the Magnific Popup library

Attention! In new versions gulp-sass To import CSS files into Sass, you must specify the extension .css and import CSS files into SASS files with an underscore at the beginning of the name. For example, in order to import the library-name.css file, you need to create an auxiliary SASS file, for example, _libs.sass, and import the required CSS into it - @import "app/libs/library-name.css" and add the auxiliary _libs.sass to the main main.sass without specifying the underscore and extension, for example, like this: @import "libs"

At the output, in the app/css folder we receive, in addition to main.css, the libs.css file, which contains the styles of all libraries. There is little point in minifying the main.css file, since it contains custom (user) styles. But we are happy to minify the libs.css file.

Attention! If no library code appears in the libs.css file and you still see @import statements in it, create a separate _libs.sass file for the libraries that starts with underscore. Then import this file into the main one, thereby combining both the libraries and custom styles into one file.

To minify CSS, install packages gulp-cssnano And gulp-rename:

Npm i gulp-cssnano gulp-rename --save-dev

And let's connect them in our gulpfile.js:

Var gulp = require("gulp"), // Connect Gulp sass = require("gulp-sass"), // Connect the Sass package, browserSync = require("browser-sync"), // Connect Browser Sync concat = require ("gulp-concat"), // Include gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Include gulp-uglifyjs (for JS compression) cssnano = require("gulp-cssnano" ), // Connect the package for CSS minification rename = require("gulp-rename"); // Include the library to rename files

And create the corresponding task css-libs. Let's immediately add this task to watch so that the libraries are collected during the project launch. It’s better to call the sass task before running css-libs, so that we have something to minify:

Gulp.task("css-libs", ["sass"], function() ( return gulp.src("app/sass/libs.sass") // Select the file to minify.pipe(sass()) // Convert Sass to CSS with gulp-sass .pipe(cssnano()) // Compress.pipe(rename((suffix: ".min"))) // Add suffix.min .pipe(gulp.dest("app/css ")); // Upload to the app/css folder)); gulp.task("watch", ["browser-sync", "css-libs", "scripts"], function() ( gulp.watch("app/sass/**/*.sass", ["sass "]); // Monitoring sass files in the sass folder gulp.watch("app/*.html", browserSync.reload); // Monitoring HTML files in the project root gulp.watch(["app/js/common .js", "app/libs/**/*.js"], browserSync.reload); // Monitoring the main JS file and libraries ));

Code for Gulp 4:

Gulp.task("css-libs", function() ( return gulp.src("app/sass/libs.sass") // Select a file to minify.pipe(sass()) // Convert Sass to CSS using gulp -sass .pipe(cssnano()) // Compress.pipe(rename((suffix: ".min"))) // Add suffix.min .pipe(gulp.dest("app/css")); Upload to the app/css folder)); gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); // Monitoring sass files gulp.watch(" app/*.html", gulp.parallel("code")); // Watching HTML files in the project root gulp.watch(["app/js/common.js", "app/libs/**/* .js"], gulp.parallel("scripts")); // Monitoring the main JS file and libraries )); gulp.task("default", gulp.parallel("css-libs", "sass", "scripts", "browser-sync", "watch"));

Preparation for production

Resulting code for Gulp 4 will be presented at the end of the article.

For production (building in the dist folder), we will create a separate build task at the end of gulpfile.js. In this instruction we will build Sass, JS and upload what we have ready to the dist folder.

Gulp.task("build", ["sass", "scripts"], function() ( var buildCss = gulp.src([ // Transfer CSS styles to production "app/css/main.css", "app/ css/libs.min.css" ]).pipe(gulp.dest("dist/css")) var buildFonts = gulp.src("app/fonts/**/*") // Transfer fonts to production.pipe (gulp.dest("dist/fonts")) var buildJs = gulp.src("app/js/**/*") // Move the scripts to production.pipe(gulp.dest("dist/js")) var buildHtml = gulp.src("app/*.html") // Transfer HTML to production.pipe(gulp.dest("dist"));

Here, by assigning any actions to variables, we perform them. This way you can perform multitasking tasks. You don’t have to appropriate it, but we’ll do it this way because it’s more beautiful.

Everything is fine, but there is always one “But”. Before assembling the project, it would be advisable for us to clear the dist folder so that there are no unnecessary giblets left from previous iterations with our project.

Install and enable the del package:

Npm i del --save-dev var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync"), // Connect Browser Sync concat = require("gulp-concat"), // Connect gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Connect gulp-uglifyjs (for JS compression) cssnano = require("gulp-cssnano"), // Include the package for CSS minification rename = require("gulp-rename"), // Include the library for renaming files del = require("del"); // Connect the library to delete files and folders

Create a cleanup task clean and add its execution before execution of build:

Gulp.task("clean", function() ( return del.sync("dist"); // Delete the dist folder before building )); gulp.task("build", ["clean", "sass", "scripts"], function() ( var buildCss = gulp.src([ // Move the libraries to production "app/css/main.css", "app/css/libs.min.css" ]) .pipe(gulp.dest("dist/css")) var buildFonts = gulp.src("app/fonts/**/*") // Transfer fonts to production.pipe(gulp.dest("dist/fonts")) var buildJs = gulp.src("app/js/**/*") // Move the scripts to production.pipe(gulp.dest("dist/js ")) var buildHtml = gulp.src("app/*.html") // Transfer HTML to production.pipe(gulp.dest("dist")); ));

For Gulp 4, try creating tasks yourself, as we did in previous examples.

Image optimization

As you may have noticed, our production project lacks images. Let's correct this misunderstanding and add image processing to our project. This section was written using Gulp 3. The code for Gulp 4 can be adapted independently, as we did earlier.

There are 3 images in the app/img folder that we need to move to the production folder by optimizing.


To optimize images, install 2 packages ( gulp-imagemin, imagemin-pngquant) and connect them:

Npm i gulp-imagemin imagemin-pngquant --save-dev var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser -sync"), // Connect Browser Sync concat = require("gulp-concat"), // Connect gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Connect gulp-uglifyjs ( for JS compression) cssnano = require("gulp-cssnano"), // Include a package for CSS minification rename = require("gulp-rename"), // Include a library for renaming files del = require("del"), / / Include the library for deleting files and folders imagemin = require("gulp-imagemin"), // Include the library for working with images pngquant = require("imagemin-pngquant"); // Include the library for working with png

Gulp.task("img", function() ( return gulp.src("app/img/**/*") // Take all images from app .pipe(imagemin(( // Compress them with the best interlaced settings: true, progressive: true, svgoPlugins: [(removeViewBox: false)], use: ))) .pipe(gulp.dest("dist/img")); // Upload to production )); gulp.task("build", ["clean", "img", "sass", "scripts"], function() ( var buildCss = gulp.src([ // Transfer libraries to production "app/css/main .css", "app/css/libs.min.css" ]).pipe(gulp.dest("dist/css")) var buildFonts = gulp.src("app/fonts/**/*") / / Move the fonts to production.pipe(gulp.dest("dist/fonts")) var buildJs = gulp.src("app/js/**/*") // Move the scripts to production.pipe(gulp.dest( "dist/js")) var buildHtml = gulp.src("app/*.html") // Transfer HTML to production.pipe(gulp.dest("dist"));

Everything is fine. As long as the number of images in the project does not exceed 3 pieces. A large number of images will take much longer to process, so it would be a good idea to add a cache to image processing so that the images are cached, saving us time.

Install and connect gulp-cache:

Npm i gulp-cache --save-dev var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync" ), // Connect Browser Sync concat = require("gulp-concat"), // Connect gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Connect gulp-uglifyjs (for JS compression ) cssnano = require("gulp-cssnano"), // Include the package for CSS minification rename = require("gulp-rename"), // Include the library for renaming files del = require("del"), // Include the library to delete files and folders imagemin = require("gulp-imagemin"), // Include the library for working with images pngquant = require("imagemin-pngquant"), // Include the library for working with png cache = require("gulp- cache"); // Connect the caching library

Modifying the task img:

Gulp.task("img", function() ( return gulp.src("app/img/**/*") // Take all images from app .pipe(cache(imagemin(( // Compress them with the best settings taking into account caching interlaced: true, progressive: true, svgoPlugins: [(removeViewBox: false)], use: )))) .pipe(gulp.dest("dist/img")); // Upload to production ));

Automatically Generating CSS Prefixes with Gulp

Vendor prefixes are required to ensure maximum compatibility with all modern browsers. It would be logical to automatically add prefixes, so that by writing in CSS or Sass:

Display:flex

We got the following output:

Display: -webkit-flex; display: -moz-flex; display: -ms-flex; display: -o-flex; display: flex;

Let's install the package gulp-autoprefixer and connect it to gulpfile.js:

Npm i --save-dev gulp-autoprefixer var gulp = require("gulp"), // Include Gulp sass = require("gulp-sass"), // Include the Sass package, browserSync = require("browser-sync" ), // Connect Browser Sync concat = require("gulp-concat"), // Connect gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Connect gulp-uglifyjs (for JS compression ) cssnano = require("gulp-cssnano"), // Include the package for CSS minification rename = require("gulp-rename"), // Include the library for renaming files del = require("del"), // Include the library to delete files and folders imagemin = require("gulp-imagemin"), // Include the library for working with images pngquant = require("imagemin-pngquant"), // Include the library for working with png cache = require("gulp- cache"), // Include the caching library autoprefixer = require("gulp-autoprefixer"); // Include the library for automatically adding prefixes

And we modify our task sass:

Gulp.task("sass", function())( // Create a Sass task return gulp.src("app/sass/**/*.sass") // Take the source.pipe(sass()) // Transform Sass in CSS via gulp-sass .pipe(autoprefixer(["last 15 versions", "> 1%", "ie 8", "ie 7"], ( cascade: true ))) // Create prefixes.pipe(gulp .dest("app/css")) // Upload the result to the app/css folder .pipe(browserSync.reload((stream: true))) // Update the CSS on the page when changed ));

Default Gulp task

Attention! The default task for Gulp 4 is different from the one given in this chapter. The complete code for Gulp 4 can be found at the end of the article.

So, we have 2 main tasks - gulp watch- to work on a project online and gulp build- for assembling a project for production without unnecessary files, folders and compressed images. Since most often we will need a task watch, you can hang it on the default task, so as not to constantly write gulp watch in the console, but simply write gulp.

Gulp.task("default", ["watch"]);

Also, you need to create a standalone task to clear the Gulp cache so that it can be called with a simple command gulp clear:

Gulp.task("clear", function () ( return cache.clearAll(); ))

If you have problems with images or other cached files, simply clear the cache.

As a result, we should get something like this gulpfile.js. Gulp 3:

Var gulp = require("gulp"), // Connect Gulp sass = require("gulp-sass"), // Connect the Sass package, browserSync = require("browser-sync"), // Connect Browser Sync concat = require ("gulp-concat"), // Include gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Include gulp-uglifyjs (for JS compression) cssnano = require("gulp-cssnano" ), // Include a package for CSS minification rename = require("gulp-rename"), // Include a library for renaming files del = require("del"), // Include a library for deleting files and folders imagemin = require(" gulp-imagemin"), // Include the library for working with images pngquant = require("imagemin-pngquant"), // Include the library for working with png cache = require("gulp-cache"), // Include the caching library autoprefixer = require("gulp-autoprefixer");// Include the library to automatically add prefixes gulp.task("sass", function())( // Create a Sass task return gulp.src("app/sass/**/*. sass") // Take the source.pipe(sass()) // Convert Sass to CSS using gulp-sass .pipe(autoprefixer(["last 15 versions", "> 1%", "ie 8", "ie 7 "], ( cascade: true ))) // Create prefixes.pipe(gulp.dest("app/css")) // Upload the results to the app/css folder .pipe(browserSync.reload((stream: true)) ) // Update the CSS on the page when )); gulp.task("browser-sync", function() ( // Create a task browser-sync browserSync(( // Execute browserSync server: ( // Define server parameters baseDir: "app" // Directory for the server - app ), notify: false // Disable notifications )); gulp.task("scripts", function() ( return gulp.src([ // Take all the necessary libraries "app/libs/jquery/dist/jquery.min.js", // Take jQuery "app/libs/magnific -popup/dist/jquery.magnific-popup.min.js" // Take Magnific Popup ]).pipe(concat("libs.min.js")) // Collect them in a heap in a new file libs.min.js .pipe(uglify()) // Compress the JS file.pipe(gulp.dest("app/js")); // Upload to the app/js folder)); gulp.task("css-libs", ["sass"], function() ( return gulp.src("app/css/libs.sass") // Select the file for minification.pipe(sass()) // Convert Sass to CSS with gulp-sass .pipe(cssnano()) // Compress.pipe(rename((suffix: ".min"))) // Add suffix.min .pipe(gulp.dest("app/css ")); // Upload to the app/css folder)); gulp.task("clean", function() ( return del.sync("dist"); // Delete the dist folder before building )); gulp.task("img", function() ( return gulp.src("app/img/**/*") // Take all images from app .pipe(cache(imagemin(( // With caching // . pipe(imagemin(( // Compress images without caching interlaced: true, progressive: true, svgoPlugins: [(removeViewBox: false)], use: )))/**/) .pipe(gulp.dest("dist/img ")); // Upload to production )); gulp.task("build", ["clean", "img", "sass", "scripts"], function() ( var buildCss = gulp.src([ // Transfer the libraries to production "app/css/main.css", "app/css/libs.min.css" ]).pipe(gulp.dest("dist/css")) var buildFonts = gulp.src( "app/fonts/**/*") // Transfer the fonts to production.pipe(gulp.dest("dist/fonts")) var buildJs = gulp.src("app/js/**/*") / / Move the scripts to production.pipe(gulp.dest("dist/js")) var buildHtml = gulp.src("app/*.html") // Move the HTML to production.pipe(gulp.dest("dist" )); gulp.task("clear", function (callback) ( return cache.clearAll(); )); gulp.task("watch", ["browser-sync", "css-libs", "scripts"], function() ( gulp.watch("app/sass/**/*.sass", ["sass"]); // Watching sass files in the sass folder gulp.watch("app/*.html", browserSync.reload); // Monitor HTML files in the project root gulp.watch(["app/js/common.js", "app/libs/**/*.js"], browserSync.reload); // Monitor JS files in the js folder)); gulp.task("default", ["watch"]);

Resulting code for Gulp 4:

Var gulp = require("gulp"), // Connect Gulp sass = require("gulp-sass"), // Connect the Sass package, browserSync = require("browser-sync"), // Connect Browser Sync concat = require ("gulp-concat"), // Include gulp-concat (for file concatenation) uglify = require("gulp-uglifyjs"), // Include gulp-uglifyjs (for JS compression) cssnano = require("gulp-cssnano" ), // Include a package for CSS minification rename = require("gulp-rename"), // Include a library for renaming files del = require("del"), // Include a library for deleting files and folders imagemin = require(" gulp-imagemin"), // Include the library for working with images pngquant = require("imagemin-pngquant"), // Include the library for working with png cache = require("gulp-cache"), // Include the caching library autoprefixer = require("gulp-autoprefixer");// Include the library to automatically add prefixes gulp.task("sass", function() ( // Create a Sass task return gulp.src("app/sass/**/*. sass") // Take the source.pipe(sass()) // Convert Sass to CSS using gulp-sass .pipe(autoprefixer(["last 15 versions", "> 1%", "ie 8", "ie 7 "], ( cascade: true ))) // Create prefixes.pipe(gulp.dest("app/css")) // Upload the results to the app/css folder .pipe(browserSync.reload((stream: true)) ) // Update the CSS on the page when )); gulp.task("browser-sync", function() ( // Create a task browser-sync browserSync(( // Execute browserSync server: ( // Define server parameters baseDir: "app" // Directory for the server - app ), notify: false // Disable notifications )); gulp.task("scripts", function() ( return gulp.src([ // Take all the necessary libraries "app/libs/jquery/dist/jquery.min.js", // Take jQuery "app/libs/magnific -popup/dist/jquery.magnific-popup.min.js" // Take Magnific Popup ]).pipe(concat("libs.min.js")) // Collect them in a heap in a new file libs.min.js .pipe(uglify()) // Compress the JS file.pipe(gulp.dest("app/js")); // Upload to the app/js folder)); gulp.task("code", function() ( return gulp.src("app/*.html") .pipe(browserSync.reload(( stream: true ))) )); gulp.task("css-libs", function() ( return gulp.src("app/css/libs.sass") // Select a file to minify.pipe(sass()) // Convert Sass to CSS using gulp -sass .pipe(cssnano()) // Compress.pipe(rename((suffix: ".min"))) // Add suffix.min .pipe(gulp.dest("app/css")); Upload to the app/css folder)); gulp.task("clean", async function() ( return del.sync("dist"); // Delete the dist folder before building )); gulp.task("img", function() ( return gulp.src("app/img/**/*") // Take all images from app .pipe(cache(imagemin(( // With caching // . pipe(imagemin(( // Compress images without caching interlaced: true, progressive: true, svgoPlugins: [(removeViewBox: false)], use: )))/**/) .pipe(gulp.dest("dist/img ")); // Upload to production )); gulp.task("prebuild", async function() ( var buildCss = gulp.src([ // Transfer libraries to production "app/css/main.css", " app/css/libs.min.css" ]).pipe(gulp.dest("dist/css")) var buildFonts = gulp.src("app/fonts/**/*") // Transfer the fonts to production .pipe(gulp.dest("dist/fonts")) var buildJs = gulp.src("app/js/**/*") // Move the scripts to production.pipe(gulp.dest("dist/js" )) var buildHtml = gulp.src("app/*.html") // Transfer HTML to production.pipe(gulp.dest("dist")); gulp.task("clear", function (callback)); ) ( return cache.clearAll(); )) gulp.task("watch", function() ( gulp.watch("app/sass/**/*.sass", gulp.parallel("sass")); // Watching sass files gulp.watch("app/*.html", gulp.parallel("code")); // Watching HTML files in the project root gulp.watch(["app/js/common.js", "app/libs/**/*.js"], gulp.parallel("scripts")); // Monitoring the main JS file and libraries )); gulp.task("default", gulp.parallel("css-libs", "sass", "scripts", "browser-sync", "watch")); gulp.task("build", gulp.parallel("prebuild", "clean", "img", "sass", "scripts"));

You can look at the example project from this lesson on GitHub and download it: https://github.com/agragregra/gulp-lesson

To install all packages and dependencies for the downloaded example, run the command npm i in the project folder.

Remember - any plugin for Gulp has good documentation on connecting and using it on npmjs.com or on the GitHub page.

Greetings. If you are involved in frontend development, you may have noticed that you often have to perform the same tasks. It would be great to automate all this and reduce the amount of routine to a minimum. Task managers and project assemblers, such as Gulp and Grunt.

Gulp is a fork of the Grunt project. He took the best practices from his parent. The instruction code is written in JavaScript. It works several times faster than Grunt.

Gulp is truly powerful. It will make frontend development easier and faster. I will list the main tasks that the project assembler will help you solve.

  • Creating a Web Server for Debugging
  • Automatically reload pages when changes are made (LiveReload)
  • Tracking changes in project files
  • Using HTML, CSS, JS preprocessors
  • Combining files and minifying them
  • Automatic creation of vendor prefixes for browsers (Autoprefixer)
  • Automation of file and directory management
  • Launching and controlling external operating system commands
  • Launching and controlling applications
  • Image optimization (compression, resizing, etc.)
  • Uploading a project to an external server using FTP, SFTP, Git, etc.
  • Connecting and using additional plugins (today there are already 3570 of them; the solution can be
  • find for almost all everyday routine tasks and more)
  • Automation of manual labor

Installation

Gulp requires Node.js to run. You can download it on the official website. I advise you to install the LTS version of the software platform. After installing Node.js, you can proceed to installing Gulp. To do this, open the operating system console and run the following command:

We use the parameter -g, which allows you to install Gulp globally on the operating system, without being tied to a specific project.

It is important that there are no Russian characters in the path to the installation directory. This may cause some gulp plugins to not work correctly.

Okay, it's time to create a project in which we will use Gulp. Go to the project directory and run the command:

This will launch a script that will ask you some questions about the project. The result will be a configured file for npm package.json. This is the project manifest. It contains a list of packages that are used in the project and other information. At this stage I entered the following data, adapt it to your project.

name: (bybtc-landing) version: (1.0.0) description: Landing Page for byBTC entry point: (index.js) test command: git repository: https://github.com/Neuropassenger/bybtc-landing.git keywords : landing

If you want to skip a question, just press Enter. The default value will be used. Now we can install Gulp for our project. Run the command:

npm i --save-dev gulp

Gulp will be installed in the project directory, and the parameter –save-dev will add it to package.json dependency. This will allow another developer who opens your project to quickly deploy it on their machine (using the command npm i).

If everything went well, then a directory should appear in the project folder node_modules. It contains the installed package gulp and all the dependencies needed for it to work.

It's time to create the basic structure of the project. I stick to the same directory names as many developers. I advise you to do this too, so that another person can quickly understand the structure of your project. However, no one forbids you to use the names you want.

Create two folders in the project root:

  • /src/ – the source code of the project during development, this is where you will edit the files
  • /dist/ – project files and folders after assembly, finished product

Catalog /dist/ will be filled in automatically when building the project. Let's get on with it for now /src/. Create the following folders inside:

  • /css/ – for cascading style sheets
  • /js/ – for JavaScript scripts
  • /img/ – for images
  • /fonts/ – for fonts
  • /sass/ – for SASS preprocessor files (if you use SASS)
  • /libs/ – for third-party libraries

If everything is ready, then it's time to move on to creating the file gulpfile.js in the root of the project, which will help you configure Gulp. This is where you can create Gulp instructions that will help automate some of the mundane tasks.

Gulp Instructions

Any instruction is created in gulpfile.js using the function gulp.task(). The first parameter is the name of the instruction. Then there is an array of the names of instructions that must be executed before the defined instruction is executed. The last parameter is a function whose body defines what the instruction does.

gulp.task("instruction_name", ["instruction_executed_before_the_current", "another_instruction"], function() ( // Some actions ));

To call the instruction, use the following command in the console:

gulp command_name

Compiling SASS to CSS

Let's start with compiling SASS to CSS. Install the gulp-sass package:

npm i --save-dev gulp-sass

First you need to connect the packages you use to gulpfile.js. Let's do it:

var gulp = require("gulp"), sass = require("gulp-sass");

Now let's create a statement that will compile SASS to CSS:

gulp.task("sass", function() ( return gulp.src("src/sass/**/*.sass") .pipe(sass()) .pipe(gulp.dest("src/css") ); ));

In the first line of the instructions we indicate the source files for compilation. In a specific example, all files with the extension will be taken .sass located inside the folder /src/sass/ and its subfolders. You can also select specific files. Here is a sample list of how you can set paths to source files.

  • src/sass/main.sass – select the main.sass file
  • src/sass/*.sass – selects all files with the sass extension
  • src/sass/**/*.sass – selects all files with the sass extension in all subfolders in the sass folder
  • !src/sass/main.sass – main.sass file exception
  • [‘!src/sass/main.sass’, ‘src/sass/second.sass’] – exclusion of an array of files main.sass and second.sass
  • src/sass/**/*.+(scss|sass) – select all scss and sass files in all subfolders in sass

Now create in the folder /src/sass/ file main.sass and define some styles in it:

body color: red font-size: 20px

Save the file. Now we can check how the compilation works. In the console we run the command:

Checking the catalog /src/css/. It should contain the newly compiled CSS file. Do you see? Great! Let's move on.

Automatic page refresh (LiveReload)

Let's move on to automating page updates when they change, i.e. let's set it up LiveReload. This is one of the most popular tasks facing. We will need the npm package Browsersync to automatically update the browser. Let's install it:

npm i --save-dev browser-sync

Let's connect browser-sync package at the beginning gulpfile.js, as we did earlier with packages gulp And gulp-sass:

browserSync = require("browser-sync");

Let's create instructions for launching Browsersync:

gulp.task("browser-sync", function() ( browserSync(( server: ( baseDir: "src" ) )); ));

All we did was call Browsersync to start and specify the project directory with the source files. There are other settings for Browsersync. You can find out about them in the documentation.

Let's add one more pipe to instructions sass, which will be used to update styles when compiling CSS files. Specify the parameter stream: true. This will allow you to update the styles streaming, without completely reloading the page.

Pipe(browserSync.reload(( stream: true; )))

Then we will create an instruction that will monitor changes in files and reload the page if necessary.

gulp.task("watch", ["browser-sync"], function() ( gulp.watch("src/sass/**/*.sass", ["sass"]); gulp.watch("src /js/**/*.js", browserSync.reload); gulp.watch("src/**/*.html", browserSync.reload); ));

Let me explain. The instructions are executed before starting browser-sync, i.e. The web server starts to debug the project. After this the instruction itself is executed watch. To track changes in files we use gulp.watch().

Inside the anonymous function we execute 3 times gulp.watch with two parameters. The first parameter is the files that need to be monitored, the second is the actions that need to be performed when files change, i.e. follow instructions sass or refresh the page.

Pay attention to the first one gulp.watch. Instead of browserSync.reload we pass the instruction in the array sass, which must be executed if the files have been changed. In it, as you remember, we stream-update the styles on the page.

Minification and merging of files

Almost any project has to use third-party libraries. Their number can be from 5 to infinity. Accordingly, all of them must be included in the finished product. It would be nice to optimize this whole thing, namely:

  • minify (compress) used libraries
  • reduce the number of requests to the server by combining libraries into a single file

Let's add several libraries to the project source files. For this I use Bower, package for NPM. Install Bower:

Create a configuration file .bowerrc in the root of the project for Bower, where we tell it where to save the libraries:

("directory": "src/libs/" )

Let's install, for example, the library jQuery and slider slick:

bower i jquery slick-carousel

Now we can start concatenating and compressing libraries. For this we will use packages gulp-concat And gulp-uglifyjs regarding JavaScript files. Let's install them:

npm i --save-dev gulp-concat gulp-uglifyjs

Regarding CSS – package gulp-cssnano. Install:

npm i --save-dev gulp-cssnano

Minified files usually have the suffix .min. The package will help us add it gulp-rename. Install:

npm i --save-dev gulp-rename

Let's start by connecting the installed plugins to gulpfile.js:

concat = require("gulp-concat"), uglifyJs = require("gulp-uglifyjs"), cssNano = require("gulp-cssnano"), rename = require("gulp-rename");

JavaScript

Let's create an instruction that will allow us to compress and merge JavaScript files:

gulp.task("min-js", function() ( return gulp.src([ "src/libs/jquery/dist/jquery.min.js", "src/libs/slick-carousel/dist/slick.min .js" ]) .pipe(concat("libs.min.js")) .pipe(uglifyJs()) .pipe(gulp.dest("src/js")); ));

Inside an anonymous function statement min-js We first specify the paths to the JavaScript library files as an array. Then using concat we combine the libraries into a single file libs.min.js uglifyJs. And finally, save the result to a folder /src/js/.

The instructions can be checked using the command in the console:

In folder /src/js/ the file will appear libs.min.js, which combines and compresses the JavaScript library files used in the project.

CSS

Let's create it in the catalog /src/css/ file libs.sass. We will import CSS library files into it. For example, using Bower I downloaded the library Bootstrap:

bower i bootstrap

Let's open the file libs.sass and import the Bootstrap CSS file into it:

@import "src/libs/bootstrap/dist/css/bootstrap"

Thus, we will collect all the CSS library files in one place, namely in the file libs.sass using import. Now let's create a compression instruction:

gulp.task("min-css", ["sass"] , function() ( return gulp.src("src/css/libs.css") .pipe(cssNano()) .pipe(rename(( suffix: ".min" ))) .pipe(gulp.dest("src/css"));

Before compression we compile the CSS from SASS using the instruction sass, which we indicated in the array after the instruction name min-css.

In the first line we take a specific file, libs.css. Next, we compress it using cssNano. Then using rename add a suffix .min. We save the result in a folder /src/css/.

Checking the instructions:

If you did everything correctly, then in the folder /src/css/ two files should appear. libs.css And libs.min.css. Compare their sizes.

Automatically adding vendor prefixes (Autoprefixer)

When using new CSS features, you must set vendor prefixes for styles to work correctly. Doing such things manually is a thankless task. So let's get Gulp to do it for us.

First let's install gulp-autoprefixer:

npm i --save-dev gulp-autoprefixer

Let's connect the installed package to gulpfile.js:

autoprefixer = require("gulp-autoprefixer");

Okay, now we can use autoprefixer in the instructions sass. Let's do it after the call .pipe(sass()), because vendor prefixes need to be placed after SASS is converted to CSS. Let's add a new one pipe:

Pipe(autoprefixer([ "last 10 versions" ], ( cascade: true )))

The first parameter autoprefixer we pass an array in which we indicate that we want to enable support for the latest 10 browser versions. The second parameter is the settings, where we indicate that we want to see beautiful code in the output, i.e. enable cascading.

We check by adding to main.sass new property flex. Run the instructions sass:

IN main.css vendor prefixes should appear. It's very simple, everything works automatically. Amazing!

Final build of the project

The last thing I would like to touch on in this guide for Gulp beginners is the final build of the project. For this we need a folder /dist/, which we created at the very beginning. It must be cleaned before each assembly. For this we will use the NPM package del. Let's install it:

npm i --save-dev del

Let's connect the package del V gulpfile.js:

del = require("del");

Let's create instructions clean to clean up the directory / dist/ before assembly:

gulp.task("clean", function() ( return del.sync("dist"); ));

Now you can start directly assembling the project. Let's create instructions build:

gulp.task("build", ["clean", "min-css", "min-js"], function() ( var buildCss = gulp.src([ "src/css/libs.min.css", "src/css/main.css" ]).pipe(gulp.dest("dist/css")); var buildFonts = gulp.src("src/fonts/**/*") .pipe(gulp.dest ("dist/fonts")); var buildJs = gulp.src("src/js/**/*") .pipe(gulp.dest("dist/js")); var buildHtml = gulp.src(" src/*.html") .pipe(gulp.dest("dist")); ));

Before calling instructions build we are clearing the folder /dist/ in case the assembly has already been carried out before. Then we compress and merge JavaScript and CSS files using the instructions min-js And min-css respectively. At the same time, we compile SASS to CSS, because before following instructions min-css instruction is executed sass.

Inside the body of the instruction, we copy the prepared project files to the directory with the finished product /dist/. Let's check the instructions:

Everything works great! In folder /dist/ Now there is a finished product after assembly, which can be uploaded to the production server.

Conclusion

This concludes the guide for beginners on assembling projects in Gulp. As you can see, everything is quite simple. Over time I will publish a few more posts regarding Gulp and its plugins, once I have a good understanding of them myself. In the meantime, use and automate your routine tasks in frontend development according to the instructions provided. If you have any questions, ask them in the comments to the post.

( "name": "bybtc-landing", "version": "1.0.0", "description": "Landing Page for byBTC", "main": "index.js", "scripts": ( "test" : "echo \"Error: no test specified\" && exit 1" ), "repository": ( "type": "git", "url": "git+https://github.com/Neuropassenger/bybtc- landing.git" ), "keywords": [ "landing" ], "author": "Oleg Sokolov", "license": "ISC", "bugs": ( "url": "https://github.com /Neuropassenger/bybtc-landing/issues" ), "homepage": "https://github.com/Neuropassenger/bybtc-landing#readme", "devDependencies": ( "browser-sync": "^2.18.13" , "del": "^3.0.0", "gulp": "^3.9.1", "gulp-autoprefixer": "^4.0.0", "gulp-concat": "^2.6.1", " gulp-cssnano": "^2.1.2", "gulp-rename": "^1.2.2", "gulp-sass": "^3.1.0", "gulp-uglifyjs": "^0.6.2" ) )

var gulp = require("gulp"), sass = require("gulp-sass"), browserSync = require("browser-sync"), concat = require("gulp-concat"), uglifyJs = require("gulp- uglifyjs"), cssNano = require("gulp-cssnano"), rename = require("gulp-rename"), autoprefixer = require("gulp-autoprefixer"), del = require("del"); gulp.task("sass", function() ( return gulp.src("src/sass/**/*.sass") .pipe(sass()) .pipe(autoprefixer([ "last 10 versions" ], ( cascade: true ))) .pipe(gulp.dest("src/css")) .pipe(browserSync.reload(( stream: true ))); gulp.task("min-css", ["sass"] , function() ( return gulp.src("src/css/libs.css") .pipe(cssNano()) .pipe(rename(( suffix: ".min" ))) .pipe(gulp.dest("src/css")); gulp.task("min-js", function() ( return gulp.src([ "src/libs/jquery/dist/jquery.min.js", "src/libs/slick-carousel/dist/slick.min .js" ]) .pipe(concat("libs.min.js")) .pipe(uglifyJs()) .pipe(gulp.dest("src/js")); )); gulp.task("browser-sync", function() ( browserSync(( server: ( baseDir: "src" ) )); )); gulp.task("watch", ["browser-sync"], function() ( gulp.watch("src/sass/**/*.sass", ["sass"]); gulp.watch("src /js/**/*.js", browserSync.reload); gulp.watch("src/**/*.html", browserSync.reload); )); gulp.task("clean", function() ( return del.sync("dist"); )); gulp.task("build", ["clean", "min-css", "min-js"], function() ( var buildCss = gulp.src([ "src/css/libs.min.css", "src/css/main.css" ]).pipe(gulp.dest("dist/css")); var buildFonts = gulp.src("src/fonts/**/*") .pipe(gulp.dest ("dist/fonts")); var buildJs = gulp.src("src/js/**/*") .pipe(gulp.dest("dist/js")); var buildHtml = gulp.src(" src/*.html") .pipe(gulp.dest("dist")); ));

Installing Gulp is quite simple. First, install the Gulp package globally:

Npm install -g gulp

Then install it in your project:

Npm install --save-dev gulp

Using Gulp

Let's create a Gulp task to minify one of our JavaScript files. Create a file called gulpfile.js. It will define your tasks, which are launched using the gulp command.

Add the following commands to your gulpfile.js file:

Var gulp = require("gulp"), uglify = require("gulp-uglify"); gulp.task("minify", function () ( gulp.src("js/app.js") .pipe(uglify()) .pipe(gulp.dest("build")) ));

Install gulp-uglify via npm by running npm install --save-dev gulp-uglify and then run the task via gulp minify. Let's say you have a file called app.js in the js folder, a new app.js will be created in the build folder and contain a compressed version of js/app.js.

What's really going on here?

We do several things in our gulpfile.js file. First we load the gulp and gulp-uglify modules:

Var gulp = require("gulp"), uglify = require("gulp-uglify");

We then define a task called minify, which when run calls the function given as its second argument:

Gulp.task("minify", function () ( ));

Finally, and this is the hard part, we define what our task should do:

Gulp.src("js/app.js") .pipe(uglify()) .pipe(gulp.dest("build"))

If you're not familiar with threads, and most front-end developers aren't, the code above won't tell you anything.

Streams

Streams allow some data to pass through a series of typically small functions that modify the data and then pass it on to the next function.

In the example above, the gulp.src() function takes a string that matches a file or set of files and creates a stream of objects representing those files. They then pass (or flow) into the uglify() function, which takes file objects and returns new minified file objects. This result is then passed into the gulp.dest() function, which saves the modified files.

Here's what happens in diagrammatic form:

When there is only one task, the function does nothing. However, consider the following code:

Gulp.task("js", function () ( return gulp.src("js/*.js") .pipe(jshint()) .pipe(jshint.reporter("default")) .pipe(uglify() ) .pipe(concat("app.js")) .pipe(gulp.dest("build"));

To run this yourself, install gulp, gulp-jshint, gulp-uglify and gulp-concat.

This task takes all the files corresponding to js/*.js (in other words, all the JavaScript files in the js folder), runs JSHint on them, prints a report, minifies each file, and then merges them, storing them in build/app.js. In diagram form:

If you're familiar with Grunt, you'll notice that this is quite different from how Grunt works. Grunt doesn't use threads. Instead, it takes the files, runs one task for each file, and saves to new files, repeating the entire process for each task. As a result of many file system calls, Grunt is slower than Gulp.

For a better understanding of streams, read the Stream Handbook.

gulp.src()

The gulp.src() function takes one or more files or an array and returns a stream that can be passed to plugins.

The other two plugins are clearer: the uglify() function minifies the code, and the concat("app.js") function combines all files into one called app.js.

gulp-load-plugin

A module that I find quite useful is called gulp-load-plugins, it automatically loads any Gulp plugins from the package.json file and attaches them to the object. The main application is as follows:

Var gulpLoadPlugins = require("gulp-load-plugins"), plugins = gulpLoadPlugins();

You can write everything on one line ( var plugins = require("gulp-load-plugins")();), but I'm not a big fan of the one-line require call.

After running this code, the plugins object will contain your plugins with CamelCase-style names (for example, gulp-ruby-sass will be loaded as plugins.rubySass ). You can use them in the usual way. For example, our js task would be shortened like this:

Var gulp = require("gulp"), gulpLoadPlugins = require("gulp-load-plugins"), plugins = gulpLoadPlugins(); gulp.task("js", function () ( return gulp.src("js/*.js") .pipe(plugins.jshint()) .pipe(plugins.jshint.reporter("default")) .pipe (plugins.uglify()) .pipe(plugins.concat("app.js")) .pipe(gulp.dest("build"));

Attached to this is a package.json file that contains something similar to this:

( "devDependencies": ( "gulp-concat": "~2.2.0", "gulp-uglify": "~0.2.1", "gulp-jshint": "~1.5.1", "gulp": " ~3.5.6" ) )

This example is actually not much shorter. However, for large and complex Gulp files, this will reduce the file upload block to one or two lines.

Version 0.4.0 of gulp-load-plugins released in early March added lazy loading of the plugin which improves performance. Plugins aren't loaded until they're called, meaning you won't have to worry about unused plugins in package.json impacting performance (although they should probably be removed anyway). In other words, if you run a task that only requires two plugins, it will not load all the plugins that other tasks require.

File tracking

Gulp has the ability to watch for file changes and execute a task or tasks when changes are detected. This feature is amazingly useful (probably one of the most useful in Gulp for me). You can save the Less file and Gulp will turn it into CSS and update the browser without any action on your part.

To watch a file or files, use the gulp.watch() function, which takes a pattern of files or an array of them (such as gulp.src()), or an array of tasks to run them or execute a callback function.

Let's say we have a build task that turns our template files into HTML and we want to define a watch task that watches for changes to the templates and runs a task to convert them to HTML. We can use the watch function like this:

Gulp.task("watch", function () ( gulp.watch("templates/*.tmpl.html", ["build"]); ));

Now, when you change the template file, the build task will be run, which will create the HTML.

You can also give watch a callback function instead of an array of tasks. In this case, the function receives an event object containing information about the event that called the function:

Gulp.watch("templates/*.tmpl.html", function (event) ( console.log("Event type: " + event.type); // added, changed or deleted console.log("Event path: " + event.path); // path to the file ));

Another distinctive feature of gulp.watch() is that it returns a watcher . Use it to listen for additional events or to add files to your watch. For example, to run a task list and call a function at the same time, you could add a listener to the change event when watcher returns:

Var watcher = gulp.watch("templates/*.tmpl.html", ["build"]);

In addition to the change event, you can listen to a number of other events:

  • end
    Fires when the watcher terminates (meaning tasks and callbacks will no longer be called when files change).
  • error
    Fired when an error occurs.
  • ready
    Fires when files have been found and are ready to be tracked.
  • nomatch
    Fires when no files match the request.

The watcher object also contains some methods that can be called:

  • watcher.end()
    Stops the watcher (no more tasks or callbacks will be called).
  • watcher.files()
    Returns a list of files that the watcher is monitoring.
  • watcher.add(glob)
    Adds files to the watcher that match the specified glob pattern (also takes an optional callback function as the second argument).
  • watcher.remove(filepath)
    Removes a specific file from watcher.
December 13, 2017 at 5:40 pm

We understand and work with gulp

  • JavaScript

Hi all. If you are in any way connected with JS, you have probably heard about such an application as gulp. And perhaps they even used it. From my own experience, I can say that it can be difficult to “get the hang of” how to work with it, although the key to understanding lies on the surface. That’s why I’m publishing this material, hoping that it will be useful.

Also, a video was made based on this material, so you can choose in what form to consume it.


If you compare gulp with other popular assembly systems, it’s like comparing a ready-made quadcopter of the “bought and flew” type, and a kit for self-assembly of a drone. Yes, you won’t take off until the next day, but your hands have more flexibility and control, especially if you have a non-standard task.

In fact, after overcoming the entry threshold, gulp does not look so complicated, and at times it is even understandable and logical. But, without proper preparation, reaching such a state can be difficult. Let's dive right into it and look at the principles on which gulp is built.

Let's come from afar. In the nodejs ecosystem, there is such a thing as threads, or stream. Due to the complexity of translation, threads are also called threads of a multi-threaded program. In our case, a stream is an object representing streaming data, and is a completely different concept.

So, these streams offer a convenient interface for asynchronously working with data. The entire reading/writing process is handled by the node engine, and we only have the corresponding callbacks when a new piece of data has appeared, when an error has occurred, when the flow has ended, etc. This achieves I/O efficiency with minimal effort on the part of the programmer.

Const fs = require("fs"); const input = fs.createReadStream("myfile"); input.on("data", (chunk) => ( console.log(chunk); )); input.on("end", () => ( console.log("file is read"); ));
Almost anything can be streams in nodejs, from files or strings to sockets. For example, in the famous Express framework, HTTP request and response are nothing more than streams. Streams can be read-only, write-only, or both.

Streams have one useful function: they can be stacked together in a chain called a pipe. Thus, we can combine several threads with each other and manage them as one. The output of one thread goes to the input of the next and so on until the end. As you can guess from the translation of the word pipe, it is very similar to a pipeline.

This allows you to determine the required data flow (again the difficulty of translation. Here we mean flow, or current) right here and now without waiting for the data to become available.

For example, this is how we can determine what we want to give as a result, and the “how” of giving is already dealt with by the engine itself.

Const fs = require("fs"); const express = require("express"); var app = express(); app.get("/", function (req, res) ( fs.createReadStream("myfile") .pipe(res); )); app.listen(3000);
Please note that the request handler completes before the file is even opened - the rest is taken care of by the node engine.

Gulp is built on a similar approach. This is its advantage, but it is also its disadvantage. At the very least, it can be considered a disadvantage due to the confusion that arises, since gulp uses other, similar, but incompatible threads. Gulp works closely with the file system, which is why it uses streams, which represent not so much a stream of data, but individual virtual files, each with its own content.

If you've ever heard of vinyl, this is exactly the implementation of threads that gulp uses. If we take a standard task for galp and look at what’s inside, we’ll find that for every call to the data event we receive a file object, which contains all the necessary information: the file name, the path to the file, the working directory and, of course, its content.

Const gulp = require("gulp"); gulp.task("default", function() ( gulp.src("./*.js") .on("data", function(file) ( console.log("data callback"); console.log( file.inspect()); /* It outputs: * data callback * > * data callback * > */ )).pipe(gulp.dest("dist/")); ));
The content can be presented in two formats: as an already read buffer, or as a native node stream. Each stage of the galp pipe takes such files as input, does some kind of transformation and passes it on to the output of the next chain. The last chain usually just saves them to disk.

Pipe(gulp.dest("dist/"));
Realizing that the threads in gulp are different leads to enlightenment and understanding as it explains most of the problems and errors.

Let's look at a real example. You want to use browserify to merge your JS files. You go and find the gulp-browserify plugin. But you see a note that says that the plugin is deprecated, i.e. Outdated.

As a well-mannered programmer, you reject this option and go looking for what solution is not outdated. Find the official recipes from gulp, and you will see that browserify works with gulp directly. Well, directly, through the layer, which just converts the native node stream into a vinyl stream that gulp understands. Without it, nothing would work, since these are different threads.

If you want to write your own transformation, you can use this template.
As you can see, everything is simple here: our handler will be called for each file, which will perform the modifications. We can do whatever we want: change the contents of the file, rename the file, delete the file, or add a couple more new files to the stream.

As we remember, the contents of a file in a vinyl stream can be represented as a buffer or as a data stream. However, it is not necessary to support both. You can always use the package

  • Translation

This article is the first in a series on the topic of taming CSS. Today we will look at technology CSS Reset.

Why is this necessary?

Each browser sets its own default style values ​​for various HTML elements. Using CSS Reset we can level out this difference to ensure cross-browser compatibility of styles.

For example, you use the element a in your document. Most browsers, like Internet Explorer and Firefox, add a link Blue colour And underlining. However, imagine that five years from now someone decides to create a new browser (let's call it UltraBrowser). The browser developers didn't like the blue color and were annoyed by the underline, so they decided to highlight links in red And bold. It is based on this that if you set the base style value for an element a, then it is guaranteed to be the way you want it to be, and not how the UltraBrowser developers prefer to display it.

But now we have no indents at all, including between individual paragraphs! What to do? Don’t lie and don’t be afraid: below our reset we will describe the rule we need. This can be done in different ways: specify the indent at the bottom or top of the paragraph, specify it in percentage, pixels or em.

Most importantly, the browser now plays by our rules, and not we by its rules. I decided to do it this way:

* ( margin: 0; padding: 0; ) p ( margin: 5px 0 10px 0; )

As a result, we got what can be seen in the third example.

You can create your own reset styles if you are solving a specific problem in your project. Despite this, there is no step-by-step guide for creating your own CSS Reset. Rely on your own principles and your own style.

To help you make the right choice, here are a couple more links:

  1. Less is more - my choice of Reset CSS (Ed Elliott).

2. Your CSS Reset is the first thing the browser should see

Resetting styles after setting your own styles for elements is the wrong approach. In this case, you should not expect anything good from the browser display. Remember that you should always include CSS Reset first, and then all other styles.

Yes, I understand, it sounded funny, but this is one of the main mistakes of developers, young and old. Many people simply forget about this.

Some may ask a logical question: why is this happening? The answer is simple: rules written lower in the text of the CSS file (and even lower in their order in the document) overwrite the rules declared earlier.

Let's not go too far off topic and continue. Let's apply Eric Meyer's styles to our example, but after descriptions of our properties, as shown in example 4. Mathematicians would say the following: “That’s what we needed to prove.”

3. Use a separate CSS document for CSS Reset

I must (no, I was by no means forced) to mention this advice. Using a separate file for CSS Reset is a common practice supported by a large number of developers.

In fact I take the position of creation one large CSS file due to the higher performance of this approach. But on this issue I am inclined to agree with the majority: CSS Reset should be placed in a separate file (usually called reset.css). In this case, you can use it in different projects without making any effort to separate it from other CSS rules.

4. Try to avoid using a universal selector

Although this concept works, its use is often not desirable due to incompatibility with some browsers (for example, this selector is not processed correctly in Internet Explorer). You should only use this technique for simple, small, static and predictable pages (if you had to do that).

This advice is especially important when you are developing solutions such as CMS themes. You cannot predict in advance how it will be used or how it will be modified. It is better to describe fundamental CSS rules for all elements than to use the unpredictable (albeit smaller) mechanism of universal selectors for this purpose.

5. Avoid Redundant Property Descriptions When Using CSS Reset

Another reason I don't like a separate file for CSS Reset is the potential redundancy of subsequent CSS property declarations. Repeating individual styles of yours among the entire set of CSS files is bad manners and should be avoided. Of course, sometimes we are too lazy to painstakingly go through a set of styles and combine some of them, but we should at least try!

Let's go back to Eric's CSS Reset. It sets default values ​​for the element's line-height, color and background body in the following way:

body ( line-height: 1; color: black; background: white; )

Let's say you already know what the element will look like body:
  1. background-color: #cccccc;
  2. color: #996633;
  3. You want to repeat a certain background image horizontally.

In this case, there is no need to create a new selector to describe your properties - you can simply include them in the CSS Reset. Let's do it:

body ( line-height: 1; color: #996633; background:#ccc url(tiled-image.gif) repeat-x top left; )

Don't be afraid to modify the CSS Reset itself. Adapt it to yourself, make it work for you. Change, rearrange, remove and add as needed in your specific case.

Eric Meyer said the following about this: “this is not a case where everyone should use CSS Reset without changes.”