手把手教你基于 ES6 架構自己的 React Boilerplate 項目
React 技術之火爆無須多言,其與 webpack 的完美結合,也讓二者毋庸置疑的成為天生一對。為了進行 React 的快速和規范化開發,開源社區中涌現了很多 React + webpack 的 boilerplate 項目。通過使用這些 boilerplate ,我們可以快速的創建一個React項目的架構。
蔥哥 之前專門創建了一個Github項目用于收集這些 boilerplate : awesome-react-boilerplate 。當然這里不可能完整收錄,但是目前為止已經有近30個了。連boilerplate都這么多,真讓我們眼花繚亂,無從下手。
當然,由于每個人的使用習慣和技術背景的不同,每個 boilerplate 都會有自己的側重點,因此即便是公認比較好的boilerplate項目也未必適合所有人。我們拿到這些開源項目,只是知其然但是并不知其所以然。 蔥哥 相信,只有適合自己的,才是最好的。這就是本文的初衷, 蔥哥 會追根溯源,從項目開發的蠻荒階段開始,搭建開發環境,配置 webpack ,在 React 項目中使用 webpack ,搭建項目的測試環境,一步一步構建適合適合自己的 React + webpack 起始項目。
本文陸陸續續寫了將近一個月的時間,所使用的技術和依賴庫均選用目前最新版本,其間大大小小的坑踩過不知道多少。本文供入門參考,如果你是前端大牛,請直接忽略此文。當然,如果讀后覺得對你有幫助,還請關注 蔥哥的Github 。
TL;DR
將使用的技術棧
如前所述,本文的主要目的是構建適合適合自己的 React + webpack 起始項目。與其他多數類似項目不同的是,我們不僅要支持ES6,使用webpack,而且要搭建一套相對完整的單元測試和自動化測試體系。本文主要使用到的相關技術如下:
- React
- webpack
- babel
- ES6
- mocha
- chai
- sinon
- karma
- phantomJS
webpack快速入門
webpack介紹
Webpack是一個前端模塊管理工具,有點類似browserify,出自非死book的Instagram團隊,但功能比browserify更為強大,可以說是目前最為強大的前端模塊管理和打包工具。
Webpack將項目中的所有靜態資源都當做模塊,模塊之間可以互相依賴,由webpack對它們進行統一的管理和打包發布,下圖為官方網站說明:
webpack對React有著與生俱來的良好支持,隨著React的流行,webpack也成了React項目中必不可少的一部分。特別是隨著ES6的普及,使得webpack有了更廣闊的用武之地。
安裝配置webpack
安裝nodejs
安裝webpack之前,需要確認本機已經安裝好了nodejs。
如果還沒有安裝,請去 nodejs官網 下載安裝即可。這里使用的node版本是V4.4.1.
初始化項目環境
$ mkdir react_boilerplate
$ cd react_boilerplate\
$ npm init -y
Wrote to .\react_boilerplate\package.json:
{
"name": "react_boilerplate",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
npm init 加上一個 -y 選項會生成一個默認的 package.json ,關于這個文件,不是本文重點,在此不會詳述,可以參考 官方文檔 。可以簡單的理解,這個文件是用于管理項目里面的依賴包的。
設置.gitignore
如果我們使用git進行版本管理,一個.gitignore文件是必要的。這里我們可以先將項目需要安裝的node包目錄添加進去。
node_modules
使用 npm install 安裝的node包都會在 node_modules 目錄下,這個目錄是不需要commit到git的。
安裝webpack
安裝webpack很簡單,命令如下:
npm i webpack --save-dev
其中 --save-dev 表示該包為開發環境依賴包。安裝完后會生成一個 node_modules 目錄,并且在 package.json 文件中多出如下幾行:
......
"devDependencies": {
"webpack": "^1.13.0"
}
}
如果寫為 --save 則表示該包為生產環境依賴包,在 package.json 文件中會新增或者修改 dependencies 字段。
初始化項目結構和代碼
安裝完 webpack 后,我們可以給項目中增加一些內容了。項目的簡單結構如下圖所示:
app 目錄用于存放項目代碼, dist 目錄為編譯后的項目文件, webpack.config.js 為 webpack 的配置文件。
我們給項目中的文件添加一些簡單的代碼,首先是組件代碼:
app/component.js
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hello world';
return element;
};
然后需要一個入口文件,在入口文件中使用上面定義的組件:
app/index.js
var component = require('./component');
document.body.appendChild(component());
配置webpack
我們需要讓webpack知道如何處理我們的項目目錄結構,因此需要配置文件 webpack.config.js 。一個簡單的配置文件如下所示:
var webpack = require('webpack');
var path = require('path'); //引入node的path庫
var config = {
entry: ['./app/index.js'], //入口文件
output: {
path: path.resolve(__dirname, 'dist'), // 指定編譯后的代碼位置為 dist/bundle.js
filename: 'bundle.js'
},
module: {
loaders: [
// 為webpack指定loaders
//{ test: /\.js$/, loaders: ['babel'], exclude: /node_modules/ }
]
}
}
module.exports = config;
到目前為止,我們已經可以讓webpack工作了,在命令行執行
webpack
我們看到,會有一個新的文件 /dist/bundle.js 生成出來了。但是我們還需要一個html文件來加載編譯后的代碼,這就需要用到一個webpack插件: html-webpack-plugin 。
安裝 html-webpack-plugin
使用如下命令安裝:
npm install html-webpack-plugin --save-dev
然后在我們的 webpack.config.js 中增加下面幾行:
plugins: [
new HtmlwebpackPlugin({
title: 'React Biolerplate by Linghucong'
})
]
現在在命令行下再次執行 webpack 命令,會看到在 dist 目錄下生成了兩個文件: bundle.js 和 index.html 。其中 index.html 內容如下:
dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React Biolerplate by Linghucong</title>
</head>
<body>
<script src="bundle.js"></script></body>
</html>
有必要提一下,如果我們安裝webpack的時候使用的是全局安裝選項( npm install -g webpack ),可以在命令行中直接執行 webpack 命令;如果沒有使用 -g ,那么要用的 webpack 可執行文件位于:
./node_modules/.bin/webpack
我們可以在 package.json 中為此命令增加一個快捷方式:
# package.json
... other stuff
"scripts": {
"build": "./node_modules/.bin/webpack"
}
現在就可以直接使用命令 npm run build 來執行webpack了。
$ npm run build
> react_boilerplate@1.0.0 build D:\node\react_boilerplate
> webpack
Hash: cbf754a65493b4d791d7
Version: webpack 1.13.0
Time: 919ms
Asset Size Chunks Chunk Names
bundle.js 233 kB 0 [emitted] main
index.html 179 bytes [emitted]
[0] multi main 52 bytes {0} [built]
[75] ./app/index.js 82 bytes {0} [built]
[76] ./app/component.js 142 bytes {0} [built]
+ 74 hidden modules
Child html-webpack-plugin for "index.html":
+ 3 hidden modules
安裝 webpack-dev-server
webpack-dev-server 可以讓我們在本地啟動一個web服務器,使我們更方便的查看正在開發的項目。其安裝也十分簡單:
npm i webpack-dev-server --save-dev
然后在 webpack.config.js 文件中作如下修改:
# webpack.config.js
# ...
entry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:3000',
'./app/index.js' //入口文件
],
# ...
我們可以在 package.json 中增加 webpack-dev-server 的快捷方式:
# package.json
... other stuff
"scripts": {
"dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
"build": "./node_modules/.bin/webpack"
}
配置中指定web服務器端口號為3000,指定目錄為dist。
運行 npm run dev :
$ npm run dev
> react_boilerplate@1.0.0 dev D:\node\react_boilerplate
> webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist
......
Time: 1109ms
Asset Size Chunks Chunk Names
bundle.js 274 kB 0 [emitted] main
index.html 179 bytes [emitted]
chunk {0} bundle.js (main) 216 kB [rendered]
[0] multi main 52 bytes {0} [built]
......
......
......
[77] ./app/component.js 142 bytes {0} [built]
Child html-webpack-plugin for "index.html":
chunk {0} index.html 505 kB [rendered]
[0] ./~/html-webpack-plugin/lib/loader.js!./~/html-webpack-plugin/default_index.ejs 540 bytes {0} [buil
t]
[1] ./~/lodash/lodash.js 504 kB {0} [built]
[2] (webpack)/buildin/module.js 251 bytes {0} [built]
webpack: bundle is now VALID.
web服務器啟動完畢,此時訪問 http://localhost:3000/ 就可以看到我們的“Hello world”了。
需要特別說明的是, webpack-dev-server 是支持熱加載的,也就是說我們對代碼的改動,保存的時候會自動更新頁面。比如我們在文件中將“Hello world”改為“Linghucong”,會看到頁面實時更新了,無須再按F5刷新,爽吧?!
webpack-dev-server 的配置還可以放在 webpack.config.js 中,需要使用一個 devServer 屬性,詳細可以參考官方文檔。
處理CSS樣式
項目中使用CSS是必不可少的。webpack中使用
loader的方式來處理各種各樣的資源,根據設定的規則,會找到相應的文件路徑,然后使用各自的loader來處理。CSS文件也需要特定的loader,一般需要使用兩個: css-loader 和 style-loader ,如果使用LESS或者SASS還需要加載對應的loader。這里我們使用LESS,因此安裝loaders:
npm install css-loader style-loader less-loader --save-dev
踩坑提醒
npm3.0以上需要單獨安裝less: npm install less --save-dev 。
然后在文件 webpack.config.js 中配置:
{
test: /\.less$/,
loaders: ['style', 'css', 'less'],
include: path.resolve(__dirname, 'app')
}
可以看到,test里面包含一個正則,包含需要匹配的文件,loaders是一個數組,包含要處理這些文件的loaders,注意loaders的執行順序是從右到左的。
新建一個LESS文件 /app/index.less ,其內容如下:
h1 {
color: green;
}
在入口文件 index.js 中引入這個文件:
require('./index.less');
然后運行webpack進行編譯: npm run build :
$ npm run build
> react_boilerplate@1.0.0 build D:\node\react_boilerplate
> webpack
Hash: 0c25c4bacdc334db1e04
Version: webpack 1.13.0
Time: 1902ms
Asset Size Chunks Chunk Names
bundle.js 243 kB 0 [emitted] main
index.html 179 bytes [emitted]
[0] multi main 52 bytes {0} [built]
[75] ./app/index.js 110 bytes {0} [built]
[80] ./app/component.js 141 bytes {0} [built]
+ 78 hidden modules
Child html-webpack-plugin for "index.html":
+ 3 hidden modules
可以看到, http://localhost:3000/ 頁面上的文字已經變成綠色了。
到目前為止的代碼可以在 react_boilerplate _v1 中查看。
webpack 支持ES6
Javascript包管理格式
Javascript中的包管理比較常見的有幾種方式:
CommonJS
//CommonJS 定義的是模塊的同步加載,主要用于NodeJS
var MyModule = require('./MyModule');
// export at module root
module.exports = function() { ... };
// alternatively, export individual functions
exports.hello = function() {...};
AMD
//AMD 是異步加載,比如require.js使用這種規范
define(['./MyModule.js'], function (MyModule) {
// export at module root
return function() {};
});
// or
define(['./MyModule.js'], function (MyModule) {
// export as module function
return {
hello: function() {...}
};
});
ES6
//ES6 變得越來越主流了
import MyModule from './MyModule.js';
// export at module root
export default function () { ... };
// or export as module function,
// you can have multiple of these per module
export function hello() {...};
還有其他格式如UMD、CMD等,在此不再一一介紹。webpack對這些模塊格式都可以很好的支持。在我們之前的項目中使用的是CommonJS格式的模塊管理,但是隨著ES6的普及和應用,同時得益于強大的 Babel 的存在,使我們可以方便的使用ES6的語法,而不必考慮瀏覽器支持的問題。
webpack支持ES6語法
在webpack中支持ES6同樣只需要安裝配置相應的loader就可以了。
安裝如下:
npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save-dev
在 webpack.config.js 中添加loader如下:
{
test: /\.jsx?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
presets: ['react', 'es2015']
}
}
由于后邊需要支持React的jsx文件,所以我們在這里安裝了 babel-preset-react 。
順便提一下,我們可以在項目根目錄下創建一個 .babelrc 文件,將loader中的 presets 放在文件 .babelrc 中:
# .babelrc
{
"presets": ["react", "es2015"]
}
此時我們運行 npm run build ,正常編譯后,使用 npm run dev ,啟動web服務器,打開 http://localhost:3000/ 可以看到頁面已經可以正常顯示了。
踩坑提醒
如果上面對于loader的配置寫為(注意這里是 loaders 不是 loader ):
{
test: /\.jsx?$/,
loaders: ['babel'],
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
則可能會出現這樣的錯誤:
$ npm run build
> react_boilerplate@1.0.0 build D:\node\react_boilerplate
> webpack
D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:54
if(!element.loader || element.loader.indexOf("!") >= 0) throw new Error("Cannot define 'query' and multiple loaders in loaders list");
^
Error: Cannot define 'query' and multiple loaders in loaders list
at getLoadersFromObject (D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:54:65)
at LoadersList. (D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:78:12)
at Array.map (native)
at LoadersList.match
...
原因是使用了多個 loader ,而 query 僅僅作用于 babel-loader 。如果非要使用 loaders 加載多個 loader ,可以做如下修改:
var babelPresets = {presets: ['react', 'es2015']};
......
loaders: ['other-loader', 'babel-loader?'+JSON.stringify(babelPresets)]
......
到目前為止的代碼可以在 react_boilerplate _v2 中查看。
在項目中支持使用React
關于React的介紹和基本概念相信你已經有所了解,如果需要,可以參考本文最后的“參考閱讀”中的鏈接,在此不再詳述。
安裝React
npm install react react-dom --save
這里我們使用的版本是15.0.1。
$ npm install react react-dom --save
react_boilerplate@1.0.0 D:\node\react_boilerplate
+-- react@15.0.1
| `-- fbjs@0.8.1
| +-- isomorphic-fetch@2.2.1
| | +-- node-fetch@1.5.1
| | | +-- encoding@0.1.12
| | | | `-- iconv-lite@0.4.13
| | | `-- is-stream@1.1.0
| | `-- whatwg-fetch@0.11.0
| `-- ua-parser-js@0.7.10
`-- react-dom@15.0.1
改造項目結構
在項目中我們使用了html-webpack-plugin插件來用webpack自動生成入口的index.html文件,但是里面的內容我們沒法控制。html-webpack-plugin提供了一種模板的機制,可以讓我們對生成的文件內容進行定制。
創建模板文件
我們使用一個新的目錄templates用于存放模板文件,新建一個index.ejs文件:
templates/index.ejs
<%= htmlWebpackPlugin.options.title %>
Welcome to New Page
修改 html-webpack-plugin 設置
修改 webpack.config.js 文件如下:
plugins: [
new HtmlwebpackPlugin({
title: 'React Biolerplate by Linghucong',
template: path.resolve(__dirname, 'templates/index.ejs'),
inject: 'body'
})
]
關于 html-webpack-plugin 更多高級用法可以 參考其項目主頁 。
支持sourcemap
sourcemap的作用各位自行Google吧。要生成編譯出的js文件的sourcemap文件,只需要在webpack配置文件中加入如下一行配置即可:
devtool: 'source-map',
運行 npm run build 可以看到一個會在 dist 目錄生成一個新的文件 bundle.js.map ,這就是sourcemap文件。
Minification 代碼壓縮
要對生成的js文件進行壓縮,需要使用一個新的插件:UglifyJsPlugin。
修改 webpack.config.js 如下:
......
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
var config = {
......
plugins: [
......
new UglifyJsPlugin({ minimize: true })
]
}
module.exports = config;
運行 npm run build 可以看到生成的bundle.js文件已經被minify了。
在實際的項目開發中,我們在開發階段一般不需要將代碼minify,因為壓縮之后很不方便調試。因此,我們有必要將開發模式和發布模式區分開。我們通過設置 process.env.WEBPACK_ENV 來做區分。
修改 webpack.config.js 如下:
......
var env = process.env.WEBPACK_ENV;
var outputFile;
var plugins = [new HtmlwebpackPlugin({
title: 'React Biolerplate by Linghucong',
template: path.resolve(__dirname, 'templates/index.ejs'),
inject: 'body'
})];
if (env === 'build') {
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
plugins.push(new UglifyJsPlugin({ minimize: true }));
outputFile = 'bundle.min.js';
} else {
outputFile = 'bundle.js';
}
var config = {
......
output: {
path: path.resolve(__dirname, 'dist'),
filename: outputFile
},
......
plugins: plugins
}
module.exports = config;
同時需要修改npm run的快捷方式,在 package.json 文件中修改如下:
"scripts": {
"dev": "WEBPACK_ENV=dev webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
"build": "WEBPACK_ENV=build webpack"
},
踩坑提醒
在Windows系統上不能像上述那樣設置 WEBPACK_ENV ,可以使用 set 來設置,如下:
"scripts": {
"test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive ./test",
"test:watch": "npm test -- --watch",
"dev": "set WEBPACK_ENV=dev&&webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
"build": "set WEBPACK_ENV=build&&webpack"
},
更新項目代碼
對我們的組件稍作修改:
import './index.less';
import component from './component';
let content = document.getElementById("content");
content.appendChild(component());
然后編譯,運行:
$ npm run build
$ npm run dev
可以看到,目前訪問 http://localhost:3000/ 的頁面顯示已經發生了變化。
通過查看源代碼,可以看到我們頁面正是應用了我們的模板文件。
到目前為止的代碼可以在 react_boilerplate _v3 中查看。
創建React組件
我們將 app/index.js 修改一下,創建一個新的React組件。
app/index.js
import React from 'react';
import ReactDOM from 'react-dom';
class HelloReact extends React.Component {
render() {
return Hello React!
}
}
ReactDOM.render(, document.getElementById('content'));
代碼十分簡單,引入了 react 和 react-dom ,創建了一個叫做HelloReact的組件,并將其渲染到頁面上id為 content 的DOM元素內。
編譯React代碼
我們在之前已經在webpack的配置中配置好了對React的支持,因此目前不需要做什么修改了。
npm run build 之后就可以在頁面上看到“Hello React!”了。
至此,我們基于ES6并使用webpack和Babel的React初始項目已經可以完美運行了。
到目前為止的代碼可以在 react_boilerplate _v4 中查看。
測試環境搭建(Mocha + Chai + Sinon)
所用技術介紹
如上所見,我在這里使用Mocha + Chai + Sinon 這幾個技術來搭建我們的測試環境,簡單介紹如下:
- Mocha:用于運行我們的測試用例。
- Chai:Mocha用的斷言庫。
-
Sinon:用于創建一些mocks/stubs/spys。
另外值得一提的是,AirBnB創建了一個專門針對React代碼測試的開源程序:Enzyme,有興趣的可以研究一下。
Mocha安裝及環境配置
安裝Mocha、Chai以及Sinon
安裝很簡單,命令如下:
npm i mocha chai sinon --save-dev
因為我們要支持ES6的語法,因此還需要安裝一個額外的插件 babel-register :
npm i babel-register --save-dev
寫一個簡單的測試用例
Mocha默認會去當前目錄下找test目錄,然后在其中去找后綴為.js的文件。如果需要修改這個目錄,可以使用Mocha的參數進行設置。我們這里創建一個新的目錄,叫做test,然后一個新的Spec文件:
index.spec.js
import { expect } from 'chai';
describe('hello react spec', () => {
it('works!', () => {
expect(true).to.be.true;
});
});
這個時候我們在命令行中使用命令 mocha --compilers js:babel-register 運行mocha,如果順利的話,可以看到如下結果:
$ mocha --compilers js:babel-register
hello react spec
√ works!
1 passing (11ms)
簡單解釋一下這里的 babel-register 。如果這里沒有添加 --compilers 選項,則mocha會按照默認的方式執行,也就是“讀取spec文件”->“運行測試用例”。使用了 babel-register 之后,則執行順序為“讀取spec文件”->“將ES6代碼編譯為ES5代碼”->“運行測試用例”。
踩坑提醒
如果執行 mocha --compilers js:babel-register 命令的時候,出現如下的錯誤:
$ mocha --compilers js:babel-register
D:\node\react_boilerplate\test\index.spec.js:1
(function (exports, require, module, __filename, __dirname) { import { expect } from 'chai';
^^^^^^
SyntaxError: Unexpected reserved word
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at loader (D:\node\react_boilerplate\node_modules\babel-register\lib\node.js:126:5)
at Object.require.extensions.(anonymous function) [as .js] (D:\node\react_boilerplate\node_modules\babel-register\lib\node.js:136:7)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:219:27
at Array.forEach (native)
at Mocha.loadFiles (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:216:14)
at Mocha.run (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:468:10)
at Object. (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\bin\_mocha:403:18)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:968:3
這個錯誤可能是由于Babel的版本引入的。 在這里 提供了一個解決方案:
在我們項目中創建一個.babelrc文件,其內容如下:
{
"presets": ["react", "es2015"]
}
其作用之前講過了。現在就可以將我們 webpack.config.js 中對應設置刪除了:
#webpack.config.js
...
{
test: /\.jsx?$/,
loader: 'babel',
exclude: /node_modules/
},
創建測試工具庫test_helper.js
注意到我們在每個測試spec文件中,都會需要引入chai庫的expect,這樣就會有很多重復代碼。當然還有其他一些通用的幫助性代碼,因此我們需要一個庫來集中進行管理。這里我們創建一個新的文件 /test/test_helper.js :
/test/test_helper.js
import { expect } from 'chai';
import sinon from 'sinon';
global.expect = expect;
global.sinon = sinon;
在這里我只是添加了chai的expect,以及引入了sinon。
現在就可以將 index.spec.js 文件的第一行刪除,然后通過如下的命令來執行mocha命令了:
mocha --compilers js:babel-register --require ./test/test_helper.js --recursive
執行結果如下:
λ mocha --compilers js:babel-register --require ./test/test_helper.js --recursive
hello react spec
√ works!
1 passing (12ms)
配置 package.json 中的快捷方式
在 package.json 中我們可以創建上述mocha命令的快捷方式。在 scripts 字段中作如下修改:
#package.json
"scripts": {
"test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive ./test",
"test:watch": "npm test -- --watch",
"dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
"build": "webpack"
},
然后就可以使用
npm run test
來直接運行mocha了。
注意這里我還新增加了一個 npm run test:watch 快捷方式,其實就是使用了mocha的 --watch 選項。有了它,當我們在對代碼進行修改的時候,就會自動運行test了。
到目前為止的代碼可以在 react_boilerplate _v5 中查看。
使用Karma測試
karma安裝與配置
Karma是一個基于Node.js的前端測試啟動器(Test Runner),它出自Google的Angularjs團隊。該工具可用于測試所有主流Web瀏覽器,可以支持Chrome、Safari、Firefox、IE、Opera甚至PhantomJS。
安裝Karma:
npm install karma --save-dev
然后還需要安裝我們需要用到的一些依賴庫:
npm install lolex phantomjs-prebuilt phantomjs --save-dev
npm install karma-chai karma-chai-plugins karma-chai-sinon karma-mocha karma-mocha-reporter karma-phantomjs-launcher karma-sinon karma-sinon-chai karma-sourcemap-loader karma-webpack --save-dev
踩坑提醒
不要問我為什么裝那么多擴展,因為我踩過很多坑,這里就直接跳過了:<
然后我們就可以使用karma命令來生成一個配置文件。
λ .\node_modules\.bin\karma.cmd init karma.conf.js
Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> mocha
Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> PhantomJS
> Chrome
>
What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> app/*.js
> test/*.spec.js
>
Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes
Config file generated at "D:\node\react_boilerplate\karma.conf.js".
然后我們就可以使用 karma start 命令來運行我們的測試用例了。不過現在直接運行可能還有一些問題,暫時先不管。
優化Karma配置文件
我們使用一個單獨的文件 test.webpack.js 來保存測試文件的路徑,方便在karma設置中進行預處理。新建文件 test.webpack.js 如下:
function requireAll(requireContext) {
return requireContext.keys().map(requireContext);
}
var modules = requireAll(require.context("./test", true, /.+\.spec\.jsx?$/));
module.exports = modules
然后修改 karma.config.js :
var webpackConfig = require('./webpack.config');
webpackConfig.devtool = 'inline-source-map';
module.exports = function (config) {
config.set({
browsers: [ 'PhantomJS' ],
singleRun: true,
frameworks: [ 'mocha', 'chai', 'sinon', 'sinon-chai' ],
files: [
'test.webpack.js'
],
plugins: [
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-chai',
'karma-mocha',
'karma-sourcemap-loader',
'karma-webpack',
'karma-mocha-reporter',
'karma-sinon',
'karma-sinon-chai'
],
preprocessors: {
'test.webpack.js': [ 'webpack', 'sourcemap' ]
},
reporters: [ 'mocha' ],
webpack: webpackConfig,
webpackServer: {
noInfo: true
},
autoWatch: true
});
};
運行Karma
好了,到現在為止,我們可以正常運行我們的測試用例了。使用命令 karma start 運行結果如下:
$ karma start
START:
29 04 2016 13:26:50.350:INFO [karma]: Karma v0.13.22 server started at http://localhost:9876/
29 04 2016 13:26:50.375:INFO [launcher]: Starting browser PhantomJS
29 04 2016 13:26:52.072:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#05AECTTMgBTkXK4kAAAA with id 76498752
hello react spec
√ works!!!
Finished in 0.008 secs / 0.001 secs
SUMMARY:
√ 1 test completed
可以看到,測試用例測試通過了。
目前我們在karma的配置文件中設置的瀏覽器類型是“browsers: [ ‘PhantomJS’ ]”,也就是會使用PhantomJS來運行。如果需要使用其他瀏覽器,可以做相應修改,甚至添加多個。比如我們要支持打開Chrome瀏覽器運行測試,修改如下:
browsers: [ 'Chrome' ]
正常運作的前提是,必須事先安裝好了對應的插件,對應Chrome的就是’karma-chrome-launcher’,其他瀏覽器類型類似處理。
添加karma快捷方式到npm
我們之前使用 npm run test 來運行測試, npm run test:watch 來監聽文件改變并運行測試。使用karma之后,需要在 package.json 中作如下修改:
"scripts": {
"test": "karma start",
"test:watch": "watch \"npm run test\" app/",
......
}
另外需要安裝一個npm包:
npm install watch --save-dev
這樣我們就可以使用 npm run test 來運行測試, npm run test:watch 來監聽文件改變并自動運行測試了:
到目前為止我們自己的react boilerplate已經創建完畢了!代碼可以在 react_boilerplate _v6 中查看。
后記
本文帶你一步步建立了自己的react boilerplate項目,但是需要知道的是,文中所述甚淺,只是帶你入門罷了。其中每一個話題,都可以展開來再寫一系列的文章。比如測試所用的mocha+chai+sinon套裝,比如React測試利器Enzyme等。即便是文中已經成型的代碼,亦多有可優化的地方。如果你有好的意見或者建議,也歡迎到這個Github repo上來提pull request或者issue:
https://github.com/jiji262/react_boilerplate
最后,感謝閱讀。
來自: http://jiji262.github.io/2016/04/29/create-your-own-react-boilerplate/