本文原文和例子程序都在
https://github.com/jacobbubu/browserify-beefy-tutorial
Browserify-Beefy-Tutorial
对有基础的同学
如果你比较了解 browserify
和 beefy
,那么可以直接运行:npm install
安装所有的依赖包。
直接运行例子程序:
npm start -- examples/canvasTest.js
或者
npm start -- examples/rotatingTriangle.coffee
打开浏览器访问 http://localhost:9966
。
通过阅读 package.json
, start.sh
和 examples/canvasTest.js
就可以知道大致的用法了。
如果你不熟悉这种开发方法,请继续阅读。
概述
传统写前端的代码,一定要写 HTML,往往也离不开单独的 JS 文件,或者还要写一些 CSS 文件。一个例子程序最少两个文件是省不掉的,多了三四个文件也很常见,可能还要包括一些外部引用 (jQuery, bootstrap 之类的)。
最近在准备 WebGL 的教程,需要快速地撰写例子代码。WebGL 的用例代码和一般的网页开发教程不同,往往就是一个 Canvas
,剩下的就是 JavaScript
代码了。如果你熟悉 Node.JS 那么就很适合用 browserify
和 beefy
来加快开发速度了。
让我们先来看看我的需求有哪些:
需求
- Web 页面需要提供一个 WebGL 类型的
Canvas
。 - Canvas 可以随着窗口拉伸而变化,其中内容自动刷新。
- 能够调用
requestAnimationFrame
,并且计算两次调用间的时间差,便于实现动画。 - 一个显示 FPS (Frame Per Second) 的组件,能够显示当前的程序的执行帧率。
- 一个
Toggled Button
,让用户能够在 "启动" 和 "停止" 之间切换。 - 支持键盘事件,用于简单的动画控制,例如速度。
- 例子代码可以直接用
CoffeeScript
编写。 - 易于安装和执行。
- 开发调试时候支持 live-reload,这样调试效率会高很多。
局部安装
大部分安装 browserify
和 beefy
的说明都是全局安装:
npm install -g browserify
,其实没有必要,完全可以局部安装到当前项目的目录下:
npm install browserify beefy coffee-script --save-dev
这样将把 browserify
、beefy
和 coffee-script
都安装到当前目录的 node_modules
子目录下。
安装到全局目录(/usr/local/bin
)的好处是只要安装一次,那么在各个项目中就无需重新安装,直接可以使用。安装到局部目录则可以避免不同项目间版本冲突,例如:老一些的项目只能和旧版本的 browserify
兼容,而新的项目在可以自由使用最新的 browserify
了。
我的习惯是尽量使用局部安装,仅对最常用的 Package 再多装一份全局的。
browserify
、beefy
和 coffee-script
都会在 node_modules\.bin
下放置自己的可执行程序。
当你运行 package.json
中 scripts
节点定义的脚本(也称为 npm scripts
)的时候,node_modules\.bin
会被加到搜索路径中。
所以运行 npm test
、npm start
,或者 npm run your-script --
,都会到 node_modules\.bin
中来搜索可执行程序。
如果当前项目仅包含一个例子程序,那么现在的配置也就够了。
大部分基于 Node.JS 的全栈程序员往往都用过或听说过 browserify
,不知道也没关系,可以直接到其网站获取详细信息 https://github.com/substack/node-browserify。
而 beefy
则很像 ecstatic
,本身提供了一个静态的 Web 服务器。但是它被设计为和 browserify
紧密集成,让基于 browserify
的开发过程更加流畅,如下文。
运行 JavaScript 例子
node_modules/.bin/beefy examples/canvasTest.js --live
用浏览器访问 localhost:9966
,可以看到浏览器中一个红色的矩形。
--live
意思是,当前目录下的文件变化时(包括 node_modules
中的文件),页面将自动刷新。
beefy
实现这种 live-reload
的方式很轻巧,它直接在当前页面中嵌入了和服务器通信的脚本(XHR
),定时比对目标文档的时间戳,不同则调用 window.location.reload
进行刷新。所以用 beefy
的 live-reload
无需浏览器安装任何插件。
当 --live
开关打开后,beefy
或监视当前目录下所有文件,甚至包括 node_modules
子目录下的变化。
如果你希望执行 beefy
的时候直接打开缺省浏览器,那么加上 --open
参数即可:
node_modules/.bin/beefy examples/canvasTest.js --live --open
npm start
如果嫌每次打入这么长一串路径繁琐,那么可以在 paclage.json
中设置 scripts
如下:
{
...
"scripts": {
"start": "beefy examples/canvasTest.js --live"
},
...
}
这样你每次只要键入 npm start
,即可启动 beefy
。npm scripts
在执行时,会缺省搜寻 node_modules/.bin
目录,因此我们不需要给 beefy
加上完整的路径。
参数
可是我们每次需要运行的例子可能是不一样的,不都是 canvasTest.js
(以我为例,我会将不同的例子放在 examples
目录下的不同文件中)。那么是否可以用传入的参数的方式来解决呢?答案是“不行”。
npm 2.0
之后,虽然可以通过 --
前缀来添加参数(--
之后的所有内容都会被认为是参数),但是这个参数只会被添加到执行的命令的尾部,而不是像 bash
脚本那样,用 $1
, $2
这样的方式来任意放置参数。
例如,package.json
的 scripts
声明如下
"scripts": {
"start": "beefy $1 --live"
},
当你执行:
npm start -- examples/canvasTest.js
那么实际上执行的是
beefy $1 --live examples/canvasTest.js
$1
并没有被输入参数代入,examples/canvasTest.js
被插入到了我们不希望的尾部。
加一个过渡 shell
既然如此,就只能退化到 shell
方式了。创建一个脚本,命名为: start.sh
,添加执行权限: chmod +x start.sh
。内容如下:
beefy $1 --live
package.json
的 scripts
的内容是:
"scripts": {
"start": "./start.sh"
},
这样,当你执行 npm start -- examples/canvasTest.js
实际执行的是:
beefy examples/canvasTest.js --live
这是我们想要的。
canvas-testbed
因为有了 browserify
,所以我们可以像写 Node.JS module 一样来写网页应用。最简单的例子就是 domready
,可以让你在 JS 程序中用 Node.JS 方式来响应 DOM Ready
事件 (浏览器兼容问题被封装在 domread
package 里面了),例如:
require('domready')(function () {
$('body').html('boosh
')
})
类似的专门用于 Web 前端开发的 Packages 很多,canvas-testbed
是专门用于 2D 或 WebGL Canvas 测试的 package。它会在 DOM 上自动添加一个 Canvas Element,响应 Window Resize 事件,甚至支持 requestAnimationFrame
动画回调,自动计算两次回调之间的时间差等。
具体用法请参见它自己的 GitHub Repo. (https://github.com/mattdesl/canvas-testbed).
我们这个教程就用到了: canvas-testbed
,toggle-button
,fps-component
,webgl-context
,keydown
和 gl-clear
。
支持 CoffeeScript
如果要直接支持 CoffeeScript 编写的用例,那么需要配置 browserify
以支持 CoffeeScript
。这需要做两个工作。
coffeeify
第一个工作是为 browserify
配置 transform
插件:
npm install coffeeify --save-dev
coffeeify
完成将 CoffeeScript
源程序编译为 JavaScript
,并且提供适合 browserify
消费的 stream
接口。
然后在 package.json
中添加配置项:
"browserify": {
"transform": [
"coffeeify"
]
}
browserify
会读取 package.json
中的配置信息。
extension
第二个工作是把 .coffee
文件扩展名添加到 browserify
可以默认载入的扩展名列表中,获得等同于 .js
的地位。这样,当你的代码中有 requrie './ex01'
这样的引用,browserify
可以将 ex01.coffee
这样的文件引入,否则你就必须显示地写成 requrie './ex01.coffee'
,感觉不太优雅。
这个参数只要添加到 start.sh
中即可,如下:
beefy $1 --live -- --extension='.coffee'
beefy
参数中的 --
表示其后的参数将被直接传递给 browserify
。
最后,你可以试试
npm start -- examples/rotatingTriangle.coffee
可以看到一个旋转的三角形,以及 FPS Meter,还有一个控制动画的 toggled button。你还可以试试用上下方向键调整三角形的旋转速度。
所有这些都是通过 Node.JS
Packages 来组合完成的,不需要创建自己的 HTML 和 CSS 文件。
总结
browserify
和 beefy
这种方法缺点就是对网页本身的 Looks and Feel 的控制能力比较弱。但是对于做实验和样例非常方面,也很有乐趣。
Enjoy!