Building with Gulp
===================
Original address Translation source
Optimizing the site resources and using different browser tests is not the most interesting part of the site design process, but many of the repetitive tasks in the process can be done automatically with the right tools, which makes it much more efficient, which is something that many developers find interesting.
Gulp is a build system that improves the process of website development by automating common tasks such as compiling pre-processing CSS, compressing JavaScript, and refreshing the browser. Through this article, we will know how to use Gulp to change the development process, thus making development faster and more efficient.
What is Gulp?
Gulp is a build system that developers can use to automate common tasks during site development. Gulp is built on node. js, so gulp source files and gulp files that you use to define tasks are written into JavaScript (or coffeescript). Front-end development engineers can also write tasks in their familiar language to lint JavaScript and CSS, parse templates, and compile less files when files change (of course, these are just a few examples).
Gulp itself cannot accomplish many tasks, but it has a large number of plugins available, developers can access the plug-in page or the NPM search Gulpplugin can see. For example, some plug-ins can be used to perform jshint, compile Coffeescript, perform mocha tests, and even update version numbers.
Comparing other building tools, such as grunt, and the recently popular broccoli, I'm sure Gulp will be better off (see "Why Gulp?" later). section), and I've compiled a list of build tools written using JavaScript for your reference.
Gulp is an open source project that can be found on GitHub.
Installing Gulp
The process of installing gulp is simple. First, you need to install the Gulp package globally:
NPM Install-g Gulp
Then, install gulp inside the project:
NPM Install--save-dev Gulp
Using Gulp
Now we create a gulp task to compress the JavaScript files. First create a file named Gulpfile.js, which is where you define the Gulp task, which can be run by Gulp command, and then put the following code inside the 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 ')});
Then run NPM install-–save-dev gulp-uglify in NPM to mount the Gulp-uglify and finally perform the task by running Gulp Minify. Assuming the JS directory has a app.js file, then a new app.js will be created in the compilation directory, it contains js/app.js compressed content. Think about it, what the hell happened?
We only did a little thing in the gulpfile.js. First, we load the Gulp and Gulp-uglify modules:
var gulp = require (' Gulp '), uglify = require (' gulp-uglify ');
Then we define a task called minify, which invokes the function when it executes, and this function acts as a second argument:
Gulp.task (' Minify ', function () {});
Finally, the difficulty is that we need to define what the task should do:
GULP.SRC (' Js/app.js ') . Pipe (Uglify ()) . Pipe (Gulp.dest (' Build '))
If you are familiar with the flow of data (and most front-end developers are not familiar with it), the code provided above does not make much sense to you.
STREAMS
Data streams can pass data through a series of small functions that modify the data and then pass the modified data to the next function.
In the example above, the GULP.SRC () function matches the number of a file or file (called "Glob") with a string, then creates an object stream to represent the files, and then passes it to the uglify () function, which accepts a file object after the file object is returned with a new compressed source file. Finally those output files are entered in the Gulp.dest () function and are saved.
The entire data flow process is as follows:
Functions do not play a big role when there is only one task. However, think carefully about 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 '));});
Before running this program, you will need to install Gulp,gulp-jshint,gulp-uglify and Gulp-concat first.
This task will let all the files match js/*.js (such as all JavaScript files in the JS directory), and execute Jshint, then print out the output, cancel the file indentation, and finally merge them, save as build/app.js, the whole process as shown:
If you're familiar with grunt, you'll notice that Gulp and grunt work differently. Instead of using a data stream, Grunt uses a file, performs a single task on the file, and then saves it to a new file, each of which repeats all processes, and the file system's frequent processing tasks cause grunt to run slower than gulp.
For more complete data flow knowledge, see "Stream Handbook".
GULP. SRC ()
The GULP.SRC () method enters a glob (such as a string that matches one or more files) or an Glob array, and then returns a stream of data that can be passed to the plug-in.
Gulp use Node-glob to get the files from the glob you specify, here are examples to illustrate, easy to understand:
- Js/app.js Exact matching files
- Js/*.js only matches all files with the. js suffix in the JS directory
- js/* *. js matches the JS directory and all of the files with the suffix. js in its sub-directory
- !js/app.js excludes js/app.js from matching results, which works well when you want to match all files except special files
- *.+ (JS|CSS) matches all files with a. js or. css suffix in the root directory
In addition, Gulp also has many other features, but it is not commonly used. If you want to learn more about features, check out the Minimatch documentation.
JS directory contains compressed and uncompressed JavaScript files, now we want to create a task to compress the files that have not yet been compressed, we need to match all the JavaScript files in the directory, and then exclude the suffix. min.js files:
GULP.SRC ([' Js/**/*.js ', '!js/**/*.min.js '])
Defining TASKS
The Gulp.task () function is typically used to define tasks. When you define a simple task, you need to pass in the task name and execute the function two properties.
Gulp.task (' Greet ', function () { console.log (' Hello world! ');});
The result of executing gulp greet is to print "Hello World" on the console.
A task can sometimes be a series of tasks. Suppose you want to define a task build to perform the three tasks of CSS, JS, IMGs, we can do this by specifying a task array instead of a function.
Gulp.task (' Build ', [' css ', ' js ', ' IMGs ');
These tasks are not at the same time, so you cannot think that the CSS task is over or not finished at the start of the JS task. To ensure that a task has ended before another task executes, you can combine functions and task arrays to specify their dependencies. For example, to define a CSS task, it is possible to check that the greet task has been executed before executing it:
Gulp.task (' CSS ', [' greet '], function () { //Deal with CSS here});
Now, when you execute a CSS task, gulp executes the greet task and then calls the function you defined after it finishes.
DEFAULT TASKS
You can define a task that is performed by default when the gulp starts running and name the task "default":
Gulp.task (' Default ', function () { //Your Default task});
PLUGINS
Gulp has over 600 plugins to choose from, and you can search the plugin page or NPM for Gulpplugin to browse the list of plugins. Some plugins that have "gulpfriendly" tags do not count as plug-ins, but can run properly on gulp. It is important to note that when searching directly in NPM, you cannot know if a plugin is on the blacklist (you will need to scroll to the bottom of the plugin page to see it).
Most plug-ins are easy to use, they all come with detailed documentation, and the calling method is the same (by passing the file object stream to it), which usually modifies the files (but there are some plugins exceptions, such as validators), and finally returns the new file to the next plugin.
Let us use the previous JS task to explain in detail:
var gulp = require (' Gulp '), jshint = require (' Gulp-jshint '), uglify = require (' gulp-uglify '), concat = Require (' Gulp-concat '); 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 '));});
Three plugins, gulp-jshint,gulp-uglify and Gulp-concat are used here. Developers can refer to the Readme file of the plugin, which has many configuration options, and the given initial value usually satisfies the requirement. The attentive reader may find that the Jshint plugin executes 2 times in the program, because the first execution of Jshint only attaches the Jshint attribute to the file object and has no output. You can read the properties of the jshint yourself or pass it to the default Jshint receive function or other receive functions, such as jshint-stylish.
The function of the other two plugins is clear: the Uglify () function compresses the code, and the Concat (' app.js ') function merges all the files into a file called App.js.
Gulp-load-plugins
I found the Gulp-load-plugin module useful in that it could automatically load arbitrary gulp plugins from the Package.json and attach them to an object. Its basic usage is as follows:
var gulploadplugins = require (' Gulp-load-plugins '), plugins = Gulploadplugins ();
You can write all the code to one line, but I don't recommend it.
After executing those code, the plug-in object already contains the plug-in and is named in a "camel-like" manner (for example, Gulp-ruby-sass will be loaded into Plugins.rubysass), which makes it easy to use. For example, the preceding JS task is simplified as follows:
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 ');});
Suppose the Package.json file looks like this:
{" devdependencies": { "gulp-concat": "~2.2.0", "gulp-uglify": "~0.2.1", "Gulp-jshint": "~1.5.1", "Gulp": "~3.5.6" }}
This example is short enough, but using longer, more complex gulp files simplifies them to one or two lines of code.
The gulp-load-plugins0.4.0 version released in early March added the lazy load feature to improve plug-in performance, because plugins are loaded when they are in use, and you don't have to worry about the performance of unused plug-ins in Package.json (but you need to clean them out). In other words, if you only need two plugins to perform a task, other unrelated plugins will not be loaded.
Watching FILES
Gulp can listen for changes to the file, and then perform one or more tasks when the file is changed. This feature is very useful (for me, this is probably the most useful feature in Gulp). You can save the less file, and then gulp will automatically convert it to a CSS file and update the browser.
Use the Gulp.watch () method to listen to a file, which accepts a glob or Glob array (as with GULP.SRC () and a task array to execute callbacks.
Let's take a look below, the build task can convert the template to HTML format, and then we want to define a watch task to listen for changes to the template file and convert the templates into HTML format. The watch function is used as follows:
Gulp.task (' Watch ', function () { gulp.watch (' templates/*.tmpl.html ', [' Build ']);});
Now, when you change a template file, the build task is executed and the HTML file is generated, or you can give the watch function a callback function instead of a task array. In this example, the callback function has an event object that contains information that triggers the callback function:
Gulp.watch (' templates/*.tmpl.html ', function (event) { Console.log (' Event type: ' + event.type);//added, changed, O R deleted Console.log (' Event path: ' + Event.path);//The path of the modified file});
Another very good feature of Gulp.watch () is to return to our well-known watcher. Use Watcher to listen for additional events or add files to watch. For example, when you perform a series of tasks and invoke a function, you can add a listener change event to the returned watcher:
var watcher = Gulp.watch (' templates/*.tmpl.html ', [' Build ']), Watcher.on (' Change ', function (event) { Console.log ( ' Event type: ' + Event.type '); Added, changed, or deleted console.log (' Event path: ' + Event.path ');//The path of the modified file});
In addition to the Change event, you can listen to many other events:
- End is triggered at the end of watcher (this means that the task or callback will not execute when the file changes)
- Error is triggered when error occurs
- Ready is triggered when a file is found and is being monitored
- NoMatch triggers when Glob does not match to any file
The Watcher object also contains some methods that can be called:
- Watcher.end () Stop watcher (to stop execution of subsequent tasks or callback functions)
- Watcher.files () returns a list of watcher listening files
- Watcher.add (glob) adds the file that matches the specified glob to the Watcher (also accepts the optional callback when the second parameter)
- Watcher.remove (filepath) removing individual files from watcher
Reloading changes in the Browser
You can use Gulp to load or update a Web page when a file is modified or the Gulp task is executed. The Livereload and Browsersync plugins can be used to implement loading of updated content in the browser.
Livereload
Livereload combines browser extensions (including Chrome extension) to update the Web page in real time when a file is found to be modified. It can be used with the Gulp-watch plugin or the Gulp-watch () function described earlier. Here is an example of a readme file in the Gulp-livereload repository:
var gulp = require (' gulp '), less = require (' gulp-less '), livereload = require (' Gulp-livereload '), watch = Require (' Gulp-watch '); Gulp.task (' Less ', function () { gulp.src (' less/*.less '). Pipe (Watch ()) . PIPE ( Less ()) . Pipe (gulp.dest (' CSS ')) . Pipe (Livereload ());});
This will hear all changes to the files that match the less/*.less. Once the changes are monitored, the CSS is generated and saved, and then the page is reloaded.
Browsersync
Brosersync's ability to show changes in the browser is very similar to livereload, but it has more features.
When you change the code, Browsersync will reload the page, or if it is a CSS file, it will be added directly into the CSS, the page does not need to be refreshed. This feature is useful when the site is forbidden to refresh. Assuming you're developing page 4th of a single page app, refreshing the page will cause you to go back to the start page. With Livereload, you need to click four times after each change of the code, and when you change the CSS, when you insert some changes, Browsersync will directly add the necessary changes to the CSS, there is no need to click Fallback.
Browsersync provides a great way to test Web pages in multiple browsers (see larger image).
Browsersync can also be synchronized between different browsers click Page, form action, scroll position. You can open a different browser on your computer and iphone and then do it. The links on all the devices will change, and when you scroll down the page, all the pages on the device will scroll down (usually smooth!). )。 When you enter text in a form, each window will have input. When you do not want this behavior, you can also turn this function off.
Browsersync does not need to use a browser plugin, because it can provide you with the file itself. (View larger image)
Browsersync does not need to use a browser plugin, because it can provide you with file services (if the files are dynamic, provide them with proxy services) and a scripting service to open the socket between the browser and the server. So far the use of this feature has been very smooth.
In fact Browsersync is not a plug-in for gulp, because Browsersync does not manipulate files like a plug-in. However, the Browsersync module on NPM can be called directly on the gulp.
First, you need to install it via NPM:
npm install --save-dev browser-sync
Then Gulpfile.js will start the Browsersync and listen for the file:
var gulp = require (' Gulp '), Browsersync = require (' Browser-sync '); Gulp.task (' Browser-sync ', function () { var Files = [ ' app/**/*.html ', ' app/assets/css/**/*.css ', ' app/assets/imgs/**/*.png ', ' App/assets/js /**/*.js ' ]; Browsersync.init (Files, { server: { baseDir: './app ' } });
After performing gulp Browser-sync, the changes of matching files are monitored and file services are provided for the app directory.
In addition, Browsersync's developers have written a lot about other uses of the Browsersync+gulp warehouse.
Why Gulp?
As mentioned earlier, Gulp is one of the few building tools developed using JavaScript, and there are other build tools that are not developed with JavaScript, such as rake, so why should we choose Gulp?
Two of the most popular building tools to develop with JavaScript are grunt and gulp. Grunt was very popular in the 2013 because it revolutionized the way many people develop websites, with thousands of plugins available to users, from linting, compression, and merge code, to the use of Bower installer packages, to start the Express service. These are very different from the Gulp, gulp only perform a single small task to process the file plug-in, because the task is JavaScript (and grunt use of a large object), do not need a plug-in, you just use the traditional method to start an express service.
The grunt task has a large number of configurations that reference a large number of object properties that you do not actually need, but the same task in Gulp may have only a few lines. Let's look at a simple gruntfile.js, which specifies a task that converts less to CSS, and then executes the autoprefixer:
Grunt.initconfig ({less : { development: { files: { "build/tmp/app.css": "Assets/app.less" } } }, autoprefixer: { options: { browsers: [' last 2 version ', ' IE 8 ', ' IE 9 ' }, Multiple_files: { expand:true, flatten:true, src: ' build/tmp/app.css ', dest: ' build/' } }}); Grunt.loadnpmtasks (' grunt-contrib-less '); Grunt.loadnpmtasks (' grunt-autoprefixer '); Grunt.registertask (' CSS ', [' Less ', ' autoprefixer ']);
In contrast to the gulpfile.js files, they perform the same tasks:
var gulp = require (' gulp '), less = require (' gulp-less '), Autoprefix = require (' gulp-autoprefixer '); Gulp.task ( ' CSS ', function () { gulp.src (' assets/app.less '). Pipe (less ()) . Pipe (Autoprefix (' last 2 version ', ' IE 8 ', IE 9 ') . Pipe (Gulp.dest (' Build '));});
Because grunt operates file systems more frequently than gulp, the gulp of using data streams is always faster than grunt. For a small less file, the gulpfile.js usually requires 6ms, while the gruntfile.js needs to be about 8 times times slower than the 50ms--. This is a simple example, and for long files, this number increases significantly.
Gulp Development Tutorials