(Bài tiếp) Tác vụ watch

Trong phần này tiếp tục nâng cao một chút những gì đã biết ở Thiết lập Grunt chạy 1 tác vụ đơn giản , chi tiết hơn về file cấu hình các tác vụ Gruntfile.js. Nhớ tiếp tục sử dụng dự án myproject01 ở phần trước.

Target trong Gruntfile.js

Trong ví dụ trước ta đã tạo ra một target có tên build cho tác vụ uglify. Target là một tình huống, trường hợp chạy tác vụ cụ thể, với mỗi tác vụ bạn có thể tạo ra nhiều target, sau đó tùy tình huống mà bạn muốn tác vụ chạy với target nào.

Trở lại file Gruntfile.js cũ ta thêm vào một target tên là debug với nội dung như sau:

module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        uglify: {
            options: {
                banner: '/*! Xuanthulab <%= grunt.template.today("yyyy-mm-dd") %> */\n'
            },

            build: {
                files: {
                    'build/hello.min.js' : ['src/hello.js']
                }
            },
    
            debug: {
                files: {
                    'debug/hello_debug.min.js' : ['src/hello.js']
                }
            }
        }
    });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['uglify']);                //grunt


  grunt.registerTask('debug', ['uglify:debug']);            //grunt debug
  grunt.registerTask('release', ['uglify:build']);          //grunt release

}

Ở trên ta đã thêm một target là debug vào, ở target này thì tạo ra file debug/hello_debug.min.js từ file nguồn. Vậy trong tác vụ uglify có 2 target: builddebug

Cũng để ý các hàm đăng ký tác vụ grunt.registerTask, có 3 trường hợp đăng ký tương ứng với 3 kiểu chạy lệnh grunt

Nếu chạy lệnh:

# grunt

Trường hợp này không chỉ ra tham số nào, nó sẽ chạy các tác vụ đăng ký trong default, và trong đăng ký này chỉ ra chạy tất cả các target của uglify (do ['uglify']). Và kết quả chạy sẽ có cả build/hello.min.jsdebug/hello_debug.min.js

Nếu chạy lệnh:

# grunt debug

Nó sẽ chạy các tác vụ đăng ký với tên debug ở hàm grunt.registerTask, nhìn vào trường hợp này nó chỉ ra là chạy tác vụ uglify với target là debug. Do vậy kết quả sẽ chỉ là file: debug/hello_debug.min.js

Tương tự, nếu chạy lệnh:

# grunt release

Target build sẽ thực hiện, và kết quả chỉ là file build/hello.min.js

Giờ bạn hãy thực hành lại các ví dụ trên, trước mỗi lần chạy grunt hãy xóa thư mục build, debug để xem kết quả chạy task.

Tải code ví dụ dự án trên về bằng git

git clone git@github.com:xuanthulabnet/grunt-example.git
cd grunt-example
git checkout vd2.1
npm install

Thực hiện nhiều tác vụ

Phần này sẽ phức tạp hóa dự án lên một chút, giờ trong dự án myproject01 ngoài file nguồn src/hello.js bạn tạo thêm một file nguồn JS nữa, giả sử tên là src/ab.js, trong đó chứa đoạn mã JS bất kỳ nào đó do bạn viết, ví dụ để phức tạp hóa một chút, bạn sẽ viết một lớp JS theo chuẩn ES6.

src/ab.js
class User {
    constructor(name) {
        this.name = name;
    }

    showinfo() {
        console.log(this.name);
    }
}

var user = new User('xuanthulab');
user.showinfo();

Giờ bạn mong muốn thi hành các tác vụ sau trên target mặc định (tức là mỗi khi gõ lệnh grunt không tham số):

  1. Nối nội dung 2 file nguồn hello.jsab.js thành một file lưu tại tmp/all.js
  2. Kiểm tra lại mã, cú pháp JS trong file tmp/all.js xem có cảnh báo, lỗi gì không, nếu không thì làm bước tiếp theo
  3. Do JS bạn có viết với chuẩn ES6, bạn muốn tự động convert mã tmp/all.js sao cho tương thích ngược với các trình duyệt cũ không hỗ trợ ES6. Mã convert được lưu ở tmp/all_back.js
  4. File tmp/all_back.js được nén lại thành file build/hello.min.js
  5. Cuối cùng là xóa toàn bộ những file tạm lưu ra tại thư mục tmp

Giờ ta sẽ thiết lập các package và cấu hình thi hành các tác vụ trên

1) Nối các file bằng concat

Tác vụ nối file concat cung cấp bằng package plugin grunt-contrib-concat (v 1.0.1), do vậy cần thêm vào package.json nội dung:

"grunt-contrib-concat": "~1.0.1"

Trong Gruntfile.js thêm tác vụ concat nối 2 file hello.js, ab.js thành file tmp/all.js như sau:

concat: {
  build: {
    files: {
        'tmp/all.js' : ['src/hello.js', 'src/ab.js']
    }
  }
},

2) Kiểm tra cú pháp Javascript

Để kiểm tra cú pháp JS, ta sử dụng package cung cấp tác vụ jshint grunt-contrib-jshint (V 2.0.0) thêm vào package.json nội dung:

"grunt-contrib-jshint": "2.0.0"

Để kiểm tra cú pháp file tmp/all.js thêm vào task vụ có tên jshint

jshint: {
    options: {
        '-W015': true,
        "esversion": 6
      },
    build: {
      src: ['tmp/all.js']
    },
  },

Dòng "esversion": 6 thiết lập chấp nhận code viết theo ES6.

3) Convert mã JS ES6 tương thích với phiên bản cũ

Để làm điều này ta sử dụng trình biên dịch JS có tên là Babel, đây là module phức tạp, đầu tiên bạn cài đặt core của nó bằng lệnh:

# npm install --save-dev @babel/core @babel/preset-env

Tác vụ sử dụng cung Babel có tên là babel cung cấp qua Package grunt-babel (V 8.0.0), thêm vào package.json nội dung:

"grunt-babel": "^8.0.0",

Tạo ra tác vụ babel để chuyển mã tmp/all.js sang dạng tương thích với trình duyệt cũ lưu tại tmp/all_back.js

babel: {
    options: {
        presets: ['@babel/preset-env']
      },
      build: {
        files: {
          'tmp/all_back.js': 'tmp/all.js'
        }
      }
},

4) Nén file JS

Nén file thì dùng tác vụ uglify đã biết từ ví dụ trước

uglify: {
    options: {
        banner: '/*! Dòng này chèn vào đầu file <%= grunt.template.today("yyyy-mm-dd") %> */\n'
    },

    build: {
        files: {
            'build/hello.min.js' : ['tmp/all_back.js']
        }
    },
},

5) Xóa file

Sua khi đã có hello.min.js muốn xóa đi các file tạm, dùng đến tác vụ có tên clean, cung cấp qua package grunt-contrib-clean, thêm vào package.json nội dung:

"grunt-contrib-clean": "2.0.0"

Tác vụ clean trong Gruntfile.js diễn tả như sau:

clean: {
    build: {
        src: ['tmp/*']
      },
}

Cuối cùng ta có các file package.json hoàn chỉnh như sau:

{
  "name": "my_project",
  "version": "0.1.0",
  "devDependencies": {
    "@babel/core": "^7.1.6",
    "@babel/preset-env": "^7.1.6",
    "grunt": "~0.4.5",
    "grunt-babel": "^8.0.0",
    "grunt-contrib-concat": "~1.0.1",
    "grunt-contrib-uglify": "~0.5.0",
    "grunt-contrib-jshint": "2.0.0",
    "grunt-contrib-clean": "2.0.0"
  }
}

Gõ lệnh sau để cài các gói trên

# npm install

Gruntfile.js hoàn chỉnh như sau:

module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        uglify: {
            options: {
                banner: '/*! Dòng này chèn vào đầu file <%= grunt.template.today("yyyy-mm-dd") %> */\n'
            },

            build: {
                files: {
                    'build/hello.min.js' : ['tmp/all_back.js']
                }
            },
        },
        concat: {
          build: {
            files: {
                'tmp/all.js' : ['src/hello.js', 'src/ab.js']
            }
          }
        },

        babel: {
            options: {
                presets: ['@babel/preset-env']
              },
              build: {
                files: {
                  'tmp/all_back.js': 'tmp/all.js'
                }
              }

        },

        jshint: {
            options: {
                '-W015': true,
                "esversion": 6
              },
            build: {
              src: ['tmp/all.js']
            },
          },

       clean: {
        build: {
            src: ['tmp/*']
          },
       }

    });

  //Nạp các plugin
  grunt.loadNpmTasks('grunt-babel');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-clean');


  //Thực hiện 5 tác vụ mặc định
  grunt.registerTask('default', [
                                 'concat:build',
                                 'jshint:build',
                                 'babel:build',
                                 'uglify:build',
                                 'clean'
                                ]);

}

Giờ mỗi khi cần thực hiện 5 tác vụ trên để thu được file hello.min.js bạn chỉ việc gõ grunt từ dòng lệnh:

# grunt
Running "concat:build" (concat) task

Running "jshint:build" (jshint) task
>> 1 file lint free.

Running "babel:build" (babel) task

Running "uglify:build" (uglify) task

Running "clean:build" (clean) task
>> 2 paths cleaned.

Done, without errors.

Tải code ví dụ dự án trên về bằng git

git clone git@github.com:xuanthulabnet/grunt-example.git
cd grunt-example
git checkout vd2.2
npm install

Đăng ký nhận bài viết mới
(Bài tiếp) Tác vụ watch