In UNIX / Linux file systems, the human-readable address of a resource is defined by PATH. It is an environmental variable that tells the shell which directories to search for executable files (i.e., ready-to-run programs) in response to commands issued by a user.
开发基于Node.js的前端工具
知乎上有这样一个问题:为什么node出现之后,各种前端构建工具和手段才如雨后春笋般层出不穷?,里面的答案挺有意思的。其实自从有了Node.js, Jser们可以脱离浏览器做各种各样有趣的事,在开发中,各种JS库帮助我们改善开发流程,提高开发效率, 比如
webpack/babel
等等。今天这里我们就主要讲讲怎么基于Node.js来开发(小)工具,提高我们的工作效率,满足各种实际需要。
一. 相关前置知识
1. Environments
每当shell新开启一个会话时,shell都会生成environment,environment里都是些定义系统属性的变量。
很多程序都会用到这里的变量,比如
nvm
会用这里的NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/dist
作为代理服务器地址,去淘宝的源下载node来安装,提高速度。PATH
在environment这么多变量里,有一个变量需要特别注意,就是
PATH=/Users/creeper/git/depot_tools:/usr/local/sbin:/Users/creeper/.nvm/versions/node/v6.9.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
。PATH
指定了Shell从哪些目录去查找执行文件(PATH
在windows里可以通过环境变量去设置)。当我们在shell里输入比如
ls
时,其实shell会找到/bin/ls
来执行。2. shebang line(#!)与可执行文件
上面一段提到了可执行文件,在这里我们只讲其中的一块——
script
文件。任何以shebang line(#!)
开头的文件即可执行的脚本,其中shebang line
指定了用什么(解释器)来解释执行脚本。比如常见的python脚本,你可以看到第一行是这样的:
对node.js来说,
shebang line
通常这么写:对有这行的文件,当你shell里执行
./my_script
时,系统会调用node来解释执行my_script
文件。注意,
shebang line
是可以加上参数的,如#!/usr/bin/env node --harmony
。以常见的
webpack
为例,当你npm i webpack
之后,你可以找到这样一个文件node_modules/.bin/webpack
, 它即webpack
的可执行文件。你可以shell里执行node_modules/.bin/webpack
,那么会输出help信息。那么我们稍微看下
node_modules/.bin/webpack
这个文件:果然是
shebang line
加上js代码。3. 全局安装的npm包为什么可以在shell里直接使用?
接着上面两段,我们差不多明白用node.js写工具的原理了,和python没什么不同。
但是,我们全局安装的一些npm包,比如
grunt/gulp/webpack
,为什么可以直接在shell里执行呢,和ls
之类一样?其实就是因为:
全局安装的npm包安装的位置是固定的,可执行文件存放的位置也是固定的。比如我这里,全局包放在
/Users/creeper/.nvm/versions/node/v6.9.0/lib/node_modules
,可执行文件放在/Users/creeper/.nvm/versions/node/v6.9.0/bin
:当然,这里的路径都是我本机的,不同机器会有不一样的路径。另外,可执行文件用放在 这个词描述可能不准确,这里其实是 软链接(
symlink
)。/Users/creeper/.nvm/versions/node/v6.9.0/bin
这个路径是在环境变量PATH里的,所以当你 执行crn-cli
时,shell可以正确找到这个命令。4. 当
npm run command
时,我们是在做什么?我们一般的开发中,经常会用到
npm run command
,比如npm test
等等,这里简单补充下。npm run-script <command> [-- <args>...]
可以执行在package.json
的scripts
中的相应命令。上面是从
React
的package.json
截出的,当我们在shell里执行npm run build
时,其实执行的就是grunt build
。注意:除了shell已经存在的PATH,
npm run
会添加node_modules/.bin
到PATH里。也就是说,node_modules/.bin
的执行文件是可以直接执行的,不用node_modules/.bin/grunt build
这种。二. 结合实例来具体阐述工具编写
前面讲完了一些前置知识,下面结合实例来讲工具编写,主要是我们组实际用到的 :)
1. 图片处理--直接写JS
虽然前面讲了一大堆可执行文件相关的,但对一些一次性工作,我们其实可以直接写JS,然后node执行就好了。 这是最简单快捷的。
当我们shell里执行
node x.js --args
,args可以通过process.argv
来访问:可以看到
process.argv[0]
固定是node本身路径,process.argv[1]
是文件路径,process.argv.slice(2)
才是我们输入的参数。具体到我们这里图片处理(UED有很多图片处理工作):
需求: 有一大堆大图(几百张),请导出
640x420, 582×178, 284x178, 178x178, 268x106
五种尺寸(中心缩放/切割), 且每种尺寸有高斯模糊和正常两种。 方案: 手动PS处理肯定不行,所以 imagemagick(负责图片处理)+ JS(负责参数和一些额外工作,比如图片分类/改名)。核心代码:
使用:
注: 使用通配符时,你获取的参数是通配符匹配的文件列表(如前面代码所示),如果你想获取原字符串, 请用引号,如
node processImg.js "images/**/*.jpg"
。2. git仓库更新后重新编译静态网站--githook + npm script
http://guide.cui.design/
这个是某种程度的css组件开发(专注CSS),一些我们机票部门的公用组件,比如paybar这些,可以通过这个项目有个 公共的最优实现,并在各个应用中保持一致。
以上并没有难点,难点主要在部署:即我们希望每次提交后(gitlab),可以在我们组的服务器同步最新的代码, 有最新的预览,并且这些应该完全自动化的。
代码的同步我们用了gitlab的API(这块是我同事在做),但预览呢?
基于性能原因,第2种当然更好,所以我们选择hook仓库的
post-merge
(每册服务器本地仓库更新后调用)。稍微看下
post-merge
的内容:不能更简单了,但的确做到了自动化和高效。
注: 一个坑,需要注意
/usr/share/nginx/html/repos/Dolphin-UI/.git/hooks/post-merge
文件的权限, 没有执行权限会导致脚本执行失败。3.
sugar-cli
--npm packagesugar-cli
是我们组原型开发(除RN外)的工具,主要提供模版和css编译的功能。http://cui.design/
背景和需求: 原来还是基于PHP那一套开发原型,比较笨重;新的开发环境希望基于node.js,有简单 但足够的模板语法,支持一种(或多种)css预处理语言,易于部署(预览)等等。
结合这些需求,最终开发了一个npm包
sugar-cli
,只要全局安装后,一个命令即可快速开始开发:postcss/sass/less
全支持,完善的sourcemap。这里就不具体描述功能了,下面主要讲讲怎么开发一个cli工具。
核心很简单:代码(含shebang line) + package.json配置。
下面是
sugar-cli
中sugar static
(运行一个静态文件服务器)的实现:然后,我们需要在
package.json
中配置:bin
是个map,其中key是command,value 是对应可执行文件。当全局安装时,npm会symlink
这个可执行文件到prefix/bin
;本地安装时, 则symlink
这个可执行文件到./node_modules/.bin/
。 (这一段可配合上面 全局安装的npm包为什么可以在shell里直接使用? 一起食用)。结合这两个,我们即可轻松开发一个前端工具。剩下的我们可以发布到npm,然后请同学们试用即可。
三. Thanks
Thanks
有问题直接问我即可。