Project build depending on gulp. We deal with the assembly of the front end on Gulp. Build of static images

Compression of images, JS and CSS files in order to optimize the loading of web pages and much more. To simplify this process, we suggest you use the Gulp 4 project build, which Andrey Gorokhov is constantly improving. Download links will be presented below, but for now let's go through the main points: description and installation.

Gulp Project Builder

Gulp is a project builder, a tool for automating the tasks described above. It will help you speed up your work and competently prepare the project for release.

You can download the assembly from the Github repository or through the Git command line. In the future, you can customize it to suit your needs.

Peculiarities

  • BEM class naming
  • BEM structure is used
  • SCSS preprocessor is used
  • uses the Babel transpiler to support modern JavaScript (ES6) in browsers
  • used by Webpack to build JavaScript modules
  • CSS-grid smart-grid based on Bootstrap is used for fast adaptive layout
  • hard code is used

Installation

  • install NodeJS (if required) and Yarn
  • download the build with Git : git clone https://github.com/andreyalexeich/gulp-scss-starter.git
  • install gulp globally: yarn global add gulp-cli
  • go to the downloaded build folder: cd gulp-scss-starter
  • download required dependencies: yarn
  • to get started, enter the command: yarn run dev (development mode)
  • to build the project, type yarn run build (build mode)

If you did everything correctly, you should have a browser with a local server open. The build mode involves project optimization: image compression, minification of CSS and JS files for uploading to the server.

If you have problems installing, then watch this video:

File structure

gulp-scss-starter ├── dist ├── gulp-tasks ├── src │ ├── blocks │ ├── fonts │ ├── img │ ├── js │ ├── styles │ ├── views │ └── .htaccess ├── gulpfile.babel.js ├── webpack.config.js ├── package.json ├── .babelrc.js ├── .bemrc.js ├── .eslintrc.json ├─ ─ .stylelintrc ├── .stylelintignore └── .gitignore
  • Folder root:
    • .babelrc.js - Babel settings
    • .bemrc.js - BEM settings
    • .eslintrc.json - ESLint settings
    • .gitignore - prevent Git from tracking files
    • .stylelintrc - Stylelint settings
    • .stylelintignore - prevent Stylelint from tracking files
    • gulpfile.babel.js - Gulp settings
    • webpack.config.js - Webpack settings
    • package.json - list of dependencies
  • src folder - used during development:
    • BEM blocks: src/blocks
    • fonts: src/fonts
    • images: src/img
    • JS files: src/js
    • site pages: src/views/pages
    • SCSS files: src/styles
    • HTML files: src/views
    • Apache web server configuration file with gzip settings (lossless compression): src/.htaccess
  • The dist folder is the folder from which the local development server is launched (when running yarn run dev)
  • gulp-tasks folder - folder with Gulp-tasks

Teams

  • yarn run lint:style - Check SCSS files. VSCode requires the plugin to be installed. For WebStorm or PHPStorm, Stylelint must be enabled in Languages ​​& Frameworks - Style Sheets - Stylelint (errors will be fixed automatically when the file is saved)
  • yarn run lint:style --fix - fix errors in SCSS files
  • yarn run dev - launch the server for project development
  • yarn run build - build a project with optimization without starting the server
  • yarn run build views - compile Pug files
  • yarn run build styles - compile SCSS files
  • yarn run build scripts - build JS files
  • yarn run build images - build images
  • yarn run build webp - convert images to .webp format
  • yarn run build sprites - collect sprites
  • yarn run build fonts - build fonts
  • yarn run build favicons - build favicons
  • yarn run build gzip - build Apache configuration

Component approach to website development

  • Each BEM block has its own folder inside src/blocks/modules
  • the folder of one BEM block contains one HTML file, one SCSS file and one JS file (if the block uses a script)
    • The block HTML file is imported into the src/views/index.html file (or into the necessary page file from which the block will be called)
    • Block SCSS file is imported into src/blocks/modules/_modules.scss file
    • Block JS file is imported to src/js/import/modules.js

An example of a folder structure with a BEM block:

Blocks ├── modules │ ├──header │ │ ├── header.html │ │ ├── header.js │ │ ├── header.scss

In order not to manually create the corresponding folder and files, it is enough to write the command bem create my-block in the console - to create a BEM block folder, where my-block is the name of the BEM block

Project pages

  • project pages are in src/views/pages folder
    • main page: src/views/index.html

Fonts

  • fonts are in src/fonts folder
    • use .woff and .woff2 formats
    • fonts are included in the src/styles/base/_fonts.scss file
    • you can convert local fonts using this service

Images

  • the images are in the src/img folder
    • the image for generating favicons must be located in the src/img/favicon folder and have a size of at least 1024px x 1024px
    • images are automatically converted to .webp format. Detailed information on usage.

Third Party Libraries

  • all third-party libraries are installed in the node_modules folder
    • to load them, use the command yarn add package_name
    • to include JS files of libraries, import them at the very beginning of the JS file of the BEM block (that is, the BEM block that the script uses), for example:

    import$from jquery;

    • to include library style files, import them into the src/styles/vendor/_libs.scss file
    • JS files and style files of libraries cannot be changed independently

⚠️ If your project uses several libraries that need to be included on several pages, in order to avoid errors, you need to:

  • along the path src/js/import create a folder pages
  • in the pages folder, create a js file for the page, for example, pageA.js , and import the library there, which will be used only on this page
    • do the same step for additional pages
  • in the webpack.config.js file, add page js files to the entry point, example:

Entry: (main: "./src/js/index.js", pageA: "./src/js/import/pages/pageA.js", pageB: "./src/js/import/pages/pageB.js" }

  • include compiled js files on required pages

CSS smart-grid

The faucet includes the smart-grid CSS by Dmitry Lavrik. It allows you to get rid of unnecessary classes in the markup by using mixins in SCSS and speeds up adaptive layout. The configuration is already set up according to the Bootstrap grid. Usage example:

Items ( @include row-flex (); @include md (justify-content , center ); .item ( @include col (); @include size (3 ); @include size-md (5 ); @include size- xs(10); ) )

In those days when sites were small, there was no need for a separate front-end build. However, the volume and complexity of CSS and JS has increased, and the view in which it is convenient to develop has become very different from the view in which you need to show the result to the user. Tasks such as concatenation (gluing) of files, minimization of code, and even pre-compilation appeared. The result of this was specialized front-end build systems, which we will talk about.

Of course, as soon as the need for assembly became tangible, the tools used by the backend immediately began to crawl to the frontend. Their main problem and the reason that at the moment they are being used less and less for the front-end is that they are completely not tailored to its specifics, since the project structure, the technologies used and the development cycle are very dependent on the tasks of the project and can differ significantly. The same Ant, for example, has a verbose syntax and is not particularly able to do things necessary for the frontend: there are very few built-in tasks, and it expands poorly. If we talk about GNU make, then it is much more versatile, since it operates with shell commands. Among the disadvantages, it is necessary to mention the special syntax that needs to be further studied, the need to know the shell well, as well as the tendency for the Makefile to quickly become more complex as the assembly requirements increase.

Let's look at a medium-sized site with a standard structure and try to list the main build steps that it goes through. For the sake of simplicity, let's assume that you don't bother with creating different JS files for different pages, but you want to keep a few small files in your development environment to support some kind of modularity. It usually looks something like this:

/libs/ jquery.min.js underscore.min.js /js/ common.js carousel.js popups.js ....

The build system usually does the following:

  • concatenates all JS files into one (in the right order, we don't want to load our scripts before jQuery);
  • checks the JS code for validity (for example, using JSHint);
  • minimizes the code, obfuscates it if necessary (that is, makes it incomprehensible);
  • concatenates CSS files (the order is also important here, since properties are often redefined);
  • minify CSS;
  • puts the files in a separate directory, from which you include them in your HTML.

Often this simple scheme is complicated by additional requirements: tests are run, CSS preprocessor code is compiled, images are optimized, templates are compiled.

All these tasks, and even more, can be solved by modern assembly tools. We will consider the most popular solutions that work on the Node.js platform. Their common advantage is a clear language that all front-end developers know (or think they know), an initial focus on solving front-end problems, and a clear Node.js environment in which you may already be developing your application.

Grunt

Grunt is the oldest, most important and most popular build tool. Almost all of the build systems we've looked at compare themselves to Grunt in one way or another, and some have emerged as faster or simpler alternatives to it. Despite this, it has a couple of significant drawbacks.

First, as many front-end developers point out, Grunt is verbose. To set up a simple build system, you need a config for a hundred lines. However, this in itself is not such a disadvantage: the config is quite easy to read, and due to the popularity of Grunt, finding a ready-made config for a typical task is usually not difficult.

Secondly, Grunt was developed as a universal product, that is, on its basis, you can solve almost any task related to building a project. It's cool, but you have to pay for versatility. As mentioned verbosity, and speed. Compared to other Node.js build systems, Grunt is noticeably slower, and, most frustratingly, tends to slow down as the project grows. Without going into the details of Grunt's architecture, the reason lies in the fact that every time you need to build, for example, a JS file, it rebuilds all JS files. You can try to speed up the build process by manually writing the necessary links between the files, but on a project with a complex tree of file dependencies, this can be overly complicated.

Despite all this, Grunt has a huge ecosystem: hundreds of plugins, thousands of projects, billions of developers, that's it. That is, not only is Grunt universal, but also a plugin for your task, most likely, has already been written.

In summary, Grunt is a great choice for small to medium projects, especially if you haven't set up any build systems before. A huge community, a bunch of plugins, clear documentation and even articles and reports in Russian for those unfortunate people who cannot live without it. And of course, if in the future, for some reason, Grunt ceases to suit you, you can always switch to another system devoid of its shortcomings.

gulp

Gulp is a currently actively developing build system. Its architecture is based on the use of threads in Node.js, which allows you not to write temporary files and folders to disk. The main advantages of Gulp are the speed and brevity of the config. Moreover, if the first is indisputable, then brevity compared to Grunt is achieved simply due to its different structure. If in the Grunt config you individually operate with plugins, configuring each of them, then in the Gulp config you need to describe the process that each file (or set of files) must go through in order to be built. Here is a live example of compiling SASS:

Gulp.task("styles", function() ( return gulp.src("styles/*.scss") .pipe(sass(( style: "expanded" ))) .pipe(rename((suffix: ".min "))) .pipe(minifycss()) .pipe(gulp.dest("build/styles/css")); ));

In the first line, we register a task for Gulp named styles . Then we sequentially describe what needs to be done with each of the files that matches the styles/*.scss mask: compile SASS, add .min to the file name, minify it, put it in the final directory. If we need to do something else with this file, we simply add the appropriate command, for example.pipe(add a comment with an ASCII unicorn to the beginning of the file) (I hope they finally make a plug-in for this everyday task). I like this approach to writing a config more: it describes better what really happens with your files.

Of course, while Gulp loses to Grunt in terms of the number of plugins, there are plugins for many tasks. Most likely, existing plugins will be enough for you, and if something is really missing, you can always write your own (just kidding). By the way, there is a gulp-grunt package that allows you to run Grunt tasks from Gulp if you really need to.

If you like this approach to building, speed is important, and you don't need to perform specific tasks for which there is a plug-in only for Grunt, then Gulp can be a great choice. Gulp remains Grunt's biggest competitor to date.

Broccolli

The youngest of the build tools under consideration is now, in fact, under development. The Broccolli developers do not hide the fact that they were inspired by Gulp, but they consider some of the concepts underlying it to be erroneous. For example, they chose to cache all intermediate build results (implemented by each of the plugins) to speed up the build, instead of partially rebuilding only the required files. They also didn't like that Gulp works best with transforming one file into one final, that is, one by one. To improve the performance of many-to-one operations, Gulp is currently developing a complex scheme with the creation of a virtual file system, which to the developers of Broccolli seems to be an unnecessary complication and a manifestation of the weakness of the original concepts of Gulp. Broccolli initially operates with the concepts of trees instead of files and performs only transformations of trees into other trees (even if they are degenerate and from one vertex).

A very reasonable theoretical approach to the assembly problem does not solve the problem of the number of extensions to Broccolli. Unfortunately, there are about two dozen of them and they perform only the most basic tasks. If you want to try something new, look at Broccolli, it's fast enough, it's being actively developed, but, probably, it's still damp for serious projects.

Brunch

Brunch was created with the same goal - to beat Grunt on all fronts, but approached it from a completely different angle. The Brunch developers decided to take a good understanding of the subject area, that is, to make a less versatile tool that will be sharpened specifically for front-end tasks, for example, without any settings, understand that *.js is a file with scripts, *.coffee is CoffeeScript and so on. Brunch is quite fast, much faster than Grunt, but slightly slower than Gulp. The undoubted advantages of Brunch include a really compact config, which is several times smaller than that of Grunt and Gulp. Here, for example, is a simple Brunch config:

Exports.config = files: javascripts: joinTo: "javascripts/app.js": /^app/ "javascripts/vendor.js": /^(bower_components|vendor)/ stylesheets: joinTo: "stylesheets/app.css" order :after: ["vendor/styles/helpers.css"] templates: joinTo: "javascripts/app.js"

Note that the config can be written both in CoffeeScript (as in this case) and in regular JS. We create a regular module that returns JSON with build settings.

Notice the joinTo and order keys. This is the domain knowledge I was talking about - at the config level, Brunch knows that you will most likely want to merge files, some before others. This is what allows you to replace 400 lines of the Grunt config with 20-30 lines of Brunch.

Plus, the Brunch ecosystem is much smaller than Grunt and even Gulp. There are about 50 plugins (compared to 450+ for Gulp, for example), development is not very fast, in general, everything is rather sad here.

To sum up: if you really like short configs, speed is important, but you don’t need any special actions at the build stage, then you can look at Brunch. Confused, of course, a small number of plug-ins, but maybe the situation will change.

ENB

And finally, the sweetest part. I want to tell you about the assembly system developed at Yandex by Marat Dulin, which is called ENB. This is what we are currently using in our project. Its approach is fundamentally different from all the described systems: it was originally created to work with projects using the BEM methodology, although, as the author notes, its platform is free from the BEM ideology and can be used for all projects of a suitable structure.

Briefly, what is the point. In ENB, we operate with the concept of a target, that is, the final file that needs to be collected, or a node (folder, in the general case, a page), for which a certain set of files needs to be collected. In order to build the target file, we use a number of technologies (roughly speaking, plugins in Grunt terms, although the technologies are smaller and more specialized). First of all, ENB determines the initial set of files that are needed to build the targets (this is done by several basic technologies that work with the BEM methodology by default, that is, they look for a *.bemdecl file that contains the dependencies of this node on different blocks), fully deploys it's a dependency tree (when the block your page depends on depends on another, both are included in the right order) and then finds the files needed for each registered technology. Then ENB follows the sequence of file transformations described in the config (here you can trace some analogy with Gulp). Despite some differences from the standard build systems approach, once you understand the basic concepts, it's pretty easy to work with ENB.

The main advantages of ENB: assembly speed, due to a flexible caching system and the ability to exchange intermediate data between different technologies, parallelize independent processes, and separate the heaviest technologies into separate subprocesses. It is unusually easy to write new technologies to ENB if you are not satisfied with the behavior of standard ones.

The disadvantages include the fact that the ENB config is quite verbose, since it is possible to control absolutely all stages of the assembly. Plus, ENB was still written for the BEM methodology, and attaching it to a project with a completely different structure will require extra gestures. There are not many written technologies for ENB (about 60), but it copes with most of the tasks of BEM projects with a bang.

To summarize: ENB is the best choice for projects based on the BEM methodology, which I personally find the most suitable for medium to large sites, as the organization of the code into blocks drives and beeps. It is very fast, collects dozens of pages and hundreds of files in seconds, is easy to set up and pleasant to use. If your project is large, you get confused in the code and edit thousands of lines of files, I advise you to study BEM in more detail as a way to organize the structure of front-end projects. And when you love BEM, you will love ENB as the most native build tool for BEM projects.

In this article, we will consider an example of a Gulp environment that can be used for comfortable front-end development of a web project. This example is configured by default to create sites and web applications based on the Bootstrap 4 framework.

The project covered in this article is hosted on Github at: https://github.com/itchief/gulp-project-bootstrap-4

Video for this article:

Instructions for installing the Gulp environment

To create an environment, you must have the following programs installed:

  • "Node.js" (you can download the "Node.js" installer for your operating system from this page ; the project requires at least version 10 );
  • "Gulp" (You can install Gulp by running the following command in the console: npm install -g gulp-cli).

The next step is to install npm packages and their dependencies. To do this, in the console (should be in the root directory of the project), you must run the command:

npm install

This command will install all the packages that are needed both for the work of the environment itself and for the frontend. npm performs these actions according to the instructions written in the "package.json" file.

When using the first version of the project (1.0.0), which uses the Bower package manager, you need to run another command:

Bower install

This program will install the frontend packages specified in the "bower.json" file.

How to use Gulp environment?

Open a command prompt (the path should point to the project's root folder) and type gulp (normal mode):

After entering this command, the default task will start, i.e. "default". This task will in turn run a series of other tasks: "build", "webserver", and "watch".

The "build" task will build the project for production (i.e. it will run "clean:build", "html:build", "css:build", "js:build", "fonts:build" and "image:build "). These tasks will place the resulting project files in the "assets/build" folder.

The "webserver" task is designed to run a local web server with "live reload" of pages in the browser. With it, you can very easily view the project and perform its testing.

The "watch" task is used to keep track of changes to source files in the "assets/src" folder and run different tasks if they occur. In other words, it allows you to automatically run the necessary tasks and keep the resulting files (the contents of the "assets/build" folder) up to date.


In addition, you can perform a selective (independent) assembly of one or another part of the project.

For example, to build only the CSS of a part of the site, it is enough to enter the command:

gulp css:build

List of other tasks:

Gulp clean:build // to clean up the "assets/build" directory gulp html:build // to build HTML files gulp js:build // to build JS files gulp fonts:build // to build fonts gulp image:build // to assembly image

Description of the Gulp environment

In this section, we will analyze:

  • the main tools and file structure of the Gulp environment;
  • how Bootstrap sources are connected to the project and how they are configured;
  • how to independently (from scratch) initialize the Gulp project and install dependencies (without using the ready-made package.json)
  • how to initialize Bower and install frontend packages from scratch (without using ready-made "bower.json")*;
  • contents of the Gulp project builder file (gulpfile.js)

* The Bower package manager has not been used in the project since version 2.0.0.

List of tools

The environment intended for the development of a front-end project (website) is built on the basis of the following tools:

  • Node.js (the environment in which the environment will run);
  • npm (package manager included with Node.js; will be used to load Gulp, plugins, and front-end packages);
  • jQuery, Popover, Bootstrap (packages that will be used to build the css and js parts of the site);
  • Gulp and its plugins (will be used to build the project and perform other web tasks).

In the first versions of the project, the Bower package manager was additionally used. It was used for loading the jQuery, Popover and Bootstrap libraries. In project versions starting from 2.0.0, these libraries are loaded using npm.

Gulp project file structure

The file structure of a project can be organized in different ways. This may depend both on the preferences of a particular developer, and on the project for which it is created.

In this article, we will follow the following structure:

At the root of the project is the folder "assets" and the files "gulpfile.js", "package.json". The "gulpfile.js" file will contain tasks for the builder of the Gulp project.

The first version of the project also used ".bowerrc" and "bower.json" files. The file "bower.json" is the configuration file of the Bower manager, based on which the necessary front-end packages were determined for loading. In this project, it was used to load Bootstrap, jQuery and Popper.

The "assets" folder contains two folders: "src" (for source files) and "build" (for finished files; the Gulp builder will put them in this folder). The "src" folder contains the directories "fonts" (for fonts), "img" (for source images), "js" (for js files), "style" (for styles) and "template" (for HTML fragments) and the "index.html" file.

In the first version of the project, the "src" folder still contained the "bower_components" directory. It was intended for components that were loaded using Bower. It is not in the current version.

The "js" directory contains two files: "main.js" and "my.js". The "my.js" file is used to write your own scripts, and "main.js" is used to define the list of files whose contents will need to be included in the final js file. The final file is the file that should be the output (in the "build" directory).

The "style" directory is reserved for styles. This directory contains three files: "main.scss" (contains a list of files whose contents must be included in the final style file), "my.scss" (used to write your styles) and "variables.scss" (contains SCSS variables, with which we will change the styles of Bootstrap 4, and also use it to create our variables).

The "index.html" file is the main page of the project being created. In addition to "index.html", other html pages can be placed in this directory.

The "template" directory is intended for placing fragments of HTML pages into it. For example, you can create "head.html" and "footer.html" files in this directory, and import their contents (using the syntax //= path_to_file) into several pages at once. This will make it easier to create and edit html pages, because. individual parts of the pages will already be in separate files.

Connecting Bootstrap 4 sources to the project and setting them up

There are different ways to connect the Bootstrap 4 framework to a project, as well as options for working with it.

The most flexible option is to use source codes. In this case, not only can it is very easy to change the default styles of Bootstrap, but also to connect to the project only those classes and components that will be used in it.

Bootstrap 4 CSS Styles Source Coded in SCSS and are represented by a large number of small files.

List of SCSS files (located in "node_modules/bootstrap/scss/" directory): "functions.scss", "variables.scss", "mixins.scss", "variables.scss", "print.scss", "reboot. scss", "type.scss", "images.scss", "code.scss", "grid.scss", "tables.scss", "forms.scss", "buttons.scss", "transitions.scss" , "dropdown.scss", etc.

Each such file performs either a specific service task, or is responsible for styling a specific function of a framework or component. SCSS files have concise and understandable names. Using only them, you can quite accurately understand the purpose of each of them.

Customizing or changing the default styles of Bootstrap 4 is done by redefining the values ​​of SCSS variables. All SCSS variables are collected in one place for convenience (in the "variables.scss" file). But, it is desirable to redefine their values, of course, not in this file, but in your own (for example, having the same name "variables.scss", but located in "assets/style/variables.scss").

For example, changing the theme color success And danger, is done by changing the values ​​of the $green and $red variables:

// Overriding the default values ​​of Bootstrap 4 variables $red: #cc2eaa; $green: #2ecc71;

note that after copying the Bootstrap 4 variables into your CSS file ("assets/style/variables.scss"), they need to remove the !default label.

The !default label is for setting a SCSS variable to a default value. If the SCSS variable already has a value, then the new value, if it is specified with the !default key, will not be set.

Specifying which Bootstrap 4 source SCSS files should be included in the compilation to CSS and which should not is done via the SCSS file "assets/style/main.scss". In other words, it is the contents of this file that will determine the set of styles that will be connected to the web page after compilation.

In addition, the files "assets/style/variables.scss" (to override Bootstrap variables) and "assets/style/my.scss" (to create your own styles) are also connected to this file.

The contents of the "main.scss" file (example):

// Override the default Bootstrap 4 variables and define your own @import "variables"; // Include the necessary Bootstrap 4 SCSS sources @import "../../../node_modules/bootstrap/scss/_functions"; @import "../../../node_modules/bootstrap/scss/_variables"; @import "../../../node_modules/bootstrap/scss/_mixins"; @import "../../../node_modules/bootstrap/scss/_root"; @import "../../../node_modules/bootstrap/scss/_reboot"; @import "../../../node_modules/bootstrap/scss/_type"; @import "../../../node_modules/bootstrap/scss/_images"; @import "../../../node_modules/bootstrap/scss/_code"; @import "../../../node_modules/bootstrap/scss/_grid"; @import "../../../node_modules/bootstrap/scss/_tables"; @import "../../../node_modules/bootstrap/scss/_forms"; @import "../../../node_modules/bootstrap/scss/_buttons"; @import "../../../node_modules/bootstrap/scss/_transitions"; @import "../../../node_modules/bootstrap/scss/_dropdown"; @import "../../../node_modules/bootstrap/scss/_button-group"; @import "../../../node_modules/bootstrap/scss/_input-group"; @import "../../../node_modules/bootstrap/scss/_custom-forms"; @import "../../../node_modules/bootstrap/scss/_nav"; @import "../../../node_modules/bootstrap/scss/_navbar"; @import "../../../node_modules/bootstrap/scss/_card"; @import "../../../node_modules/bootstrap/scss/_breadcrumb"; @import "../../../node_modules/bootstrap/scss/_pagination"; @import "../../../node_modules/bootstrap/scss/_badge"; @import "../../../node_modules/bootstrap/scss/_jumbotron"; @import "../../../node_modules/bootstrap/scss/_alert"; @import "../../../node_modules/bootstrap/scss/_progress"; @import "../../../node_modules/bootstrap/scss/_media"; @import "../../../node_modules/bootstrap/scss/_list-group"; @import "../../../node_modules/bootstrap/scss/_close"; @import "../../../node_modules/bootstrap/scss/_toasts"; @import "../../../node_modules/bootstrap/scss/_modal"; @import "../../../node_modules/bootstrap/scss/_tooltip"; @import "../../../node_modules/bootstrap/scss/_popover"; @import "../../../node_modules/bootstrap/scss/_carousel"; @import "../../../node_modules/bootstrap/scss/_spinners"; @import "../../../node_modules/bootstrap/scss/_utilities"; @import "../../../node_modules/bootstrap/scss/_print"; // Include your SCSS files @import "my";

In addition, some Bootstrap 4 components also require JavaScript code to work.

List of Bootstrap 4 js files (located in "node_modules/bootstrap/js/dist/" directory): "util.js", "alert.js", "button.js", "carousel.js", "collapse.js ", "dropdown.js", "modal.js", "tooltip.js", "popover.js", "scrollspy.js", "tab.js", and "toast.js".

Determining which js files of the Bootstrap 4 framework need to be included in the final js file of the project, and which are not, is done through "main.js".

Importing the necessary files into the resulting build/main.js is done using the following construct:

//= path_to_file

Performing this action will be the Gulp plugin "gulp-rigger". How to install and connect it will be described below.

You can also import jQuery, Popper (required for the operation of the Dropdown, Tooltip and Popover components) and, if necessary, your own js files into this file.

The contents of the "main.js" file (example):

// Import jQuery //= ../../../node_modules/jquery/dist/jquery.js // Import Popper //= ../../../node_modules/popper.js/dist/umd /popper.js // Import the required Bootstrap 4 js files //= ../../../node_modules/bootstrap/js/dist/util.js //= ../../../node_modules/ bootstrap/js/dist/alert.js //= ../../../node_modules/bootstrap/js/dist/button.js //= ../../../node_modules/bootstrap/js/ dist/carousel.js //= ../../../node_modules/bootstrap/js/dist/collapse.js //= ../../../node_modules/bootstrap/js/dist/dropdown. js //= ../../../node_modules/bootstrap/js/dist/modal.js //= ../../../node_modules/bootstrap/js/dist/tooltip.js //= ../../../node_modules/bootstrap/js/dist/popover.js //= ../../../node_modules/bootstrap/js/dist/scrollspy.js //= ../. ./../node_modules/bootstrap/js/dist/tab.js //= ../../../node_modules/bootstrap/js/dist/toast.js // Import other js files //= my .js

How to initialize a Gulp project and install dependencies from scratch?

The development of a project usually begins with the creation of a "package.json" file (manifest).

The "package.json" file will contain general information about the project (name, version, description, author name, etc.), as well as information about the packages on which this project depends.

To create a manifest, you need to go to the root folder of the project and enter the command:

npm init

After entering the command, you need to answer the following questions:

  • project name (name) - "bootstrap-4";
  • version number (version) – "2.0.0";
  • description (description) - "Start project with use Bootstrap 4";
  • author (author) - "website";
  • git repository (git repository) - "";
  • entry point (entry point), test command (test command), license (license), keywords (keywords) - default values.

To the question "Is this ok?" answer "yes" or press Enter .

As a result, the file "package.json" will appear in the root folder of the project.

Now let's install the packages that we will use in the project with the following command:

npm install package_name --save-dev // install the package, with information about it automatically added to the "devDependencies" section of the "package.json" file npm install package_name --save-prod // install the package, with information about it , is automatically added to the "dependencies" section of the "package.json" file

The "--save-dev" or "--save-prod" key determines which section of the "package.json" file will contain information about it.

List of packages to be used in the project:

npm install gulp --save-dev // install gulp npm install browser-sync --save-dev // install browser-sync npm install gulp-autoprefixer --save-dev // install gulp-autoprefixer npm install gulp-cache - -save-dev // install gulp-cache npm install gulp-clean-css --save-dev // install gulp-clean-css npm install gulp-rimraf --save-dev // install gulp-clean-css npm install gulp-imagemin --save-dev // install gulp-imagemin npm install gulp-plumber --save-dev // install gulp-plumber npm install gulp-rigger --save-dev // install gulp-rigger npm install gulp- sass --save-dev // install gulp-sass npm install gulp-sourcemaps --save-dev // install gulp-sourcemaps npm install gulp-uglify --save-dev // install gulp-uglify npm install imagemin-jpeg- recompress --save-dev // install imagemin-jpeg-recompress npm install imagemin-pngquant --save-dev // install imagemin-pngquant npm install gulp-rename --save-dev // install imagemin-pngquant npm install jquery - -save-prod npm install popper.js --save-prod npm install bootstrap --save-prod

After installing all the dependencies, the package.json file will have the following content:

( "name": "bootstrap-4", "version": "2.0..com/itchief/gulp-project-bootstrap-4.git" ), "dependencies": ( "jquery": "^3.4.1" , "popper.js": "^1.14.7", "bootstrap": "^4.3.1" ), "devDependencies": ( "browser-sync": "^2.26.7", "gulp": "^ 4.0.2", "gulp-autoprefixer": "^6.1.0", "gulp-cache": "^1.1.2", "gulp-clean-css": "^4.2.0", "gulp-rimraf ": "^0.2.2", "gulp-imagemin": "^6.0.0", "gulp-plumber": "^1.2.1", "gulp-rigger": "^0.5.8", "gulp -sass": "^4.0.2", "gulp-sourcemaps": "^2.6.5", "gulp-uglify": "^3.0.2", "imagemin-jpeg-recompress": "^6.0.0 ", "imagemin-pngquant": "^8.0.0", "gulp-rename": "^1.4.0" ) )

How to initialize Bower and install frontend packages from scratch?

Let's define a folder where Bower will download the packages. To do this, create a .bowerrc file and enter the following into it:

( "directory" : "assets/src/bower_components/" )

Save the .bowerrc file. Now all components will be loaded into the bower_components directory located in assets/src/ .

Let's initialize Bower (create a bower.json manifest file). The creation of the bower.json file can be done using the command (in the root folder of the project):

Bower init

After that, you need to answer the following questions:

  • project name (name) - bootstrap-4;
  • description (description) - Start project on Bootstrap 4 - site;
  • author (author) - site;
  • set installed components as dependencies (set currently installed components as dependencies) - Y (Yes);
  • would you like to mark this package as private which prevents it from being accidentally published to the registry - Y (Yes);
  • for the rest of the questions, we will leave the answers offered by the program by default;

These steps will create a bower.json file.

Let's load Bootstrap 4 and the packages it depends on (Popper and jQuery) into our project using Bower.

To do this, enter the following command in the console:

Bower install bootstrap#v4.0.0-beta --save

The -save switch is required to write the package information to the dependencies section of the bower.json file.

As a result, bower.json will have the following content:

( "name": "bootstrap-4", "description": "Start project on Bootstrap 4 - website", "authors": [ "website" ], "license": "ISC", "keywords": , "homepage ": "", "ignore": [ "**/.*", "node_modules", "bower_components", "assets/src/bower_components/", "test", "tests" ], "dependencies": ( " jquery": "^3.2.1", "bootstrap": "^v4.0.0-beta" ) )

If you don't want to initialize Bower (bower.json) with the bower init command and install packages manually, you can simply create a bower.json file (using a file manager, for example) and paste the above text content into it. To install dependencies in the project, it will be enough to enter the following command:

Bower install

Description of the Gulp project builder file (gulpfile.js)

All actions performed before this were preparatory. All the functionality that the created environment will perform will be determined by the "gulpfile.js" file.

The file "gulpfile.js" is a list of tasks.

The main tasks that this file will perform:

  • collecting several style files into one, compiling the resulting SCSS to CSS, adding auto-prefixes, minimizing CSS and creating a source map;
  • importing all the necessary js files into one, minimizing this file and creating a source map;
  • collection of html file, transfer of fonts, processing (compression) of pictures and automatic updating of pages through Browser Sync.

In addition, in order not to run these tasks when changing the source files manually, let's create another "watch" task. It will monitor file changes and run certain tasks automatically.

File code "gulpfile.js" (when using Gulp 4):

"use strict"; /* Paths to source files (src), finished files (build), and files to watch for changes (watch) */ var path = ( build: ( html: "assets/build/", js: "assets/build/js/", css: "assets/build/css/", img: "assets/build/img/", fonts: "assets/build/fonts/" ), src: ( html: "assets /src/*.html", js: "assets/src/js/main.js", style: "assets/src/style/main.scss", img: "assets/src/img/**/*. *", fonts: "assets/src/fonts/**/*.*" ), watch: ( html: "assets/src/**/*.html", js: "assets/src/js/** /*.js", css: "assets/src/style/**/*.scss", img: "assets/src/img/**/*.*", fonts: "assets/srs/fonts/* */*.*" ), clean: "./assets/build/*" ); /* server settings */ var config = ( server: ( baseDir: "./assets/build" ), notify: false ); /* Include gulp and plugins */ var gulp = require("gulp"), // Include Gulp webserver = require("browser-sync"), // Server to run and automatically update pages plumber = require("gulp-plumber "), // module for tracking errors rigger = require("gulp-rigger"), // module for importing the contents of one file into another sourcemaps = require("gulp-sourcemaps"), // module for generating a map of sass source files = require("gulp-sass"), // module for compiling SASS (SCSS) to CSS autoprefixer = require("gulp-autoprefixer"), // module for automatically setting autoprefixes cleanCSS = require("gulp-clean-css" ), // plugin for minifying CSS uglify = require("gulp-uglify"), // plugin for minifying JavaScript cache = require("gulp-cache"), // plugin for caching imagemin = require("gulp-imagemin" ), // plugin for compressing PNG, JPEG, GIF and SVG images jpegrecompress = require("imagemin-jpeg-recompress"), // plugin for jpeg compression pngquant = require("imagemin-pngquant"), // plugin for compression png rimraf = require("gulp-rimraf"), // plugin for deleting files and directories rename = require("gulp-rename"); /* tasks */ // start the server gulp.task("webserver", function () ( webserver(config); )); // build html gulp.task("html:build", function () ( return gulp.src(path.src.html) // select all html files in the specified path. pipe(plumber()) // trace errors. pipe(rigger()) // import attachments. pipe(gulp.dest(path.build.html)) // upload finished files. pipe(webserver.reload(( stream: true ))); // restart server )) ; // collect styles gulp.task("css:build", function () ( return gulp.src(path.src.style) // get main.scss .pipe(plumber()) // to track errors.pipe( sourcemaps.init()) // initialize sourcemap .pipe(sass()) // scss -> css .pipe(autoprefixer()) // add prefixes.pipe(gulp.dest(path.build.css)) .pipe (rename(( suffix: ".min" ))) .pipe(cleanCSS()) // Minify CSS .pipe(sourcemaps.write(". /")) // write sourcemap .pipe(gulp.dest(path.build.css)) // upload to build .pipe(webserver.reload(( stream: true ))); // restart server )); / / build js gulp.task("js:build", function () ( return gulp.src(path.src.js) // get the main.js file .pipe(plumber()) // for error tracking.pipe( rigger()) // import all specified files into main.js .pipe(gulp.dest(path.build.js)) .pipe(rename(( suffix: ".min" ))) .pipe(sourcemaps.init( )) //initialize sourcemap .pipe(uglify()) //minify js .pipe(sourcemaps.write("./")) //write sourcemap .pipe(gulp.dest(path.build.js)) // put the finished file. pipe(webserver.reload(( stream: true ))); // restart the server )); // transfer fonts gulp.task("fonts:build", function () ( return gulp.src(path. src.fonts) .pipe(gulp.dest(path.build.fonts)); )); // process images gulp.task("image:build", function () ( return gulp.src(path.src.img ) // image source path. pipe(cache(imagemin([ // image compression imagemin.gifsicle(( interlaced: true )), jpegrecompress(( progressive: true, max: 90, min: 80 )), pngquant() , imagemin.svgo(( plugins: [( removeViewBox: false )] )) ]))) .pipe(gulp.dest(path.build.img)); // upload finished files )); // delete build directory gulp.task("clean:build", function () ( return gulp.src(path.clean, ( read: false )) .pipe(rimraf()); )); // clear cache gulp.task("cache:clear", function () ( cache.clearAll(); )); // build gulp.task("build", gulp.series("clean:build", gulp.parallel("html:build", "css:build", "js:build", "fonts:build", " image:build"))); // run tasks when files change gulp.task("watch", function () ( gulp.watch(path.watch.html, gulp.series("html:build")); gulp.watch(path.watch.css , gulp.series("css:build")); gulp.watch(path.watch.js, gulp.series("js:build")); gulp.watch(path.watch.img, gulp.series(" image:build")); gulp.watch(path.watch.fonts, gulp.series("fonts:build")); )); // default task gulp.task("default", gulp.series("build", gulp.parallel("webserver","watch")));

The "gulpfile.js" file code contains comments. With the help of them it is explained what this or that fragment of instructions performs.

Creating a task in Gulp is very easy:

// creating a gulp task (nametask is the name of the task) gulp.task("nametask", function() ( // actions the task should perform... ));

Tasks in gulp are built very simply. Their framework of actions in most cases can be represented as follows:

  • get data from source files;
  • process raw data using gulp plugins;
  • save the result (files) to the "build" directory.

If you are using Gulp 3, then the contents of the "gulpfile.js" file should be as follows:

"use strict"; /* options for gulp-autoprefixer */ var autoprefixerList = [ "Chrome >= 45", "Firefox ESR", "Edge >= 12", "Explorer >= 10", "iOS >= 9", "Safari >= 9", "Android >= 4.4", "Opera >= 30" ]; /* Paths to source files (src), finished files (build), and files to watch for changes (watch) */ var path = ( build: ( html: "assets/build/", js: "assets/build/js/", css: "assets/build/css/", img: "assets/build/img/", fonts: "assets/build/fonts/" ), src: ( html: "assets /src/*.html", js: "assets/src/js/main.js", style: "assets/src/style/main.scss", img: "assets/src/img/**/*. *", fonts: "assets/src/fonts/**/*.*" ), watch: ( html: "assets/src/**/*.html", js: "assets/src/js/** /*.js", css: "assets/src/style/**/*.scss", img: "assets/src/img/**/*.*", fonts: "assets/srs/fonts/* */*.*" ), clean: "./assets/build/*" ); /* server settings */ var config = ( server: ( baseDir: "./assets/build" ), notify: false ); /* Include gulp and plugins */ var gulp = require("gulp"), // Include Gulp webserver = require("browser-sync"), // Server to run and automatically update pages plumber = require("gulp-plumber "), // module for tracking errors rigger = require("gulp-rigger"), // module for importing the contents of one file into another sourcemaps = require("gulp-sourcemaps"), // module for generating a map of sass source files = require("gulp-sass"), // module for compiling SASS (SCSS) to CSS autoprefixer = require("gulp-autoprefixer"), // module for automatically setting autoprefixes cleanCSS = require("gulp-clean-css" ), // plugin for minifying CSS uglify = require("gulp-uglify"), // plugin for minifying JavaScript cache = require("gulp-cache"), // plugin for caching imagemin = require("gulp-imagemin" ), // plugin for compressing PNG, JPEG, GIF and SVG images jpegrecompress = require("imagemin-jpeg-recompress"), // plugin for jpeg compression pngquant = require("imagemin-pngquant"), // plugin for compression png rimraf = require("gulp-rimraf"), // plugin for deleting files and directories rename = require("gulp-rename"); /* tasks */ // start the server gulp.task("webserver", function () ( webserver(config); )); // build html gulp.task("html:build", function () ( return gulp.src(path.src.html) // select all html files in the specified path. pipe(plumber()) // trace errors. pipe(rigger()) // import attachments. pipe(gulp.dest(path.build.html)) // upload finished files. pipe(webserver.reload(( stream: true ))); // restart server )) ; // collect styles gulp.task("css:build", function () ( return gulp.src(path.src.style) // get main.scss .pipe(plumber()) // to track errors.pipe( sourcemaps.init()) // initialize sourcemap .pipe(sass()) // scss -> css .pipe(autoprefixer(( // add prefixes browsers: autoprefixerList ))) .pipe(gulp.dest(path.build. css)) .pipe(rename(( suffix: ".min" ))) .pipe(cleanCSS()) // Minify CSS .pipe(sourcemaps.write(". /")) // write sourcemap .pipe(gulp.dest(path.build.css)) // upload to build .pipe(webserver.reload(( stream: true ))); // restart server )); / / build js gulp.task("js:build", function () ( return gulp.src(path.src.js) // get the main.js file .pipe(plumber()) // for error tracking.pipe( rigger()) // import all specified files into main.js .pipe(gulp.dest(path.build.js)) .pipe(rename(( suffix: ".min" ))) .pipe(sourcemaps.init( )) //initialize sourcemap .pipe(uglify()) //minify js .pipe(sourcemaps.write("./")) //write sourcemap .pipe(gulp.dest(path.build.js)) // put the finished file. pipe(webserver.reload(( stream: true ))); // restart the server )); // transfer fonts gulp.task("fonts:build", function () ( return gulp.src(path. src.fonts) .pipe(gulp.dest(path.build.fonts)); )); // process images gulp.task("image:build", function () ( return gulp.src(path.src.img ) // image source path. pipe(cache(imagemin([ // image compression imagemin.gifsicle(( interlaced: true )), jpegrecompress(( progressive: true, max: 90, min: 80 )), pngquant() , imagemin.svgo(( plugins: [( removeViewBox: false )] )) ]))) .pipe(gulp.dest(path.build.img)); // upload finished files )); // delete build directory gulp.task("clean:build", function () ( return gulp.src(path.clean, ( read: false )) .pipe(rimraf()); )); // clear cache gulp.task("cache:clear", function () ( cache.clearAll(); )); // build gulp.task("build", [ "clean:build", "html:build", "css:build", "js:build", "fonts:build", "image:build" ]); // run tasks when files change gulp.task("watch", function () ( gulp.watch(path.watch.html, ["html:build"]); gulp.watch(path.watch.css, [" css:build"]); gulp.watch(path.watch.js, ["js:build"]); gulp.watch(path.watch.img, ["image:build"]); gulp.watch(path .watch.fonts, ["fonts:build"]); )); // default task gulp.task("default", [ "build", "webserver", "watch" ]);

Want to get more points in Google Page Speed? Don't know what "front-end assembly" is? Then you are here, it will be interesting.

What is Node.JS?

Node.JS is commonly referred to as "Northern JavaScript". This platform allows you to write programs using JavaScript syntax.

There are implementations for Windows, Mac OS and Linux.

Package manager included NPM, which can be used to install packages.

What is gulp?

Gulp is a package written in Node.JS that helps webmasters build projects at the layout stage.

To install Gulp, you need to use the command line.

npm install gulp

At the end of this article is a file that will help you build a typical project.

In this example, we will do the following using Gulp:

  • Automatically optimize images for the web;
  • We collect one minified style file from preprocessors (SASS, SCSS);
  • We collect one minified file with scripts.

How to build front-end with Gulp?

To understand how it all works, let's break it down step by step.

The structure can be seen in the screenshot.

  • The assets folder is for image sources, styles and scripts;
  • Public folder - the result of the project assembly will be located in it;
  • gulpfile.js - a file that describes the logic of the collector;
  • package.json is a file that contains information about the programs and plugins used to make Gulp work correctly.

package.json

File contents:

( "name": "gulp_project", "version": "1.0.0", "description": "Example", "main": "gulpfile.js", "scripts": ( "test": "echo \" Error: no test specified\" && exit 1" ), "author": "Dmitriy Ilichev", "license": "ISC", "devDependencies": ( "gulp": "^3.9.0", "gulp-csso ": "^1.0.0", "gulp-concat": "^2.6.0", "gulp-uglify": "^1.2.0", "gulp-imagemin": "^2.3.0", "gulp -sass": "^2.1.1" ) )

The following is clear from this file:

  • Project name gulp_project , version and description;
  • The main file is gulpfile.js ;
  • The author of the project, the license - all this is not so important and simply these fields can be empty;
  • The interesting item is devDependencies . It describes dependencies.

The file can be edited in a regular text editor. It can also be created for a new project with npm int .

Based on this, Node.JS understands that for work we need:

  • Gulp version 3.9.0 and higher to build;
  • Gulp-csso version 1.0.0 and higher is a plugin for minifying styles (css);
  • Gulp-concat version 2.6.0 and higher is a plugin for merging multiple files into one;
  • Gulp-uglify version 1.2.0 and later is a javascript minification plugin;
  • Gulp-imagemin version 2.3.0 and later is an image optimization plugin;
  • Gulp-sass version 2.1.1 and higher is a plugin for getting css from sass (scss).

Great! After that, you need to install all this. This is done from the command line. While in the project folder, run the following command:

npm install

All necessary information will be taken from package.json .

After all this magic, the service folder node_modules will appear.

gulpfile.js

File contents:

/* * * Define variables * */ var gulp = require("gulp"), // Gulp JS uglify = require("gulp-uglify"), // JS minification concat = require("gulp-concat"), // Merging files imagemin = require("gulp-imagemin"), // Minifying images csso = require("gulp-csso"), // Minifying CSS sass = require("gulp-sass"); // Convert SASS (SCSS) to CSS /* * * Create tasks (tasks) * */ // Task "sass". Runs with "gulp sass" command gulp.task("sass", function () ( gulp.src("./assets/styles/style.scss") // file to process.pipe(sass().on(" error", sass.logError)) // convert sass to css .pipe(csso()) // minify the css obtained in the previous step. pipe(gulp.dest("./public/css/")); // the result is written to the specified address)); // Task "js". Run by "gulp js" gulp.task("js", function() ( gulp.src([ "./assets/javascripts/jquery-2.1.4.min.js", "./assets/javascripts/bootstrap. min.js", "./assets/javascripts/script.js" ]) // files to process. pipe(concat("min.js")) // glue all JS .pipe(uglify()) // minify the resulting footcloth. pipe(gulp.dest("./public/js/")) // write the result to the specified address )); // "images" task. Run by "gulp images" gulp.task("images", function() ( gulp.src(".assets/images/**/*") // get any files in the folder and its subfolders. pipe(imagemin() ) // optimize images for the web. pipe(gulp.dest("./public/images/")) // write the result to the specified address )); // Task "watch". Triggered by "gulp watch" // It watches for file changes and automatically starts other tasks gulp.task("watch", function () ( // When *.scss files in the "styles" folder and subfolders change, run the sass gulp task. watch("./assets/styles/**/*.scss", ["sass"]); // When changing *.js files in the "javascripts" folder and subfolders, run the js task gulp.watch("./assets/ javascripts/**/*.js", ["js"]); // When changing any files in the "images" folder and subfolders, run the images task gulp.watch("./assets/images/**/*", ["images"]); ));

The main feature is in the task watch. By running it once, you can safely work with sources, and the project will be automatically built each time you save edited files.

As a result, we will get a template ready for publication on the Internet.

Tasks can be run separately. As a result, in the archive at the end of the article you will find the following:

! note Note that after unpacking this archive, you will first need to run the npm install command. This folder contains quite a large number of files, and copying/pasting them every time is a waste of time.

In custody

There are a huge number of other useful plugins. For example, the wonderful Jade template engine, which speeds up writing html code at times, someone may need LESS, and so on.

The presented example is just a platform and a template from which you can quickly and without much knowledge start using all these great features.

Gentleman's set of Front-end developer

It's no secret that a modern front-end developer must have one of the project build tools in his arsenal, such as gulp or Grunt. Until some time, Grunt held a monopoly in this matter, but a group of developers who separated from Grunt decided to create their own lightweight and fast Gulp task manager.

In this article, we will prepare a starter package from scratch for use in future projects.

What technologies do we use

  • Software platform: Node.js
  • CSS pre-processor: stylus
  • Task manager: gulp

Why does a frontender need a task manager?

Until recently, I myself wondered why I need to spend time setting up the task manager config, if I'm already good at layout layouts, until I started using CSS pre-processors.

CSS pre-processors are really convenient and speed up writing styles, but compiling code written in a pre-processor into regular CSS is not a trivial task that can be solved with one button. This is where the task manager comes to our aid. The conversion of the code does not happen by pressing a button, everything happens online without your participation (of course, if everything is set up correctly).

Of course, the tasks of a task manager go far beyond the processes associated with converting pre-processor code into pure CSS. The project assembler also deals with minification, concatenation, checking the code for errors, assembling images into sprites, optimizing images for the web, etc. You simply create a lot of logically separated files in your project, which are then conveniently collected into one directory, already processed and ready to work in the browser. But more on that later, but now let's start with the preparation.

Installing Node.js

If you know how to install node.js on your system and use it, feel free to skip to the next heading.

I would like to immediately warn that all the described actions are relevant for MacOS X, but generally applicable to other Unix systems. Development through the task manager and the command line in Windows somewhat more difficult and will not be described here. However, if you still use Windows and are not ready to give it up, then I can suggest the option of using a virtual machine with installed ubuntu, I use this option on my home system, which is generally quite convenient.

So the first thing we have to do is download and install the node.js package on our system to work with the node through the console. We go to the official site of node.js and download the latest stable version for your system. Once installed, the node command should be available on your command line. To check that your node is working, enter the command on the command line

the version of installed node.js should appear in response. If all is well, we move on.

Project directory structure

In our projects, we will use a unified version of the structure:

Develop - development root directory└─start - project directory├─build - build assembled by the task manager├─resource - all source files for development (.psd, etc.)├─src - development directory│├─css - style development directory││├─images - all static images││├─sprites - image collected in a sprite││├─partial - custom style files│││├─mixins.style - custom mixins│││└─styles - custom styles││├─vendor - other external style files││└─styles - main stylesheet│├─fonts - font directory│├─img - catalog of dynamic images│├─js - JavaScript development directory││├─_*.js - js side files││├─_main.js - main custom js││└─main.js - main js file│├─.htaccess - config for the server│├─*.html - page markup files│├─pages.html - a file with links to all pages of the template│├─index.html - page markup index file│└─include - directory of included markup files│ └─*.html - included markup files (header.html, etc.)├─package.json - npm package manager config├─gulpfile.js - Gulp config├─stylus.template.mustache - mask for reading sprites├─TODO - todo list└─.gitignore - git config

Installation

In the console, use the cd command to go to the development root directory, create our project directory mkdir start and go to it.

Let's set up our structure for the project via the console:

mkdir build resource src src/css src/css/images src/css/sprites src/css/partial src/css/vendor src/js src/template src/template/include src/img src/fonts

Let's create the initial files in the project structure:

touch gulpfile.js stylus.template.mustache .gitignore src/.htaccess src/TODO src/css/styles.styl src/css/partial/styles.styl src/css/partial/mixins.styl src/js/main.js src/js/_main.js src/template/pages.html src/template/index.html src/template/include/header.html src/template/include/footer.html

Create package.json

all pop-up questions can be clicked through Enter, the node will set them to default values, or fill in the proposed fields.

.gitignore

We tell the git which directories to ignore and not upload to the repository:

/node_modules/ /build/ /resource/

The node_modules directory will appear later after installing the plugins and will contain all the project's node plugins.

src/.htaccess

Set additional gzip compression and caching for the server:

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript # Serve gzip compressed CSS files if they exist # and the client accepts gzip. RewriteCond "%(HTTP:Accept-encoding)" "gzip" RewriteCond "%(REQUEST_FILENAME)\.gz" -s RewriteRule "^(.*)\.css" "$1\.css\.gz" # Serve gzip compressed JS files if they exist # and the client accepts gzip. RewriteCond "%(HTTP:Accept-encoding)" "gzip" RewriteCond "%(REQUEST_FILENAME)\.gz" -s RewriteRule "^(.*)\.js" "$1\.js\.gz" # Serve correct content types, and prevent mod_deflate double gzip. RewriteRule "\.css\.gz$" "-" RewriteRule "\.js\.gz$" "-" # Serve correct encoding type. Header append Content-Encoding gzip # Force proxies to cache gzipped & # non-gzipped css/js files separately. Header append Vary Accept-Encoding ExpiresActive on ExpiresByType application/javascript "access plus 1 months" ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType text/css "access plus 1 months"

src/css/styles.style

Include custom style files in the main style file:

@import "partial/styles"

Note that for including .styl files, the extension is not specified, according to the semantics of the Stylus pre-processor code. To include styles in another extension, such as .css, the latter is required.

TODO

This page contains the development todo list. You can read more about working with this file on the PlainTasks plugin page for Sublime Text.

This completes the installation of the structure.

Installing plugins with npm package manager

Node.js by default includes the npm package manager, which has a lot of plugins in its repositories that we will have to work with.

Installing the Gulp Plugin

First you need to install Gulp globally (with the -g switch) on our system

npm install gulp -g

You need to do this once, further global installation is not required.

Now we need to install Gulp locally in the project directory

npm install gulp --save-dev

The --save-dev key says that information about the plugin (name in the repository and its version) will be added to the package.json config and will remember it for this project. Since we do not store the heavy node_modules plugins folder in the git, the information about installed plugins saved in the config will allow us to deploy all the necessary plugins in the project with just one npm i command.

There are abbreviations for each command, so we can write the command above in a shorter format.

In the future, we will also use the abbreviated command format.

Stylus Plugin for Gulp

In our projects, we use the Stylus pre-processor, which works great and compiles on the node.

Install:

npm i gulp-stylus -D

CSS processing plugins

Autoprefixer- automatically inserts -ms- -o- -moz- -webkit- prefixes into the required properties:

npm i gulp-autoprefixer -D

CSS minification- the plugin minifies the output CSS file by removing extra spaces and tabs from it:

npm i gulp-minify-css -D

Image Processing Plugins

Combining images into sprites- you no longer need to spend hours of precious time merging all images into sprites, and then calculating their coordinates, this plugin will automatically do all this for you:

npm i gulp.spritesmith -D

Add a mask for calculating positions in sprites to the previously created stylus.template.mustache file:

((#items)) $((name)) = ((px.x)) ((px.y)) ((px.offset_x)) ((px.offset_y)) ((px.width)) (( px.height)) ((px.total_width)) ((px.total_height)) "(((escaped_image)))"; ((/items))

Add custom mixins to mixins.styl:

SpriteWidth($sprite) width $sprite spriteHeight($sprite) height $sprite spritePosition($sprite) background-position $sprite $sprite spriteImage($sprite) background-image url($sprite) sprite($sprite) if !match( "hover", selector()) && !match("active", selector()) spriteImage($sprite) spritePosition($sprite) spriteWidth($sprite) spriteHeight($sprite)

Connect the mixins and the generated file with coordinates to the main style file src/css/styles.styl:

@import "partial/sprite" @import "partial/mixins"

Note that the sprite files must be included before the custom styles @import "partial/styles"

Image optimization for the web- the plugin will automatically cut out all unnecessary information from your images and shrink them to the optimal size, which in some cases will reduce the size of images up to 90%:

npm i gulp-imagemin -D

JavaScript processing plugins

JS minification- the plugin minifies your JS code as much as possible, reducing its loading time:

npm i gulp-uglify -D

JS Bug Tracking- the plugin will thoroughly check your JS code to identify all inconsistencies and display them in the console:

npm i jshint gulp-jshint -D

HTML processing plugins

Connected files- the plugin allows you to store static parts of the site, such as header , footer , aside , etc., in separate files and include them in any part of another file. There is no more need, in case of minor changes in the header, to change dozens or even hundreds of html pages of the template:

npm i gulp-rigger -D

The plugin is also compatible with JS.

Include custom JS in the main JS file src/js/main.js with the construction:

//= _main.js

Include header.html and footer.html files in index.html

//= include/header.html//= include/footer.html

Other plugins

LiveReload- the plugin eliminates the need to reload the page in the browser each time to see the changes, now this happens automatically when you save the modified file:

npm i gulp-connect -D

Preventing Gulp from crashing- sometimes it happens that Gulp can crash out of watch mode in case of critical errors (mostly due to JS). This plugin tries to keep Gulp processes running whenever possible:

npm i gulp-plumber -D

Renaming files- the most common work with file names. The plugin allows you to completely rename files, change the extension, add prefixes and postfixes, for example, to bring the style.styl view file to style.min.css:

npm i gulp-rename -D

Cleaner- sometimes there is a need to completely clean up the build directory, here a plugin comes to the rescue:

Sourcemap- in order for your files to remain readable through browser debugging after minification, you need to add a sourcemap to the minified files:

npm i gulp-sourcemaps -D

Advanced watch features- the plugin makes watch smart, now it does not overwrite all files in the build when only one file is changed, it overwrites a specific modified file, which saves time and resources:

npm i gulp-watch -D

Check package.json

After all the plugins are installed, let's check our package.json . It should look something like this:

( "name": "start", "version": "1.0.0", "description": "Start pack for Front-end develop", "author": "Ivan Ivanov", "license": "MIT", "dependencies": (), "devDependencies": ( "gulp": "latest", "gulp-autoprefixer": "latest", "gulp-connect": "latest", "gulp-imagemin": "latest", "jshint": "latest", "jshint-stylish": "latest", "gulp-jshint": "latest", "gulp-minify-css": "latest", "gulp-plumber": "latest", "gulp-rename": "latest", "gulp-rigger": "latest", "gulp-sourcemaps": "latest", "gulp-stylus": "latest", "gulp-uglify": "latest", "gulp-watch": "latest", "gulp.spritesmith": "latest", "rimraf": "latest" ) )

Instead of latest, in your case, specific versions of installed plugins will be written. Because Since we are building our starter package that will be used in many projects, it is also recommended to replace the version values ​​with latest in order to always install up-to-date plugin versions in the project.

The node_modules directory should also appear in the project folder, in which all node plugin files are stored. All the necessary plugins are installed, you can proceed to the Gulp config settings.

Setting up gulpfile.js

gulpfile.js- this is the main configuration file of our task manager, it is in it that we will store all the settings and commands.

All Gulp's work boils down to task ( English task). A task is a separate independent function with a name. Each task can be called separately.

Compatibility mode with modern standards

Firstly, at the beginning of the file, we will connect the compatibility mode only according to modern standards:

"use strict";

You can learn more about this directive.

Initializing the Plugin

Plugins are initialized with the following construct:

var initPlugin = require("plugin-name");

In accordance with this design, we initialize all our plugins:

Var gulp = require("gulp"), //main plugin gulp stylus = require("gulp-stylus"), //preprocessor stylus prefixer = require("gulp-autoprefixer"), //arranging autoprefixes cssmin = require(" gulp-minify-css"), //css minification uglify = require("gulp-uglify"), //js minification jshint = require("gulp-jshint"), //js error tracking rigger = require("gulp -rigger"), //working with html and js includes imagemin = require("gulp-imagemin"), //minimizing images spritesmith = require("gulp.spritesmith"), //combining images into sprites rimraf = require( "rimraf"), //purge sourcemaps = require("gulp-sourcemaps"), //sourcemaps rename = require("gulp-rename"), //rename files plumber = require("gulp-plumber"), // fuse to stop gulp watch = require("gulp-watch"), //extending watch connect = require("gulp-connect"); //livereload

Path constants

For convenience, we immediately define all the paths and masks:

Var path = ( build: ( //Here we will specify where to put the files ready after the build html: "build/", js: "build/js/", css: "build/css/", img: "build/css/ images/", fonts: "build/fonts/", htaccess: "build/", contentImg: "build/img/", sprites: "src/css/images/", spritesCss: "src/css/partial/" ), src: ( //Paths to get html sources from: "src/template/*.html", //The src/template/*.html syntax tells gulp that we want to get all files with .html extension js: "src/ js/[^_]*.js",//In styles and scripts, we only need main files jshint: "src/js/*.js", css: "src/css/styles.styl", cssVendor: "src /css/vendor/*.*", //If we want to store library files separately, uncomment the img line: "src/css/images/**/*.*", //Syntax img/**/*.* means - take all files of all extensions from the folder and subdirectories fonts: "src/fonts/**/*.*", contentImg: "src/img/**/*.*", sprites: "src/css/ sprites/*.png", htaccess: "src/.htaccess" ), watch: ( //Here we specify which files we want to watch for changes html: "src/template/**/*.html", js: "src/js/**/*.js", css: "src/css/**/*.*", img: "src/css/images/**/*.*", contentImg: "src/ img/**/*.*", fonts: "src/fonts/**/*.*", htaccess: "src/.htaccess", sprites: "src/css/sprites/*.png" ), clean : "./build", //directories that can be cleared outputDir: "./build" //initial root directory to start the miniserver );

Note that we can use name masks:

  • *.js- all files with js extension
  • [^_]*.js- all files with js extension, excluding those that start with an underscore
  • *.* - any files with any extension within the current directory
  • /**/*.html- all files with .html extension within the current directory and all child directories

task (tasks)

Now that all the constants are written, you can start writing tasks. All tasks have the following structure:

Gulp.task("taskName", function()( //some functions ));

Mini Server and LiveReload

First of all, we will set up the local server and LiveReload:

// Local server for development gulp.task("connect", function()( connect.server(( //set up server configs root: , //server startup root directory port: 9999, //which port we will use livereload: true //initialize LiveReload operation )); ));

Most likely, you will often have to work simultaneously on several projects at once. The server allows you to run many servers at the same time, it is enough to register your port for different projects.

Build HTML

// task for html building gulp.task("html:build", function () ( gulp.src(path.src.html) //Select files from the required path.pipe(rigger()) //Run through rigger . pipe(gulp.dest(path.build.html)) //upload them to the build folder .pipe(connect.reload()) //and restart our server for updates));

JS build

// checking js for errors and outputting them to the console gulp.task("jshint:build", function() ( return gulp.src(path.src.jshint) //select files from the required path.pipe(jshint()) //run through jshint .pipe(jshint.reporter("jshint-stylish")); //style output of errors to the console )); // javascript building gulp.task("js:build", function () ( gulp.src(path.src.js) //Find our main file.pipe(rigger()) //Run through rigger .pipe(sourcemaps .init()) //Initialize sourcemap .pipe(uglify()) //Compress our js .pipe(sourcemaps.write()) //Write maps.pipe(rename((suffix: ".min"))) / /add the suffix.min to the output file.pipe(gulp.dest(path.build.js)) //upload the finished file to build .pipe(connect.reload()) //And restart the server ));

Sprite build

All images to be sprited are added to the src/css/sprites/ directory and, after running through Gulp, become a single sprite image. Sprites should not include logos and backgrounds without clear dimensions.

// build sprites gulp.task("sprites:build", function () ( var spriteData = gulp.src(path.src.sprites) //choose where to get images to merge into a sprite.pipe(spritesmith(( imgName: " sprite.png", //name of the sprite image cssName: "sprite.styl", //style name where we store image positions in the sprite imgPath: "images/sprite.png", //path where the sprite lies cssFormat: "stylus", //format in which we process positions cssTemplate: "stylus.template.mustache", //mask file cssVarMap: function(sprite) ( sprite.name = "s-" + sprite.name //the name of each sprite will consist of a file name and constructions "s-" at the beginning of the name ) ))); spriteData.img.pipe(gulp.dest(path.build.sprites)); // path where we save the image spriteData.css.pipe(gulp.dest(path .build.spritesCss)); // path where we save styles ));

To display a sprite, just use a mixin. For example, for the file lorem.png, the selection from the sprite will look like this:

Lorem sprite($s-lorem)

Now the .lorem object will take the dimensions of the image and the image itself as the background.

Build of static images

Static images are images used in the layout template.

// build static images gulp.task("image:build", function () ( gulp.src(path.src.img) //Select our images. pipe(imagemin(( //Compress them progressive: true, // compression.jpg svgoPlugins: [(removeViewBox: false)], //compression.svg interlaced: true, //compression.gif optimizationLevel: 3 //compression level from 0 to 7 ))) .pipe(gulp.dest(path. build.img)) //upload to build .pipe(connect.reload()) //restart the server ));

Build dynamic images

Dynamic images are content images that will change on the site and are included at the template level only for demonstration purposes. For example, it can be images for news, etc.

// build dynamic images gulp.task("imagescontent:build", function() ( gulp.src(path.src.contentImg) .pipe(imagemin(( //Compress them progressive: true, //compress.jpg svgoPlugins: [(removeViewBox: false)], //compression.svg interlaced: true, //compression.gif optimizationLevel: 3 //compression ratio from 0 to 7 ))) .pipe(gulp.dest(path.build.contentImg)) //unload to build .pipe(connect.reload()) //restart server ));

Build CSS

// build custom css gulp.task("cssOwn:build", function () ( gulp.src(path.src.css) //Select our main stylesheet. pipe(sourcemaps.init()) //initialize soucemap . pipe(stylus(( compress: true, "include css": true ))) //Compile stylus .pipe(prefixer(( browser: ["last 3 version", "> 1%", "ie 8", "ie 7"] ))) //Add vendor prefixes.pipe(cssmin()) //Compress.pipe(sourcemaps.write()) //write sourcemap .pipe(rename((suffix: ".min"))) / /add suffix.min to output filename.pipe(gulp.dest(path.build.css)) //unload to build .pipe(connect.reload()) //restart server ));

Separate task for external styles:

// building the vendor css gulp.task("cssVendor:build", function () ( gulp.src(path.src.cssVendor) // Get the vendor folder .pipe(sourcemaps.init()) //initialize the soucemap .pipe( cssmin()) //Compress.pipe(sourcemaps.write()) //write sourcemap .pipe(gulp.dest(path.build.css)) //upload to build .pipe(connect.reload()) // restart the server));

Let's also add a task for the general CSS build:

// build the entire css gulp.task("css:build", [ "cssOwn:build", // "cssVendor:build" ]);

If you want to process external styles separately from home ones and upload them as separate files, you need to uncomment the line "cssVendor:build"

Font build

// build fonts gulp.task("fonts:build", function() ( gulp.src(path.src.fonts) .pipe(gulp.dest(path.build.fonts)) //dump to build ));

Build.htaccess

// build htaccess gulp.task("htaccess:build", function() ( gulp.src(path.src.htaccess) .pipe(gulp.dest(path.build.htaccess)) //dump to build ));

General build

So that we do not have to build each part separately, let's write a task for the general build:

// build everything gulp.task("build", [ "html:build", "jshint:build", "js:build", "sprites:build", "css:build", "fonts:build", " htaccess:build", "image:build", "imagescontent:build" ]);

Cleaning up the build

Sometimes it is necessary to clean up the build directory completely. Here the following task will come to our aid:

// clean build folder gulp.task("clean", function (cb) ( rimraf(path.clean, cb); ));

Watch or track changes in real time

One of the most important and useful functions of Gulp is the watch function, which allows you to monitor in real time all changes to the produced files and, depending on this, perform specific actions:

// watch gulp.task("watch", function()( //build html in case of change watch(, function(event, cb) ( gulp.start("html:build"); )); //build sprites in case of change watch(, function(event, cb) ( gulp.start("sprites:build"); )); //build context images in case of change watch(, function(event, cb) ( gulp.start(" imagescontent:build"); )); //build css in case of change watch(, function(event, cb) ( gulp.start("css:build"); )); //check js in case of change watch(, ["jshint"]); //build js in case of change watch(, function(event, cb) ( gulp.start("js:build"); )); //build static images in case of change watch(, function (event, cb) ( gulp.start("image:build"); )); //build fonts in case of change watch(, function(event, cb) ( gulp.start("fonts:build"); )) ; //build htaccess in case of change watch(, function(event, cb) ( gulp.start("htaccess:build"); )); ));

Default actions

The default actions are what tasks the task manager will perform when entering the gulp command into the console:

// default actions gulp.task("default", ["build", "watch", "connect"]);

In our case, by default, we will build our project, enable watch mode and start the server.

Commands for the command line

All galp commands for the command line consist of two parts - the gulp command itself and the name of the task separated by a space. Here is a list of commands applicable to our config:

  • gulp - main command, runs the default task
  • gulp build - build everything
  • gulp watch - start watch
  • gulp clean - clean build directory
  • gulp connect - start server
  • gulp html:build - HTML build
  • gulp jshint:build - check JS for errors
  • gulp js:build - JS build
  • gulp sprites:build - sprite build
  • gulp image:build - static image build
  • gulp imagecontent:build - dynamic image build
  • gulp cssOwn:build - custom css build
  • gulp cssVendor:build - external CSS build
  • gulp css:build - general CSS build
  • gulp fonts:build - font build
  • gulp htaccess:build - build.htaccess

At this point, the configuration of gulpfile.js is complete.

Copy the starter package to the project

First, let's go through the console in the folder where we are developing, for example, cd develop/example and copy everything from the start package directory to our project cp -a ~/develop/start/. ~/develop/example/

This method of copying is most convenient, because. will accurately copy everything, including hidden .gitignore files, etc.

Conclusion

Using this guide, we have prepared a starter package for using Gulp in our projects for Front-end development.

This package is also available on GitHub.

Post Scriptum

This article is not final and will be updated depending on the changes and improvements.