如何编写grunt 插件

2025-05-16 11:08:31
推荐回答(1个)
回答1:

一,准备环境 Grunt团队提供了一个yeoman generator 可以自动生成一个插件模板,使用yeoman之前需要先安装: npm install -g yo 然后我们需要安装对应的 generator: npm install -g generator-gruntplugin 然后就可以创建一个目录来放你的插件,并且使用yeoman来生成模板比如: mkdir ~/my-grunt-plugin cd ~/my-grunt-plugin yo gruntplugin 执行上述最后一条命令的时候会有一个交互式问答,填好所有信息之后就会生成一个如下的文件结构: - Gruntfile.js - README.md - node_modules/ - package.json - tasks/ - test/ - tmp/ 其中我们插件的代码在 tasks/ my_test.js文件中,这里的文件名是你在之前填写的插件名。 这里的Gruntfile主要定义的是测试任务,默认情况下有两个测试,并且执行grunt不会出错。 二,模板代码结构 这个默认的插件功能非常简单,就是把几个文件内容合并,并且可以在后面追加一段文字。 在Grunt.file中定义了my_test任务,有两个分别如下: [javascript] view plaincopy my_test: { default_options: { options: { }, files: { 'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123'] } }, custom_options: { options: { placeholder: '?' }, files: { 'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123'] } } }, // Unit tests. nodeunit: { tests: ['test/*_test.js'] } 当执行grunt的时候会先执行my_test任务,然后执行nodeunit来测试任务是否正常输出结果。 可以看到,my_test任务是把 test/fixtures 下的两个文件处理并输出到 tmp/custom_options中,而且定义了不同的配置。 在test/expected目录下定义了希望的输出结果,在test.js中做测试的时候,只需要比较 /tmp下的文件内容和test/expected 中的内容是否相同即可。 这里是默认的 my_test.js 中的代码,可以看到他就是比较了tmp下的文件内容和 test/expected下的文件内容是否相同: [javascript] view plaincopy exports.my_test = { setUp: function (done) { // setup here if necessary done(); }, default_options: function (test) { test.expect(1); var actual = grunt.file.read('tmp/default_options'); var expected = grunt.file.read('test/expected/default_options'); test.equal(actual, expected, 'should describe what the default behavior is.'); test.done(); }, custom_options: function (test) { test.expect(1); var actual = grunt.file.read('tmp/custom_options'); var expected = grunt.file.read('test/expected/custom_options'); test.equal(actual, expected, 'should describe what the custom option(s) behavior is.'); test.done(); } }; 下面是my_test.js中的代码,它的主体部分逻辑非常简单,就是把所有的文件内容连接起来并写到指定的文件中。 [javascript] view plaincopy /* * my_test * * * Copyright (c) 2014 * Licensed under the MIT license. */ 'use strict'; module.exports = function (grunt) { // Please see the Grunt documentation for more information regarding task // creation: http://gruntjs.com/creating-tasks grunt.registerMultiTask('my_test', 'The best Grunt plugin ever.', function () { // Merge task-specific and/or target-specific options with these defaults. var options = this.options({ punctuation: '.', separator: ', ' }); // Iterate over all specified file groups. this.files.forEach(function (file) { // Concat specified files. var src = file.src.filter(function (filepath) { // Warn on and remove invalid source files (if nonull was set). if (!grunt.file.exists(filepath)) { grunt.log.warn('Source file "' + filepath + '" not found.'); return false; } else { return true; } }).map(function (filepath) { // Read file source. return grunt.file.read(filepath); }).join(grunt.util.normalizelf(options.separator)); // Handle options. src += options.punctuation; // Write the destination file. grunt.file.write(file.dest, src); // Print a success message. grunt.log.writeln('File "' + file.dest + '" created.'); }); }); }; 三,编写自己的代码 知道在哪里写代码和如何进行单元测试之后,就可以动手写自己的代码了。 我们先定义自己的配置项: [javascript] view plaincopy var options = this.options({ words: ['xxoo', 'ooxx'], placeholder: '*' }); 这里用户可以配置一个关键词列表,然后可以定义被屏蔽关键词的占位符。默认配置是把 xxoo 和 ooxx 替换成 *。 然后我们的只需要用关键词列表生成一个正则式并替换到原文件中的对应单词即可: [javascript] view plaincopy var r = new RegExp('(' + options.words.join("|") + ')', 'g'); src = src.replace(r, options.placeholder); 把上述代码放到文件操作的那几行代码中,如下: [javascript] view plaincopy this.files.forEach(function (file) { // Concat specified files. var src = file.src.filter(function (filepath) { // Warn on and remove invalid source files (if nonull was set). if (!grunt.file.exists(filepath)) { grunt.log.warn('Source file "' + filepath + '" not found.'); return false; } else { return true; } }).map(function (filepath) { // Read file source. return grunt.file.read(filepath); }).join(''); var r = new RegExp('(' + options.words.join("|") + ')', 'g'); src = src.replace(r, options.placeholder); // Write the destination file. grunt.file.write(file.dest, src); // Print a success message. grunt.log.writeln('File "' + file.dest + '" created.'); }); 显然如果执行grunt,会发现有两个测试错误。优秀的代码一定要有详尽的测试用例,我们来修改一下现有的测试文件就可以。 把 test/fixtures/testing 的内容改成 ‘abcxxoo’ 然后把 test/fixtures/123的内容改成 '1 2 3 xxoo’ 打开Gruntfile.js 把配置稍微改一下: [javascript] view plaincopy my_test: { default_options: { options: { }, files: { 'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123'] } }, custom_options: { options: { placeholder: '?' }, files: { 'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123'] } } }, 然后再执行 grunt 依然会报错,因为我们的任务和测试文件都改过了,所以需要把 测试的预期结果也改一下,看看插件的输出结果,是很容易知道应该怎么改 test/expected目录下的文件内容的。 到此为止,我们的插件代码和测试用例都写完了,npm publish 发布一下试试吧。