Browserify + Gulp + Babelify
在進入第二種方法前,首先先介紹一下會用到 Browserify、Gulp、Babelify 三種前端開發常會用到的工具:
- 如同官網上說明的:
Browserify lets you require('modules') in the browser by bundling up all of your dependencies.
,Browserify 是一個可以讓你在瀏覽器端也能使用像 Node 用的 CommonJS 規範一樣,用輸出(export)和引用(require)來管理模組。此外,也能使用許多在 NPM 中的模組
Gulp
是一個前端任務工具自動化管理工具。隨著前端工程的發展(Task Runner),我們在開發前端應用程式時有許多工作是必須重複進行,例如:打包文件、uglify、將 LESS 轉譯成一般的 CSS 的檔案,轉譯 ES6 語法等工作。若是使用一般手動的方式,往往會造成效率的低下,所以透過像是 Grunt、Gulp 這類的 Task Runner 不但可以提昇效率,也可以更方便管理這些任務。由於 Gulp 是透過 pipeline 方式來處理檔案,在使用上比起 Grunt 的方式直觀許多,所以這邊我們主要討論的是 Gulp
Babelify
是一個使用 Browserify 進行 Babel 轉換的外掛,你可以想成是一個翻譯機,可以將 React 中的JSX
或ES6
語法轉成瀏覽器相容的ES5
語法
初步了解了三種工具的概念後,接下來我們就開始我們的環境設置:
若是電腦中尚未安裝 Node(Node.js 是一個開放原始碼、跨平台的、可用於伺服器端和網路應用的 Google V8 引擎執行執行環境)和 NPM(Node 套件管理器 Node Package Manager。是一個以 JavaScript 編寫的軟體套件管理系統,預設環境為 Node.js,從 Node.js 0.6.3 版本開始,npm 被自動附帶在安裝包中)的話,請先 上官網安裝
用
npm
安裝browserify
用
npm
安裝gulp
、gulp-concat
、gulp-html-replace
、gulp-streamify
、gulp-uglify
、watchify
、vinyl-source-stream
開發環境用的套件(development dependencies)// 使用 npm install --save-dev 會將安裝的套件名稱和版本存放到 package.json 的 devDependencies 欄位中
$ npm install --save-dev gulp gulp-concat gulp-html-replace gulp-streamify gulp-uglify watchify vinyl-source-stream
安裝
babelify
、babel-preset-es2015
、babel-preset-react
,轉譯ES6
和JSX
開發環境用的套件,並於根目錄底下設定.babelrc
,設定轉譯規則(presets:es2015、react)和使用的外掛// 使用 npm install --save-dev 會將安裝的套件名稱和版本存放到 package.json 的 devDependencies 欄位中
$ npm install --save-dev babelify babel-preset-es2015 babel-preset-react
// filename: .babelrc
{
"presets": [
"es2015",
"react",
],
"plugins": []
}
安裝 react 和 react-dom
$ npm install --save react react-dom
撰寫 Component
// filename: ./app/index.js
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>
<h1>Hello, World!</h1>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<!-- filename: ./index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello React!</title>
</head>
<body>
<div id="app"></div>
<!-- build:js -->
<script src="./dist/src/bundle.js"></script>
<!-- endbuild -->
</body>
</html>
- 設定
gulpfile.js
// filename: gulpfile.js
// 引入所有需要的檔案
const gulp = require('gulp');
const uglify = require('gulp-uglify');
const htmlreplace = require('gulp-html-replace');
const source = require('vinyl-source-stream');
const browserify = require('browserify');
const watchify = require('watchify');
const babel = require('babelify');
const streamify = require('gulp-streamify');
// 檔案位置參數
const path = {
HTML: 'index.html',
MINIFIED_OUT: 'bundle.min.js',
OUT: 'bundle.js',
DEST: 'dist',
DEST_BUILD: 'dist/build',
DEST_SRC: 'dist/src',
ENTRY_POINT: './app/index.js'
};
// 複製 html 到 dist 資料夾中
gulp.task('copy', function(){
gulp.src(path.HTML)
.pipe(gulp.dest(path.DEST));
});
// 監聽檔案是否有變化,若有變化則重新編譯一次
gulp.task('watch', function() {
gulp.watch(path.HTML, ['copy']);
var watcher = watchify(browserify({
entries: [path.ENTRY_POINT],
transform: [babel],
debug: true,
}));
return watcher.on('update', function () {
watcher.bundle()
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC))
console.log('Updated');
})
.bundle()
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC));
});
// 執行 build production 的流程(包括 uglify、轉譯等)
gulp.task('copy', function(){
browserify({
entries: [path.ENTRY_POINT],
transform: [babel],
})
.bundle()
.pipe(source(path.MINIFIED_OUT))
.pipe(streamify(uglify(path.MINIFIED_OUT)))
.pipe(gulp.dest(path.DEST_BUILD));
});
// 將 script 引用換成 production 的檔案
gulp.task('replaceHTML', function(){
gulp.src(path.HTML)
.pipe(htmlreplace({
'js': 'build/' + path.MINIFIED_OUT
}))
.pipe(gulp.dest(path.DEST));
});
// 設定 NODE_ENV 為 production
gulp.task('apply-prod-environment', function() {
process.env.NODE_ENV = 'production';
});
// 若直接執行 gulp 會執行 gulp default 的任務:watch、copy。若跑 gulp production,則會執行 build、replaceHTML、apply-prod-environment
gulp.task('production', ['build', 'replaceHTML', 'apply-prod-environment']);
gulp.task('default', ['watch', 'copy']);
- 成果展示
到目前為止我們的資料夾的結構應該會是這樣:
接下來我們透過在終端機(terminal)下 gulp
指令來處理我們設定好的任務:
// 當只有輸入 gulp 沒有輸入任務名稱時,gulp 會自動執行 default 的任務,我們這邊會執行 `watch` 和 `copy` 的任務,前者會監聽 `./app/index.js` 是否有改變,有的話則更新。後者則是會把 `index.html` 複製到 `./dist/index.html`
$ gulp
當執行完 gulp
後,我們可以發現多了一個 dist
資料夾
如果我們是要進行 production
的應用程式開發的話,我們可以執行:
// 當輸入 gulp production 時,gulp 會執行 production 的任務,我們這邊會執行 replaceHTML
、build
和 apply-prod-environment
的任務,build
任務會進行轉譯和 uglify
。replaceHTML
會取代 index.html
註解中的 <script>
引入檔案,變成引入壓縮和 uglify
後的 ./dist/build/bundle.min.js
。apply-prod-environment
則是會更改 NODE_ENV
變數,讓環境設定改為 production
,有興趣的讀者可以參考React 官網說明
$ gulp production
此時我們可以在瀏覽器上打開我們的 ./dist/hello.html
,就可以看到 Hello, world!
了!
(image via srinisoundar、sitepoint、keyholesoftware、survivejs)
| 勘誤、提問或許願 |