概述
最近在使用vue框架重构公司的一个微信端产品,要想发挥vue的强大功能,离不开browserify或者webpack这些构建工具,基于这些构建工具可以在vue开发中使用ES6语法,单文件组件等特性,我个人更倾向于使用browserify构建工具,使用browserify工具可以在浏览器平台上提供像在node平台一样的开发体验,下面几篇文章将介绍下browserify构建的详细用法。
安装
cd app; //初始化项目 npm init //安装browserify npm install browserify --save-dev
基本用法
在package.json中的scripts属性中添加以下命令:
"xxx" : "browserify ./source/module.js -o ./dist/dist.js" 或者 "xxx" : "browserify ./source/module.js > ./dist/dist.js"
在当前目录打开命令窗口:
npm run xxx
即可在dist目录下看到打包后的dist.js文件。
browserify 后面的第一个参数表示要打包的前端程序的入口,-o或者>表示打包后的输出文件。browserify会根据入口文件中的require或者import(ES6,需要安装babel)自动完成依赖分析,并将依赖文件打包为一个单文件。
下面是API的调用方式:
var Browserify = require("browserify"); var fs = require("fs"); var b = new Browserify(); //入口文件 b.add("../source/module.js"); //打包输出 b.bundle().pipe(fs.createWriteStream("../dist/dist.js"));
将部分依赖文件打包为符合commonjs规范的模块,外部可以通过require调用其中暴露的api,输入结果仍为单文件
下面是测试代码,有三个模块(文件):modulea,moduleb,module,其中module依赖modulea和moduleb
modulea:
module.exports = { name:"moduleA", getName:function(){ console.log(this.name); } }
moduleb:
module.exports = { name:"moduleB", getName:function(){ return this.name; } }
module:
var moduleA = require("ma"); var moduleB = require("mb"); moduleA.getName();
命令脚本:
browserify -r ./source/modulea.js:ma -r ./source/moduleb.js:mb ./source/module.js > ./dist/bundle.js
新建index.html,源码如下:
<script type="text/javascript" src="./dist/bundle.js"></script><script type="text/javascript"> var mb = require("mb"); console.log(mb.getName()+"========"); </script>
控制台打印如下:
上述过程也可以通过调用API编码实现,结果和上面是一样的:
var browserify = require("browserify"); var path = require("path"); var fs = require("fs"); var sourcepath = path.resolve(__dirname,"../","source"); var dist = path.resolve(__dirname,"../","dist"); var b = browserify(); b.add(path.join(sourcepath,"module.js")); b.require(path.join(sourcepath,"modulea.js"),{expose:"ma"}); b.require(path.join(sourcepath,"moduleb.js"),{expose:"mb"}); b.bundle().pipe(fs.createWriteStream(path.join(dist,"bundle.js")));
将依赖模块独立打包,最终输出多个文件,模块间可以通过require调用
有些场景下,比如有多个页面,每个页面都需要依赖common.js,这个时候将每个页面的js打包为一个文件就不合适,commonjs的代码会重复出现在多个文件中,而且也不利于缓存优化。
browserify提供了三种方式支持多JS文件:
-i(–ignore),将依赖的文件以{}空对象替代,这个命令看起来没什么用处啊,依赖一个空的对象,不能提供任何属性和方法,暂时没发现这个命令的使用场景。 -u(–exclude),忽略依赖的对象,该依赖对象不会被打包,依赖的对象可以是第三方的或者是通过-r命令生成的另外一个bundle文件,可以通过-u命令指定一些第三方类库,比如vue的类库。 -x(external),-x指向的文件是通过-r命令生成的另外一个文件,该文件不会被打包。第一种方式目前不知道有什么用处,第三种方式打包的时候,我在win10平台上打包的文件路径有问题,需要对引用路径特别注意,尤其是调用API打包的时候。因此我推荐使用第二种打包方式。
举例:有两个文件base.js和demo2.js,其中base.js是基础类包,可能在多个页面中都需要,现在将base.js和demo2.js分别打包:
base.js:
module.exports = { name:"base", getName:function(){ return this.name; } }
demo2.js:
var com = require("common"); console.log(com.getName());
打包脚本:
browserify -r ./source/base.js:common > ./dist/common.js browserify -u common ./source/demo2.js > ./dist/bundle.js
index.html源码如下:
<script type="text/javascript" src="./dist/common.js"></script> <script type="text/javascript" src="./dist/bundle.js"></script> <script type="text/javascript"> var com = require("common"); console.log(com.getName()); </script>
控制台输出如下:
调用API打包源码如下:
var browserify = require("browserify"); var path = require("path"); var fs = require("fs"); var b = new browserify(); b.require(path.resolve(__dirname,"../source/base.js"),{ expose:"common" }); b.bundle().pipe(fs.createWriteStream("../dist/common.js")); var b2 = new browserify(); b2.exclude("common"); b2.add("../source/demo2.js"); b2.bundle().pipe(fs.createWriteStream("../dist/bundle.js"));
使用browserify构建工具可以直接使用一些原来只有在node平台上才有的API
比如url,path,stream,buffer,process等等。
transform
browserify提供了非常方便的transform接口来扩展打包行为。一个基本的transform接口定义格式如下:
var through2 = require("through2"); module.exports = function(file,opts){ return through2(function(chunk,enc,next){ //自定义transform逻辑 }); }
定义完成后,可以通过-t命令指定该文件,将自定义行为应用到打包中,也可以通过package.json的配置文件来配置过滤器:
"browserify":{ "transform":[ "./customTransform.js" ] }
许多知名的框架为了用户方便的使用browserify,都提供了现成的xxxify模块,比如babelify,vueify等。