helinjiang

1 年前
  • 1825

    浏览
  • 1

    评论
  • 0

    收藏

Grunt插件快速开发笔记

本文作者:IMWeb helinjiang 原文出处:IMWeb社区 未经同意,禁止转载

最近写了两个Grunt插件(grunt-htmlstampgrunt-file-modify),已经用在自己的项目中,用得很开心。本文便是记录了Grunt插件开发的一些关键的点,作为笔记,比较简明扼要,更适合对Grunt有一些了解的同学,一些基础的知识请自行 Google 之。

本文中的演示在 windows 操作系统中,Linux 或 OS X 可能有一些小区别。

一、环境准备

1. 安装 Node.js

Node.js 官网 选择合适的版本下载并安装。安装完成之后,打开 cmd 命令窗口,输入 node -v ,如输出版本号,则证明安装成功。

2. 安装 grunt-cli

根据 Grunt 官方的文档 ,打开 cmd 命令窗口,输入 npm install -g grunt-cli 进行安装。安装完成之后,再输入 grunt -version ,如输出版本号,则证明安装成功。

注意:npm 默认的源下载包地址在国外,由于某些缘故,下载包的速度可能会比较慢,建议使用国内的镜像,例如 淘宝npm镜像 等。如果在内网使用,还可能涉及到配置代理才能正常访问。

3. 安装合适的 IDE

我推荐使用 webstorm ,因为它的调试功能很好用。当然其他的开发工具也是OK的,用得顺手就行。

4. 安装 Git

除非你不打算将你的插件使用 Git 来做版本管理(当然你也可以选择 SVN等),否则需要 windows 用户请前往 https://git-for-windows.github.io/ 下载安装;同时如果你需要可视化工具,可以安装完 Git 之后,再安装 TortoiseGit

5. 在 GitHub 中注册帐号

除非你不打算将你的插件使用 GitHub 来管理源码(当然你也有很多其他的选择),否则需要前往 https://github.com/ 进行注册。

6. 在 npm 中注册帐号

除非你不打算将你的插件上传到 npm 上,否则需要前往 https://www.npmjs.com/ 进行注册。

二、新建项目

1. Grunt 插件的命名

开发一个 Grunt 插件,首先得有个合(xiang)适(liang)的名字。按照约定,Grunt 插件是以 grunt- 开头命名,但要注意:

  • "grunt-contrib" 命名空间保留给 Grunt 团队维护的task使用,我们要避免使用;
  • 确定好名字之后,请在 npm 官网 中搜索这个名字是否已经被占用了,如已被占用,请更换名字。

在本文的示例中,我们姑且将我们的这个插件叫做 grunt-mytest

2. 新建工程

确定了插件名称,则新建工程。例如我们的工程路径为: D:\code\grunt-mytest

3. 新建 GitHub 仓库

虽然不是必须的,但很有必要建立一个仓库,用于源码管理和 issue 等跟踪。一般而言,如果你的插件是开源的话,推荐使用 GitHub ,国内的话还有 Git@OSC 等可选择。例如我们申请的github仓库地址为:https://github.com/helinjiang/grunt-mytest ,其过程为:

创建新的git仓库

三、使用项目脚手架

目前主要有两种方式能够快速生成项目脚手架,一种是官方推荐的使用 grunt-init 工具,另外一种是借助 Yeoman

方式一: grunt-init 和 grunt-init-gruntplugin

官方推荐的方式。参考 官方指引 ,整理如下:

1. 安装 grunt-init

通过 npm install -g grunt-init 命令安装 grunt-init 。

2. 安装 gruntplugin

通过 git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin 命令安装grunt插件模版。但注意如果在 windows 下,则需要保存的地址需要修改为 %USERPROFILE%\.grunt-init\gruntplugin,其中的 %USERPROFILE% 一般为 C:\Users\[user]

如果当前系统中未安装 git ,则直接到 GitHub 中下载 grunt-init-gruntplugin ,并将其中的内容放置在 C:\Users\[user]\.grunt-init\gruntplugin 目录中。

注意:window下无法直接将一个文件夹命名为 .grunt-init ,可以借助 cmd 命令,cdC:\Users\[user],然后输入命令:md .grunt-init

3. 执行 grunt-init gruntplugin

在 cmd 中,cdD:\code\grunt-mytest ,执行 grunt-init gruntplugin ,将出现交互式问答,一步一步进行即可,例如:

执行grunt-init gruntplugin命令

方式二: Yeoman 和 generator-gruntplugin

参考 generator-gruntplugin 文档指引,整理如下:

1. 安装 Yeoman

进入 Yeoman 官网,按照相应提示安装 Yeoman。

执行 npm install -g yo 即安装了Yeoman,并且执行 yo --version 来确定是否安装成功。

2. 安装 generator-gruntplugin

执行 npm install -g generator-gruntplugin 即可。

3. 执行 yo gruntplugin

在 cmd 中,cdD:\code\grunt-mytest ,执行 yo gruntplugin ,将出现交互式问答,一步一步进行即可。

四、开发前

在正式编写代码之前,有必要再补充点技能。

1. 脚手架的目录结构

脚手架存在的意义是为了提供范本,以便我们能够按照这个样子书写我们的插件。因此在动手写代码之前,我们先看看其目录结构(只展示重要的文件):

|-task
    |-mytest.js
|-test
    |-expected
        |-custom_options
        |-default_options
    |-fixtures
        |-123
        |-testing 
    |-mytest_test.js
|-Gruntfile.js
|-package.json

其中我们的task任务就在 /tast/mytest.js 中。而单元测试的用例则在 /test/mytest_test.js 中。自动生成的项目的构建任务很简单,就是合并多个文件,并提供了两个选项。当我们运行 grunt 命令之后,构建就开始了,并且还执行了单元测试。

2. 文档

我们需要一些必要的文档资料,包括 API 等:

由于 Grunt 本身就是基于 Node.js 开发的,因此理论上使用 Node.js 的 API 就能做很多事,但我们还是推荐尽量使用 Grunt 提供的 API ,它可以提高开发效率。

五、开发中

在我们的示例中,我们主要打交道的是 /tasks/mytest.js 文件,因为我们的 task 就是定义在这里。由于每个插件的目的不一样,因此无法讨论太多编程细节,这里只讨论几个点。

1. 不要闭门造车

每个 Grunt 插件存在,都有其特定的目的,但也无外乎是“对某些文件(src),依据某些配置(options),进行某些处理”,并且每个 task 任务还可能有多个 target 目标。最难的就是要熟悉它这一套是怎么玩的,熟悉了其规则(比如如何获得所有的合法src文件、如何保存文件、如何处理多target的场景等等),剩下的事情就很好办了。

如果我们的经验不够,最好的方式就是参考目前大量使用的插件是怎么玩的,尤其是官方提供的插件。比如按照对 src 文件的处理方式的不同,grunt-contrib-cleangrunt-contrib-copy 就属于两种典型代表。

grunt-contrib-clean 直接操作 src ,其典型用法如下。比较适合直接对原文件进行处理的场景,比如我的 grunt-file-modify

clean: {
    build: {
        src: ["path/to/dir/one", "path/to/dir/two"]
    }
    release: ["path/to/another/dir/one", "path/to/another/dir/two"]
}

grunt-contrib-copy 需要配置 src 和 dest,其典型用法如下。大部分的 Grunt 插件应该都是这种 。

copy: {
    build: {
        src: 'src/*',
        dest: 'dest/',
    },
    release: {
        files: [
            {
                expand: true,
                cwd: 'path/',
                src: ['**'],
                dest: 'dest/'
            },
        ],
    },
}

我之所以举这个例子,只是为了说明除了看 API 之外,也需要结合看看人家的代码,这样能够更深刻理解。

2. 断点,单步调试

在前文中我提到过推荐使用 webstorm ,主要是因为它断点调试非常容易。有一段时间里,我喜欢使用 console 平台打印日志来调试,后来发现这种方式效率极低;我知道应该也有一些同学和我一样,还没有完全习惯去单步调试,这也是为什么我要在此特意强调的。

请尝试用单步调试,因为在调试的过程中你可以发现很多的细节,这些细节单靠查资料和看文档是无法获得的。比如我在开发过程中,在 grunt.registerMultiTask 内很需要获得当前 task 执行的 target 名字,即执行 grunt copy:build 时,我能获得 target="build",而执行 grunt copy:release 时,我能获得 target="release" 。通过断点,我找到了三个可能的取值:

  • grunt.task.current.name: 目前调用的任务名字,两种情况值都为 “copy”,不符合我的预期
  • grunt.cli.tasks[0]: 最外层调用的task名字,分别为 target="copy:build"target="copy:release" ,不符合我的预期
  • this.target: 分别为 target="build"target="release" ,符合我的预期

使用debug找到target值

3. 按功能迭代

完成一个功能块,且测试无问题之后,及时合入代码,迭代开发。千万别一口气完成很多改动再合入,这样不仅无法跟踪代码合入情况,而且一旦出错之后回滚也成了大问题。

同时如果功能已经基本完成之后(当然你也可以一开始就这么做),可以使用 issue 来跟踪 bug 和新的需求。如果你使用的是 GitHub 来管理源码(可能其他的也有此功能),你新建了 issue 之后,如果合入代码时在合入记录中输入这个isuue的网址,那么,这个 issue 中自动会将本次合入记录进行管理,这也意味着你的每个 issue 都可以找到对应的代码合入记录了。你可以到 https://github.com/helinjiang/grunt-htmlstamp/issues/2 看效果:

使用issue来管理代码合入

六、单元测试

不要偷懒,一定要写对应的单元测试。可能有些人会愁麻烦,但就我的亲身经历而言,它带来的好处远远大于所谓的“麻烦”。尤其是你的功能增多时,你每次的修改都有可能影响到之前OK的代码,单靠自己手动检视代码是没法保证代码质量的。

在本例中,写单元测试用例只需要在 /test/mytest_test.js 中写就行了。

虽然测试用例完全覆盖所有场景是很难达到,也很费时间去写用例,但覆盖主要场景却是必须的。在代码合并或发布之前,一定要确保已经写的用例都通过了单元测试。

七、readme.md

脚手架已经帮我们生成了一份,我们只需要在此基础上进行完善即可。它是我们插件的说明,因此尽可能描述清楚用法,以便其他人能够快速上手使用你的插件。

八、发布到 npm

如果你已经在 https://www.npmjs.com/ 中注册了帐号,则首先要在你本地的环境中增加该用户信息。在 cmd 中输入 npm login ,按提示在客户端中进行登录。如果你没卸载 npm ,则一般只需要登录一次即可。

如果已经在客户端中登录过,cdD:\code\grunt-mytest ,执行 npm publish 即可。当然由于我们演示的是个示例,因此是不会真实发布到 npm 上面的。

发布成功之后,可以在 https://www.npmjs.com/ 进行搜索你的插件,或者直接输入 https://www.npmjs.com/package/grunt-mytest 就能进入到你插件的主页面了。

九、一些容易遇到的坑

  • 注意如果readme.md中有中文字符,一定要检查这个文件的编码格式为 utf-8,否则即便它在 GitHub 中显示正常,但在 npm 网站上面,中文会显示为乱码。
  • npm publish 到 npm 上时,npmjs.com的数据可能不会实时刷新,其reademe.md的信息也一样,有可能需要等待几分钟。同时,各种 npm 镜像同步也需要一点时间(一般也允许你手动触发同步)。
  • 在脚手架生成的交互式问答中,description 中千万别输入单引号或者双引号,否则生成的代码会出现问题(你可以自己亲自试一试)。即便使用转义符转义,还是可能会有一些意外的场景。
  • 如果我们修改了readme.md,每次 pull 了代码到 GitHub 上之后, GitHub 上显示的是最新的文档;但 我们执行 npm publish 到 npm 上时,却发现 npm 上面的文档并未更新。除非你同时修改了package.json中的版本号。

The README displayed on the site will not be updated unless a new version of your package is published, so you would need to run npm version patch and npm publish to have a documentation fix displayed on the site. —— Updating the package

1条评论

    您需要 注册 一个IMWeb账号或者 才能进行评论。