這是Webpack+React系列配置過程記錄的第一篇。其他內(nèi)容請參考:
- 第一篇:使用webpack、babel、react、antdesign配置單頁面應(yīng)用開發(fā)環(huán)境
- 第二篇:使用react-router實現(xiàn)單頁面應(yīng)用路由
- 第三篇:優(yōu)化單頁面開發(fā)環(huán)境:webpack與react的運行時打包與熱更新
- 第四篇:React配合Webpack實現(xiàn)代碼分割與異步加載
- 第五篇:分離Webpack開發(fā)環(huán)境與生產(chǎn)環(huán)境的配置
- 第六篇:在React中使用Redux
本文內(nèi)容將記錄使用webpack、babel、react、antdesign配置單頁面應(yīng)用開發(fā)環(huán)境的過程。這是我首次使用前端框架開發(fā)Web應(yīng)用,在此之前,我寫Web代碼使用最原生的HTML、CSS、JS,即使是敲這些文字的這一刻,我還沒能熟練使用jQuery庫。最近想跨出這個怪圈,希望使用一些“前沿”一些的框架重構(gòu)之前寫的書籍分享網(wǎng)站的管理后臺后臺,因此才選擇使用webpack、babel、react、ant design作為突破口。
主要依賴庫的版本如下(PS. 不同版本配置不一定一樣):
- webpack: 2.4.1
- react: 15.4.2
- react-dom: 15.4.2
- babel-core: 6.24.1
- babel-loader: 7.0.0
- antd: 2.5.2
準(zhǔn)備靜態(tài)Web服務(wù)器
靜態(tài)Web服務(wù)器可以使用Nginx、Apache等現(xiàn)成的服務(wù)器軟件,僅用于接下來對配置結(jié)果的測試和校驗。
為了節(jié)省安裝這些服務(wù)器軟件的精力,我直接使用node.js配合express寫了個簡單的靜態(tài)服務(wù)器。也把這一步驟記錄下來。
- 創(chuàng)建項目目錄demo,并使用npm init命令初始化node.js空項目,生成package.json文件。
- 使用npm安裝express。
- 創(chuàng)建Web的啟動腳本index.js。
- 創(chuàng)建存放靜態(tài)資源的目錄public
- 在public中創(chuàng)建頁面文件index.html
index.js文件的內(nèi)容如下:
var express = require('express');
var app = express();
app.use('/', express.static('public'));
var server = app.listen(2000, function() {
var port = server.address().port;
console.log('Open http://localhost:%s', port);
});
index.html文件的內(nèi)容如下:
<html>
<head></head>
<body>
<p>Hello world</p>
</body>
</html>
使用node啟動index.js,就可以在瀏覽器中輸入 http://localhost:2000訪問到index.html中的內(nèi)容了。
接下來才是真正開始本文的真正內(nèi)容。我的目的很明確——開發(fā)一個網(wǎng)頁,因此我將從React開始。
使用React開發(fā)頁面
使用React框架編寫頁面的方法有兩種,第一種是直接在html文件中直接引用react.js和react-dom.js,然后在后續(xù)的腳本中使用React帶來的能力。
僅改動前文提到的index.html文件即可做到:
<html>
<head>
<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
</head>
<body>
<p>Hello world</p>
<div id='main'/>
<script>
var e = React.createElement('p', null, 'This is React');
ReactDOM.render(e, document.getElementById('main'));
</script>
</body>
</html>
在瀏覽器中訪問index.html,你將看到頁面使用React渲染了一行文字。
但是通過這種方式使用React并不能很好發(fā)揮其作用。我們要使用ES6、JSX、UI重用等特性,因此我們將使用下面的第二種方法。
使用Webpack、Babel和React開發(fā)頁面
這種方法實際上你所寫的代碼并不是最終在用戶瀏覽器上執(zhí)行的代碼。源代碼將經(jīng)過Babel和Webpack進(jìn)行轉(zhuǎn)換處理,然后生成可在用戶瀏覽器上執(zhí)行的代碼。這個過程有點像C或者C++的編譯。
安裝React
使用下面命令安裝React(參考:https://facebook.github.io/react/docs/installation.html)
npm install react@15.4.2 react-dom@15.4.2 --save
由于在寫這篇文章之前做過了一次測試,預(yù)料到如果使用最新版本的react,后面引入的ant design將會報兼容性錯誤,故指定了react的版本。
因為瀏覽器并沒有提供給我們引入其他模塊的能力,我們也就無法直接使用React模塊,這時需要Webpack的幫助。
安裝與配置Webpack
使用下面命令安裝Webpack
npm install webpack --save-dev
配置Webpack的方法有好幾種,我使用的是配置文件的方式。在項目根目錄下生成webpack.config.js文件。內(nèi)容如下:
var path = require('path');
module.exports = {
entry: './public/index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'public')
}
};
這個文件配置了webpack的入口為public目錄下的index.js,轉(zhuǎn)換后生成的文件為public/out.js。
接下來在package.json配置一個build命令,內(nèi)容為:
...
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "node index.js",
},
...
這樣就可以使用npm run build調(diào)用webpack對js文件進(jìn)行轉(zhuǎn)換。
再看一下此刻的public目錄的index.js文件內(nèi)容:
import React from 'react';
import ReactDOM from 'react-dom';
var e = React.createElement('p', null, 'This is React');
ReactDOM.render(e, document.getElementById('main'));
而index.html文件的內(nèi)容:
<html>
<head>
</head>
<body>
<p>Hello world</p>
<div id='main'></div>
<script src="out.js"></script>
</body>
</html>
注意到html中script標(biāo)簽引用的js文件是out.js,這個文件是webpack生成的,是最終在用戶瀏覽器上執(zhí)行的腳本。
現(xiàn)在我們執(zhí)行npm run build命令,項目文件布局內(nèi)容如下圖所示:

確實生成了我們想要的out.js文件了。
Webpack有一個優(yōu)點就是針對JS文件,它能夠做到按需加載。后面你將會發(fā)現(xiàn)對于其他類型的文件,如:css、html、jade等,只要使用了適當(dāng)?shù)牟寮材茏龅桨葱杓虞d。
到這里,你會發(fā)現(xiàn)不需要使用Babel,我們就可以使用React開發(fā)頁面內(nèi)容了。但是你會注意到,除了import語句是webpack做了兼容性處理的,我所使用的其他語法都是ES5的語法。
如果在index.js中使用JSX語法,webpack構(gòu)建的時候就會報錯。同樣地,如果在index.js中添加ES6的語法,盡管webpack構(gòu)建時不會報錯,但生成的out.js文件末尾部分依舊可以找到這部分ES6語法的代碼,這樣的代碼被用戶加載到瀏覽器中執(zhí)行,是否能被瀏覽器支持是無法得到保證的。
為此,我們需要引入Babel,讓其把所有瀏覽器可能不支持的語法轉(zhuǎn)換成ES5的語法。
安裝與配置Babel
使用Babel的方法也有好多種,官網(wǎng)的幫助文檔可以根據(jù)環(huán)境提供對應(yīng)的幫助。本文是基于Webpack使用Babel,因此無論是增加的依賴庫還是配置流程均只對Webpack的場景有效。我們將使用Webpack關(guān)于Babel的一個擴(kuò)展加載器babel-loader關(guān)聯(lián)這兩者。而且關(guān)于Babel的配置也集合到webpack.config.js中,通過webpack傳遞給babel,這樣可以省去獨立配置babel步驟。
安裝基于Webpack的Babel使用下面命令:
npm install --save-dev babel-loader
npm install --save-dev babel-core
上文提到,Babel用于把新版本的JS代碼翻譯成大多數(shù)瀏覽器都支持的ES5版本的代碼。要做到這些翻譯,只需要使用對應(yīng)的擴(kuò)展即可。例如:
- babel-preset-env根據(jù)配置環(huán)境計算babel對代碼填充何種等級的polyfill,已包括es2015的配置,但沒有包括stage-x。官方首推。
- babel-preset-[stage-0、stage-1、stage-2、stage-3]與ES7相關(guān)的配置;
- 除此之外,Babel還可以有其他擴(kuò)展,比如我們希望使用JSX語法,這時需要引入babel-preset-react處理器。
根據(jù)官方的推薦,我們暫時先使用這幾個:
npm install --save-dev babel-preset-react
npm install --save-dev babel-preset-stage-0
npm install --save-dev babel-preset-env
在webpack.config.js中配置babel,內(nèi)容更新為:
var path = require('path');
module.exports = {
entry: './public/index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'public')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'stage-0', 'react'],
plugins: []
}
}
}
],
},
};
注意到我們在module.rules中添加了一個規(guī)則。這個規(guī)則只要匹配到node_modules以外的js后綴的文件就會使用babel-loader進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換過程依次使用了plugins和presets制定的擴(kuò)展。注意presets的處理順序比較特別,是從右到左順序執(zhí)行的。
到這里就配置完babel了。我們修改index.js文件:
import React from 'react';
import ReactDOM from 'react-dom';
class Text extends React.Component {
render() {
return (
<p>This is a react Component</p>
);
}
}
ReactDOM.render(<Text/>, document.getElementById('main'));
使用命令編譯并啟動服務(wù)器,沒有再因為JSX語法報錯。
npm run build
npm start
在瀏覽器訪問index.html可以看到“This is a react Component”,這說明Babel很好地工作了。
到這里如果沒有其他需求就可以開始開發(fā)了。
使用Ant Design作為React的UI庫
由于我已經(jīng)怕自己造輪子了,這里我要引入基于React的一個Ant Design規(guī)范UI庫antd。
安裝Ant Design
npm install --save antd
好了可以直接使用Ant Design的UI了。修改index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { DatePicker } from 'antd';
class Text extends React.Component {
render() {
return (
<div>
<p>This is a react Component</p>
<DatePicker/>
</div>
);
}
}
ReactDOM.render(<Text/>, document.getElementById('main'));
重新構(gòu)建后執(zhí)行,在瀏覽器訪問index.html可以看到多了個日期選擇器,但是沒有相應(yīng)的樣式。
加載樣式表
想要在js中引入css樣式表,需要添加webpack的加載器,這樣在js中引入的css樣式將會被webpack構(gòu)建成以動態(tài)方式插入到html文件中。
針對css樣式,需要下面兩個加載器:
npm install --save-dev css-loader
npm install --save-dev style-loader
然后在webpack.config.js中配置一個新的規(guī)則:
var path = require('path');
module.exports = {
entry: './public/index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'public')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'stage-0', 'react'],
plugins: []
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
],
},
};
注意不要犯我的一個錯誤:因為antd的樣式是放在node_modules中的,不要在css的loader中添加exclude命令刨除掉node_modules目錄。
這時候可以在index.js中添加下面一行代碼:
...
import { DatePicker } from 'antd';
import 'antd/dist/antd.css'; // Add
...
重新構(gòu)建運行就可以看到日期選擇器有樣式了。
配置按需加載
上述方法實際上加載整個antd包到最終生成的out.js文件中了。不信的話,在瀏覽器訪問index.html可以在console中看到下面的提示:

配置按需加載需要使用另外一個Babel的插件babel-plugin-import,安裝命令如下:
npm install --save-dev babel-plugin-import
因為這是Babel的插件,所以它的配置要在babel-loader的plugins節(jié)點中配置。修改后的webpack.config.js內(nèi)容如下:
var path = require('path');
module.exports = {
entry: './public/index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'public')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'stage-0', 'react'],
plugins: [['import', {"libraryName": "antd", "style": "css"}]]
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
],
},
};
這樣就完成了按需加載的配置了。
使用antd的組件的時候也無需再增加import樣式文件的語句了。去除掉剛剛在index.js中增加的那一行語句吧。重新構(gòu)建運行,你會看到警告沒有了。out.js中的行數(shù)從原來的13萬多行減少到了5萬多。
到此配置完畢。
注:所有內(nèi)容均參考自React、Babel、Webpack、AntDesign、第三方插件等的官方網(wǎng)站或?qū)?yīng)Github。
本文來自作者同步博客