本文是依據 Browserify 官網及網路參考資料逐步學習記錄的內容

Browserify 讓我們可以在瀏覽器中使用Node.js 風格的模組,不管是 AMD / CMD / ES6 …..風格的模塊化,它都能認識,並且編譯成瀏覽器認識的JS。

Browserify 運作的方式,會先在代碼中以靜態分析(static analysis)搜尋有調用 require()的內容,彙整出調用依賴關係圖(dependency graph),並且將關鍵字解析成路徑,然後根據路徑找到檔案, 接著,檔案會被打包(bundle)成單一獨立的 javascript 檔案,讓你可以直接在網頁中直接使用。 並且,打包的檔案預設都會使用嚴格模式 ```use

接下來,開始介紹 Browserify 安裝方式及用法說明:

安裝 browserify

首先,安裝 browserify

CVT2HUGO: strict```
npm install -g browserify

安裝完畢後,接下來將陸續介紹如何透過 Browserify 來編譯 Node 風格的模組:

  • require(‘modules’)
  • exports

一、 require(‘modules’)

在 Node 的 require() 函式是用來載入外部的程式碼,且調用的方式有兩種

1.當你填寫的是 require(路徑),例如 require(’./foo.js’) ,將會直接從 ./ 或者 ../ 前往位置(例如 /beep/boop/bar.js),呼叫內容 2.如果直接填寫名稱的方式,例如 require(‘xyz’),Node 就會依照下邏輯方式進行搜索

/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz

如果每個目錄都有 xyz,Node會返回檢查package.json 裡的 main ,是否有指定xyz

{
  "name": "xyz",
  "version": "1.2.3",
  "main": "lib/abc.js"
}

如果沒有指定main,Node就會預設採用下列位置的檔案

/beep/node_modules/xyz/index.js

這裡將以 uniq 來進行 require() 演練,及如何透過 browserify 編譯出結果

範例

接下來,會透過一個 uniq modules 來示範

uniq 可以從陣列中刪除所有重複的值 安裝 uniq

npm install uniq

建立 Node require

接著,新增 main.js 並寫入底下內容

//main.js
var unique = require('uniq');

var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];

//檢查是否去除掉重複的值
console.log(unique(data));

執行 Node 檢視結果

我們先用 node 來檢視會出現甚麼結果

node main.js

輸出結果

[ 1, 2, 3, 4, 5, 6 ]

Browserify 轉譯檔案

接下來,用browserify 來轉譯main.js的結果,並且儲存為 bundle.js 語法如下:

browserify main.js -o bundle.js

或者,可以透過 > 操作子

browserify main.js > bundle.js

執行轉譯結果

建立一個 test.html,並且使用剛剛轉譯成功的 bundle.js, 可直接開啟瀏覽器,從開發者工具中察看 console

<html>
<body>
	<script src="bundle.js"></script>
</body>
</html>

輸出結果

Array(6)
0:1
1:2
2:3
3:4
4:5
5:6
length:6

#二、 export 當我們透過 require 載入模組, 當模組載入時,會返回module.exports的內容 當然,也可以直接使用 module.exports 的輔助方法 exports,照樣能夠正常返回結果 (建議統一使用module.exports) 首先,使用 module.exports 測試 foo.js

module.exports = function (n) { return n * 111 }

main.js

var foo = require('./foo.js');
console.log(foo(5));

然後執行```node

接下來用 exports 試試看

foo.js

CVT2HUGO: main.js```,就能看到輸出結果為555
exports.name = function() {
    console.log('My name is Adam');
};

main.js

var foo = require('./foo.js');
foo.name();

輸出結果為 My name is Adam

接下來,一樣將上面的結果進行 browserify 轉譯

browserify main.js > bundle.js

再檢查是否正常在瀏覽器上面執行

三、搭配第三方套件

這裡僅以jQuery來示範,其他第三方套件則依照同樣原則來使用即可。

jQuery

通常,我們會先前往jQuery官網,下載最新的檔案, 但現在,只要透過 npm 就能直接下載最新的檔案,再透過browserify 即可在瀏覽器中使用

首先,先安裝 jQuery,並且透過 –save 將jquery 自動加入 package.json 行列

npm install jquery --save

在main.js載入jquery並且使用 main.js

var $ = require('jquery');
$(function(){
	$("h1").hide();
	console.log('h1 hided');
});

用browserify將main.js打包成bundle.js

browserify main.js > bundle.js

編輯 test.html 內容

<body>
	<h1>Hello world</h1>

	<!--js-->
	<script type="text/javascript" src="bundle.js"></script>
</body>

其他

Gulp + Browserify

如果想在Gulp使用Browserify,不推薦使用 gulp-browserify

而是直接 require(‘browserify’) 即可,

先安裝 browserify 並儲存在本地gulp

npm install browserify --save

如果遇到下方錯誤

Refusing to install browserify as a dependency of itself

請檢查你的package.json name是否命名為 browserify,如果是就會引發衝突,請更名

另外,Gulp 使用的是 Vinyl File Object Stream,而不是普通的Node Stream,無法支援取得 Node stream 庫,

所以,需透過 vinyl-source-stream 把 Node Stream 轉換為Gulp支援的 Vinyl File Object Stream,讓一般的 Node Stream 可以連結到 Gulp體系。(詳細可參考 這裡)

npm install vinyl-source-stream --save

順帶一提,vinyl-source-stream 和gulp.src()一樣,會依照來源名進行新增,因此可搭配gulp.dest()將檔案複製到指定位置,因此不必再寫使用 gulp-rename 重新命名

另外,一定要確認有在 package.json 加入 babelify package.json

{
  "browserify": {
    "transform": [["babelify", { "presets": ["latest"] }]]
  },
  "name": "browserifys",
  "version": "1.0.0",
  "babel": {
    "plugins": [
      [
        "transform-runtime",
        {
          "helpers": false,
          "polyfill": false,
          "regenerator": true,
          "moduleName": "babel-runtime"
        }
      ]
    ]
  },
  ...
}

範例如下:

gulpfile.js

var browserify = require('browserify'),
    gulp = require('gulp'),
    source = require('vinyl-source-stream');//returns a streaming vinyl object where as uglify expects buffered vinyl file objects.

gulp.task('browserify', function() {
    return browserify('./main.js')
        .bundle()
        // pass desired output filename to vinyl-source-stream
        .pipe(source('boundle.js'))
        .pipe(gulp.dest('./'));
});

gulp.task('default',['browserify']);

進階一點的使用方式: gulpfile.js

var browserify = require('browserify'),
    gulp = require('gulp'),
    uglify =  require('gulp-uglify'),//will compress source code
    source = require('vinyl-source-stream'),//returns a streaming vinyl object where as uglify expects buffered vinyl file objects.
    buffer     = require('vinyl-buffer');// will convert streaming vinyl files to use buffer. 

gulp.task('browserify', function() {
    return browserify('./main.js')
        .bundle()
        // pass desired output filename to vinyl-source-stream
        .pipe(source('boundle.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./'));
});

gulp.task('default',['browserify']);

watchify 即時監聽

將上面 browserify修改成監聽模式,先安裝 watchify

npm install watchify --save

要等到檔案變更之後,才會觸發 gulpfile.js

var browserify = require('browserify'),
    gulp = require('gulp'),
    watchify = require('watchify'),//watchify
    source = require('vinyl-source-stream');//returns a streaming vinyl object where as uglify expects buffered vinyl file objects.

var b = browserify({
  entries: ['./main.js'],
  cache: {},// required for watchify
  packageCache: {},// required for watchify
  plugin: [watchify]
});
 
function bundle() {
    return b.bundle()
        // pass desired output filename to vinyl-source-stream
        .pipe(source('boundle.js'))
        .pipe(gulp.dest('./'));
}
bundle();

b.on('update', bundle);

gulp.task('default');