Building với Gulp
Tối ưu hóa tài sản trang web và thử nghiệm thiết kế trên nhiều trình duyệt khác nhau chắc chắn không phải là một phần thú vị nhất của quá trình thiết kế. Công việc trên gồm các nhiệm vụ lặp đi lặp lại, rất nhàm chán và thiếu tính hiệu quả. May mắn thay, ta có thể dùng các công cụ để giải quyết công ...
Tối ưu hóa tài sản trang web và thử nghiệm thiết kế trên nhiều trình duyệt khác nhau chắc chắn không phải là một phần thú vị nhất của quá trình thiết kế. Công việc trên gồm các nhiệm vụ lặp đi lặp lại, rất nhàm chán và thiếu tính hiệu quả. May mắn thay, ta có thể dùng các công cụ để giải quyết công việc mang tính lặp đi lặp lại này nhằm tăng hiệu suất công việc. Gulp là một công cụ như thế.
Gulp là gì?
Gulp là một build system, có nghĩa là bạn có thể sử dụng nó để tự động hóa các công việc thông thường trong quá trình phát triển Website.Nó được xây dựng trên nền Node.js, và cả Gulp source hay Gulp files nơi bạn định nghĩa các task được viết bằng Javascript (hoặc CoffeeScript). Nếu bạn là một front-end developer thì Gulp gần như trở thành một build system hoàn hảo. Bạn có thể viết các tasks cho việc phân tích cú pháp và tự động biên dịch khi các tập tin được chỉ định có sự thay đổi.
Bản thân Gulp thì không thực hiện gì nhiều, nhưng với một lượng lớn pulgin có sẵn mà bạn có thể dễ dàng tìm kiếm trên các trang pulgin hoặc tìm với từ khóa gulpplugin ngay trên NPM. Ví dụ, các plugins để chạy JSHint, biên dịch CoffeeScript, chạy Mocha Tests hay thậm chí cập nhật số phiên bản của bạn.
Cài đặt Gulp
Việc cài đặt Gulp tương đối dễ dàng. Nếu bạn chưa cài Node.js, bạn cần cài Node.js theo hướng dẫn có trên trang chủ của NodeJs.
Install Gulp global
$ npm install --global gulp
Install Gulp in project
$ npm install --save-dev gulp
Sử dụng Gulp
Hãy tạo một Gulp task là một file Javascript thu nhỏ. Tạo một file với tên là gulpfile.js. Chúng ta sẽ định nghĩa các task của Gulp ở đây, và chúng sẽ được chạy bởi gulp command. Đặt đoạn code dưới đây vào trong file gulpfile.js:
var gulp = require('gulp'), uglify = require('gulp-uglify'); gulp.task('minify', function () { gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build')) });
Để cài đặt trên pulgins ví dụ gulp-uglify chúng ta chỉ cần chạy lệnh npm install --save-dev gulp-uglify NPM sẽ tự động cài đặt và chúng ta chỉ cần sử dụng plugin đó với một định nghĩa như một object bằng cú pháp:
var gulp = require('gulp'), uglify = require('gulp-uglify');
Chúng ta sẽ định nghĩa một task có tên là minify, khi chạy sẽ gọi đến function ở argument thứ hai:
gulp.task('minify', function () { });
Cuối cùng chúng ta sẽ định nghĩa những gì mà task của chúng ta sẽ thực hiện ở trong function đó:
gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build'))
Trừ phi bạn đã quen với streams, nếu không đoạn code trên không có ý nghĩa nhiều với bạn. Sau đây tôi sẽ giải thích về streams trong Gulp.
Streams
Streams cho phép bạn vượt qua một số dữ liệu thông qua một số function nhỏ, ở đó sẽ sửa đổi các dữ liệu và sau đó chuyển các dữ liệu đã sửa đổi đến các function tiếp theo. Trong ví dụ ở trên, function gulp.src() sẽ cần một string dẫn đến một file hoặc nhiều files mà chúng ta cần buil. Tạo một stream đại diện cho các objects của files, sau đó thông qua hoăc pipep tới function uglify(), function này sẽ sử dụng files với src ở trên và tạo ra các object files mới với code đã được thu nhỏ. Files đầu ra sẽ được tạo ra ở function gulp.dest(). Dưới đây là sơ đồ mô tả những gì đã diễn ra:
Khi sử dụng duy nhất 1 task, function trên dường như là không đủ. Xem tiếp đoạn code dưới đây:
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')); });
Để chạy function trên bạn cần cài đặt gulp, gulp-jshint, gulp-uglify, và gulp-concat. Task trên sẽ lấy tất cả các file có đuôi js ở trong thư mục js/, chạy JSHint trên chúng in ra output, thu nhỏ chúng rồi ghép chúng với nhau lưu vào một file build/app.js
Gulp.src()
Function gulp.src()sẽ lấy một hoặc nhiều file trùng khớp với điều kiện trong src() và trả về một stream có thể piped tới các plugins.
Gulp sử dụng Node-glob để lấy file từ glob hoặc globs đã được chỉ định. Cách sử dụng rất dễ dàng:
- js/app.js Tìm chính xác file.
- js/*.js Tìm kiếm tất các file kết thúc bằng ```.js`` và nằm trong thư mục js.
- js/**/*.js Tìm kiếm tất cả các file kết thúc bằng .js ở trong thư mục js/ và tất cả thư mục con của nó.
- !js/app.js Tìm kiếm tất cả các file trong thư mục ngoại trừ file app.js
- *.+(js|css) Tìm kiếm tất cả các file trong thư mục root có đuôi là .js và .css.
Những ví dụ trên là những ví dụ thông thường nhất được sử dụng trong Gulp. Nếu bạn muốn sử dụng nhiều hơn, tham khảo Minimatch. Nếu muốn thêm điều kiện để lấy files, chỉ cần kết hợp các điều kiện bên trong một mảng:
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
Defining Tasks
Để định nghĩa 1 task, sử dụng function gulp.task(). Khi định nghĩa một task đơn giản, function này cần 2 thuộc tính: tên của task và một function dùng để chạy.
gulp.task('greet', function () { console.log('Hello world!'); });
Khi chạy gulp greet sẽ nhận được kết quả là Hello world! được in ra trong console.
Một task cũng có thể gồm nhiều task khác. Khi muốn định nghĩa một task nhằm chạy 3 task khác css``,js,imgs```, chúng ta có thể quy định một mảng các tasks:
gulp.task('build', ['css', 'js', 'imgs']);
Chú ý là các task trên sẽ chạy không đồng bộ, có nghĩa là bạn không thể chắc chắn rằng task css sẽ chạy xong khi task js bắt đầu được. Để đảm bảo rằng một task được chạy sau khi một task khác chạy xong chúng ta có thể làm như sau:
gulp.task('css', ['greet'], function () { // Deal with CSS here });
Task css sẽ được chạy ngay sau khi task greet hoàn thành.
Default tasks
Bạn có thể định nghĩa một task mặc định khi chạy gulp với task name là default:
gulp.task('default', function () { // Your default task });
Plugins
Chúng ta có thể sử dụng một số plugins (hơn 600) với Gulp. Chúng có thể được tìm thấy tại Plugin page hoặc bẳng cách tìm kiếm với từ khóa gulpplugin trong npm.
Gulp-load-plugins
Một module rất hữu ích cho việc tự động load bất kỳ plugins nào từ package.json và gắn chúng vào một object.
var gulpLoadPlugins = require('gulp-load-plugins'), plugins = gulpLoadPlugins();
Package.json
{ "devDependencies": { "gulp-concat": "~2.2.0", "gulp-uglify": "~0.2.1", "gulp-jshint": "~1.5.1", "gulp": "~3.5.6" } }
Sau khi chạy gulp-load-plugins, chúng ta có thể sử dụng plugins với tên dạng camelCase ví dụ, sử dụng plugin gulp-ruby-sass bằng cú pháp plugins.rubySass sử dụng như dạng require thông thường.
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')); });
Watching files
Gulp có khả năng kiểm soát sự thay đổi của file và chạy một task hoặc nhiều task khi phát hiện sự thay đổi của file đó. Tính năng này rất tiện dụng, bạn có thể tưởng tượng rằng, khi bạn lưu một LESS file hoặc SASS file, Gulp sẽ đưa những thay đổi đó vào trong file CSS và tự động cập nhật nó trên trình duyệt. Bạn không cần phải reload lại trang hay làm gì cả.
gulp.task('watch', function () { gulp.watch('templates/*.tmpl.html', ['build']); });
khi ta thay đổi một file file template, task build sẽ được chạy và file html sẽ được tạo ra. Bạn cũng có thể đặt function watch trong một function callback:
gulp.watch('templates/*.tmpl.html', function (event) { console.log('Event type: ' + event.type); // added, changed, or deleted console.log('Event path: ' + event.path); // The path of the modified file });
Reloading Changes In The Browser
LiveReload
LiveReload liên kết với browswer extensions (bao gồm cả Chrome extensions) sẽ reload browswer mỗi khi phát hiện thấy sự thay đổi của một file. Nó có thể sử dụng với gulp-watch plugin hoặc với gulp.watch(). Ví dụ:
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()); });
Đoạn code trên sẽ xác định sự thay đổi của bất kỳ file .less nào trong thư mục less/, khi phát hiện thấy sự thay đổi, nó sẽ tạo ra CSS sau đó tự động reload lại browser.
BrowserSync
Tương tự với LiveReload, BrowserSync cũng tự động hiện thị những thay đổi trên browser, nhưng nó có nhiều chức năng hơn. Khi bạn tạo ra một thay đổi trong code, Browser hoặc là reload page, hoặc nếu file thay đổi là css sẽ injects css, điều đó có nghĩa là sẽ không cần refresh lại page.
Để cài đặt BrowserSync, chúng ta sẽ sử dụng npm:
npm install --save-dev browser-sync
Sử dụng như các plugins khác trong Gulp:
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' } }); });
Chạy gulp browser-sync sẽ kiểm soát tất cả thay đổi của file và sẽ bắt đầu một server trong thư mục app/.
Tổng kết
Như vậy, sử dụng Gulp sẽ rất tiện lợi, tăng hiệu suất và giúp công việc lập trình thuận tiện hơn. Hơn nữa với những hệ thống sử dụng nhiều CSS, JS đặc biệt là ReactJs (hoặc tương tự) thì việc sử dụng Gulp càng bộc lộ những yếu tố cần thiết và quan trọng của một build system. Một demo nhỏ, sử dụng Gulp để build CoffeeScript, Sass với Laravel 4.2