Browserify使用指南(轉)
讓瀏覽器加載Nodejs模塊
目前NPM上有二十多萬個NodeJS模塊,它們都是通過CMD的方式打包的,除了特定的可以使用CMD模塊加載器加載的模塊,大部分nodejs模塊無法直接使用到瀏覽器環境中。
Browserify是一個供瀏覽器環境使用的模塊打包工具,像在node環境一樣,也是通過require(‘modules‘)
來組織模塊之間的引用和依賴,既可以引用npm中的模塊,也可以引用自己寫的模塊,然後打包成js文件,再在頁面中通過<script>
標簽加載。
當然對於很多NodeJS模塊,比如涉及到io操作的模塊,就算通過browserify打包後肯定也無法運行在瀏覽器環境中,這種情況下就會用到為它們重寫的支持瀏覽器端的分支模塊,可以在browserify search搜索到這些模塊。
用例
比如寫一個入口main.js
文件,使用require()
來引用其它模塊,包括相對目錄中的‘./foo.js‘
和‘../lib/bar.js‘
,還有在node_modules/
目錄中的名為‘gamma‘
的模塊。
browserify通過node’s module lookup algorithm來查找
node_modules/
中的模塊)
// main.js
var foo = require(‘./foo.js‘);
var bar = require(‘../lib/bar.js‘);
var gamma = require(‘gamma‘);
var elem = document.getElementById(‘result‘);
var x = foo(100) + bar(‘baz‘);
elem.textContent = gamma(x);
眾所周知,這些被引用的模塊會用通過module.exports
或exports
輸出它們的功能接口:
// foo.js
module.exports = function (n) { return n * 111 }
接下來就可以用browserify
命令對它們進行打包了:
$ browserify main.js > bundle.js
main.js
和它所引用的模塊會按依賴序列整體打包到bundle.js
。
browserify使用required來查找
require()
依賴隊列。
接下來,就可以在html中加載這個文件<script src="bundle.js"></script>
安裝Browserify
$ npm install -g browserify
通過命令行使用
Usage: browserify [entry files] {OPTIONS}
常用選項:
--outfile, -o 指定打包後的輸出文件
如果不指定,將輸到stdout,比如shell
--require, -r 通過模塊名或文件路徑指定需要打包到bundle中的其他模塊
Optionally use a colon separator to set the target
--entry, -e 入口文件
--ignore, -i 打包過程中忽略依賴的某個文件,當成空模塊打包,引用它不會報錯
--exclude, -u 打包過程中排除依賴的某個文件,比忽略選項更嚴格,引用它會報錯
--external, -x 指定某個文件不要打包到bundle,它可能會打包在其他的bundle中,比如jquery會打包到公共的bundle中
--transform, -t 指定打包過程中使用的轉換模塊
--command, -c 指定打包過程中使用的命令行轉換
--standalone -s 生成UMD模式的bundle模塊,可以在AMD、CMD中使用
--debug -d 生成source maps,並被註釋到bundle.js的尾部
--help, -h 顯示幫助
高級選項:
--insert-globals, --ig, --fast [default: false]
如果設置為true,會跳過代碼分析,強制在每個模塊的閉包作用域中插入如下參數
process, global, __filename, and __dirname
優點: 打包速度快
缺點: 生成多余的參數
--insert-global-vars, --igv
需要在代碼分析中檢測和定義的全局變量,需要和--insert-globals一起使用
默認包括 __filename,__dirname,process,Buffer,global 用逗號分隔
--detect-globals, --dg [default: true]
在代碼分析過程中檢測全局變量 process, global, __filename, and __dirname
優點: 像npm模塊那樣工作
缺點: 打包速度慢
--ignore-missing, --im [default: false]
忽略 `require()` 引用
--noparse=FILE
對於默寫確定不包含`require()`的文件,忽略他們的解析過程(比如jquery),加快打包速度
--no-builtins
如果打包後的文件要在node環境中使用,請使用這個選項,保證node內置模塊不被打包到bundle中
--no-commondir
不是用相對路徑,__filename,__dirname會被解析成絕對路徑
--no-bundle-external
不打包擴展模塊
--bare
--no-builtins --no-commondir --insert-global-vars "__filename,__dirname" 的別名
如果bundle在node環境中運行,請使用--bare
--no-browser-field, --no-bf
忽略package.json中的browser屬性
如果bundle在node環境中運行
--node
--bare --no-browser-field 的別名
--full-paths
所有模塊都是用絕對路徑進行引用
--deps
輸出模塊的依賴序列(一個數組)
--list
輸出所有模塊的路徑列表
--extension=EXTENSION
指定有效的模塊文件擴展名
--global-transform=MODULE, -g MODULE
指定一個全局的轉換模塊
--plugin=MODULE, -p MODULE
註冊一個插件模塊
如何在轉換模塊和插件再插入參數項:
使用subarg語法在中括號中插入子命令,比如:
-t [ foo -x 3 --beep ]
會這樣執行
foo(file, { x: 3, beep: true })
nodejs內置模塊的轉換
理想情況下,大部分不涉及io操作的模塊可以在瀏覽器中直接運行。
對於nodejs內置模塊,在require()
它們的時候,會被轉換成如下模塊來打包,以適配瀏覽器環境。
- assert
- buffer
- console
- constants
- crypto
- domain
- events
- http
- https
- os
- path
- punycode
- querystring
- stream
- string_decoder
- timers
- tty
- url
- util
- vm
- zlib
另外, 如果是用到了如下5個全局變量,它們會在打包過程中被改寫成可以適配瀏覽器環境的。
- process
- Buffer
- global 全局變量window
- __filename - 文件名
- __dirname - 文件路徑
其他用例
在全局作用域中(模塊外部)引用指定模塊
$ browserify -r through -r duplexer -r ./my-file.js:my-module > bundle.js
在頁面中直接引用這些外部模塊
<script src="bundle.js"></script>
<script>
var through = require(‘through‘);
var duplexer = require(‘duplexer‘);
var myModule = require(‘my-module‘);
/* ... */
</script>
導出source maps文件
使用exorcist導出.js.map
文件
$ browserify main.js --debug | exorcist bundle.js.map > bundle.js
導出多個包
如果多個頁面的打包結果中包含公共的模塊,可以將公共模塊(common.js)單獨打包出來,以節省請求流量並優化緩存策略
# beep.js
var robot = require(‘./robot.js‘);
console.log(robot(‘beep‘));
# boop.js
var robot = require(‘./robot.js‘);
console.log(robot(‘boop‘));
這兩個文件都引用了robot.js
# robot.js
module.exports = function (s) { return s.toUpperCase() + ‘!‘ };
# 把公共的模塊打包成common.js
$ browserify -r ./robot.js > static/common.js
$ browserify -x ./robot.js beep.js > static/beep.js
$ browserify -x ./robot.js boop.js > static/boop.js
如何引用?
<!--beep.html-->
<script src="common.js"></script>
<script src="beep.js"></script>
<!--boop.html-->
<script src="common.js"></script>
<script src="boop.js"></script>
上面這個用例,還可以用插件解決,會更方便
api
Browserify本身也是一個nodejs模塊,提供的方法大致和上面介紹的命令行選項相同,具體的api請參考browserify methods,這裏不再敖述。
var browserify = require(‘browserify‘);
var b = browserify();
b.add(‘./browser/main.js‘);
b.bundle().pipe(process.stdout);
events api
//當文件被進行打包時出發,可以用來監聽文件變化來重新進行打包
b.on(‘file‘, function (file, id, parent) {})
b.pipeline.on(‘file‘, function (file, id, parent) {})
// 當每個package.json被讀取時觸發
b.on(‘package‘, function (pkg) {})
b.pipeline.on(‘package‘, function (pkg) {})
// 當執行`.bundle()`時觸發
b.on(‘bundle‘, function (bundle) {})
// 當執行`.reset()`時觸發
b.on(‘reset‘, function () {})
// 當一個文件被轉換時觸
b.on(‘transform‘, function (tr, file) {})
b.pipeline.on(‘transform‘, function (tr, file) {})
package.json
browserify會先通過package.json
中的"main"
屬性來查找模塊入口,如果沒有"main"
屬性,就在目錄中搜索"index.js"
文件。當然,package.json
中還定義了一些browserify特有的屬性:
browser屬性
“browser“屬性用來優先指定browserify打包是的模塊入口文件,這樣可以和"main"
屬性區分開
"browser": "./browser.js"
還可以指定細分的打包替換文件
"browser": {
"fs": "level-fs",
"./lib/ops.js": "./browser/opts.js"
}
browserify.transform
在package.json
中指定轉換模塊,可以打包過程中自動執行
"browserify": { "transform": [ "brfs" ] }
使用插件
對於一些更先進的用例,轉換模塊並不能滿足需求,插件是更適合的選擇。插件是以包實例為其第一個參數,其他屬性作為後面的參數。插件可以用來做一些轉換模塊做不到的花哨功能。比如factor-bundle插件可以用來自動生成多個入口文件共用的common.js模塊。
$ browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o bundle/y.js ] > bundle/common.js
參考鏈接
- Browserify插件列表
- Browserify轉換列表
- Browserify第三方工具
- Browserify參考手冊
- Browserify:瀏覽器加載Node.js模塊
- 通過Browserify在瀏覽器中使用NodeJS模塊
轉自:http://zhaoda.net/2015/10/16/browserify-guide/
Browserify使用指南(轉)