網(wǎng)上對(duì)于 React 的相關(guān)教程層出不窮,官方文檔也對(duì)其中的技術(shù)要點(diǎn)做出了充足的解釋,只是不那么簡(jiǎn)潔易懂。但有了這篇譯文,我們可以從最簡(jiǎn)單的組件開始,通過對(duì) Babel、Webpack 的了解與實(shí)踐,來搭建最簡(jiǎn)單的 React 開發(fā)環(huán)境。
- 原文地址:Setting up React for ES6 with Webpack and Babel
- 原文作者:Sam Agnew
- 譯者:韓亦樂
- 校審:韓亦樂
- 轉(zhuǎn)載請(qǐng)注明以上信息
ReactJS 從誕生以來,一直引領(lǐng)著前端技術(shù)的飛速發(fā)展。正如其官網(wǎng)所說,React 作為專注于 MVC 架構(gòu)中 View 層的前端庫(kù),允許我們構(gòu)建可重用的 UI 組件,并通過抽象 DOM 來維護(hù)數(shù)據(jù)狀態(tài)的變化。結(jié)合前端資源加載/打包工具 Webpack,React 大大簡(jiǎn)化了構(gòu)建和維護(hù)單頁(yè)應(yīng)用程序的過程。
Facebook 做了大量的工作使 React 保持活力,包括及時(shí)使它與 ECMAScript 6(ES6)標(biāo)準(zhǔn)(JavaScript 語(yǔ)言的一次重大更新)的新功能兼容。不幸的是,瀏覽器對(duì) ES6 的支持并不像許多人所希望的那樣廣泛,因此也就出現(xiàn)了 Babel 這樣實(shí)用的工具。Babel 允許我們編寫符合 ES6 標(biāo)準(zhǔn)的 JavaScript 文件并將其編譯為可以運(yùn)行在舊 JavaScript 環(huán)境的標(biāo)準(zhǔn) ES5 代碼。
在這篇文章中,我們將嘗試編寫兩個(gè)符合ES6 標(biāo)準(zhǔn)的基本 React 組件。其中需要使用
Babel 將代碼編譯為 ES5 代碼并使用 Webpack 將源代碼打包。 這個(gè)過程會(huì)很有趣的,因?yàn)閷?React、ES6、Babel 和 Webpack 搭配起來的開發(fā)體驗(yàn)真的很棒。

使用構(gòu)建工具搭建運(yùn)行環(huán)境
在我們正式開始編寫代碼之前,首先確保我們的電腦上是否已經(jīng)安裝了 NodeJS 和 npm,因?yàn)槲覀儗⑹褂眠@些來安裝需要的軟件包。
安裝完成后打開終端,使用簡(jiǎn)單的終端命令跳轉(zhuǎn)到我們的新項(xiàng)目目錄下并輸入如下命令:
npm init
在接下來終端的提示中填寫我們覺得合適的內(nèi)容(譯者注:默認(rèn)一直回車即可),將會(huì)生成一個(gè) package.json 文件。這個(gè)文件將允許我們記錄項(xiàng)目需要的所有 node 模塊以供參考。
現(xiàn)在我們來安裝 React 和 React DOM:
npm install --save react
npm install --save react-dom
我們還需要安裝 webpack 和 webpack-dev-server 來打包并運(yùn)行打包后的 JavaScript 應(yīng)用程序。這時(shí)可能需要使用“sudo”權(quán)限來將 webpack-dev-server 安裝到全局環(huán)境。
npm install --save-dev webpack
npm install webpack-dev-server -g
現(xiàn)在我們需要的模塊已經(jīng)安裝好了,我們需要一個(gè)用來解析 ES6 代碼的編譯器,也就到了 Babel 上場(chǎng)的時(shí)刻。我們來安裝將用于 Webpack 的 babel-loader 和 babel-core 模塊,以及 babel-preset-es2015 和用于加載 React 代碼的babel-preset-react 模塊。
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-react
創(chuàng)造第一個(gè) React 組件
React 使用組件來封裝界面模塊。我們可以編寫組件來處理數(shù)據(jù)的外觀并自動(dòng)呈現(xiàn)狀態(tài)數(shù)據(jù)更改后的樣子。創(chuàng)建組件時(shí),我們需要通過重載 React.Component 的 render 函數(shù)來定義每一個(gè)組件。
現(xiàn)在編寫我們的第一個(gè)組件來實(shí)踐這個(gè)概念,這個(gè)組件的最終目的是能在瀏覽器中顯示“Hello”這個(gè)單詞。
通過編輯器在項(xiàng)目中新建一個(gè)“hello.jsx”文件并寫下如下代碼:
import React from 'react';
class Hello extends React.Component {
render () {
return <h1>Hello</h1>
}
}
關(guān)于以上代碼的語(yǔ)法我們有幾件事需要注意。首先,我們有 ES6 的 import 語(yǔ)句和類定義語(yǔ)句,這使得我們的代碼更簡(jiǎn)潔,無(wú)需調(diào)用 React.createClass。第二,在組件定義的 render 函數(shù)中有一個(gè)時(shí)髦的內(nèi)聯(lián) HTML 的東西,這個(gè)類似 XML 的語(yǔ)法稱為 JSX。JSX 被設(shè)計(jì)來使 React 組件的構(gòu)建更容易,其簡(jiǎn)介、熟悉的語(yǔ)法用于定義具有屬性的 DOM 樹結(jié)構(gòu)。
這些新的語(yǔ)法或許看起來有點(diǎn)奇怪,但是不必?fù)?dān)心,因?yàn)槲覀冎恍枰晕⑹褂?babel,便能將 ES6 語(yǔ)法和 JSX 語(yǔ)法都轉(zhuǎn)換成可以在瀏覽器中運(yùn)行的 ES5 JavaScript。
如果在 React 中不使用 ES6 和 JSX 語(yǔ)法,我們的“Hello” 組件將會(huì)是這樣的:
var React = require('react');
var Hello = React.createClass({displayName: 'Hello',
render: function() {
return React.createElement("h1", null, "Hello ");
}
});
當(dāng)我們使用 JSX 時(shí),我們可以更簡(jiǎn)潔地定義我們的虛擬DOM元素,而無(wú)需調(diào)用 React.createElement 并傳遞元素應(yīng)具有的屬性。使用 JSX 并不一定能使我們這個(gè)簡(jiǎn)單的“Hello”組件剩去多少代碼行數(shù),但在我們構(gòu)建組件并將它們組合在一起時(shí),JSX會(huì)使事情變得更加容易。
現(xiàn)在我們有了一個(gè)組件類,我們需要增加一些代碼使組件能“mount”到一個(gè) DOM 元素。這將會(huì)使我們的 React 組件呈現(xiàn)到 HTML 頁(yè)面的元素中。為此我們導(dǎo)入 react-dom 模塊并調(diào)用其 render 函數(shù),傳入組件對(duì)象以及該組件要綁定的實(shí)際DOM元素。
再次打開“hello.jsx”并添加以下行(第二行和后三行):
import React from 'react';
import ReactDOM from 'react-dom';
class Hello extends React.Component {
render() {
return <h1>Hello</h1>
}
}
ReactDOM.render(
<Hello/>,
document.getElementById('hello')
);
現(xiàn)在我們來創(chuàng)建我們的第二個(gè)組件,用來渲染“World”這個(gè)單詞。在當(dāng)前項(xiàng)目根目錄下創(chuàng)建一個(gè)新的“world.jsx”文件并加入填寫代碼。請(qǐng)注意,它與我們?yōu)榈谝粋€(gè)組件編寫的代碼非常相似:
import React from 'react';
import ReactDOM from 'react-dom';
class World extends React.Component {
render() {
return <h1>World</h1>
}
}
ReactDOM.render(
<World/>,
document.getElementById('world')
);
現(xiàn)在我們有了倆個(gè) React 組件,但是還沒有地方可以使用它們。我們現(xiàn)在來通過編寫一個(gè)簡(jiǎn)單的 HTML 頁(yè)面來解決這個(gè)問題,這個(gè) HTML 頁(yè)面將為我們要渲染到頁(yè)面上的每個(gè)組件分配一個(gè) <div>。創(chuàng)建一個(gè)“index.html”文件并編寫相應(yīng)的骨架:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello React</title>
</head>
<body>
<div id="hello"></div>
<div id="world"></div>
</body>
</html>
我們現(xiàn)在創(chuàng)建了能在瀏覽器中顯示“Hello World”的所有 React 組件代碼。能讓代碼最終運(yùn)行的最終一步需要通過 Webpack 來完成。

使用 Webpack 打包源代碼
Webpack 作為模塊加載/打包器可以處理很多資源,諸如使 CSS 文件、圖像或是 JavaScript 文件等大量依賴關(guān)系的資源轉(zhuǎn)換為可以提供給客戶端網(wǎng)頁(yè)的內(nèi)容。Webpack 通過我們?cè)陧?xiàng)目配置文件中指定的裝載程序來處理對(duì)應(yīng)的資源。在我們的例子中,我們希望將 JSX 轉(zhuǎn)換為 JavaScript 并將 ES6 代碼轉(zhuǎn)換為符合瀏覽器的 ES5 代碼。我們可以通過提供一個(gè) JavaScript 文件作為 Webpack 進(jìn)行操作的入口點(diǎn)。Webpack 將分析此文件以及代碼中使用的所有后續(xù)依賴關(guān)系,以生成一個(gè)包以供最終的 HTML 頁(yè)面包含。要告訴 Webpack 有關(guān)項(xiàng)目中用到的 React 組件,我們需要做的就是導(dǎo)入這些 JavaScript 文件到入口文件中。
在文本編輯器中創(chuàng)建一個(gè)“main.js”文件,并添加以下代碼來導(dǎo)入我們制作的兩個(gè) React 組件:
import Hello from './hello.jsx';
import World from './world.jsx';
接下來我們需要告訴 Webpack 這個(gè)文件是我們的入口文件,以便我們?cè)诖虬鼤r(shí)能讓 Webpack 定位到。我們這里只用到了 Babel 的加載器,但如果我們有其他的依賴關(guān)系,我們還能使用其他加載器來實(shí)現(xiàn)如 CoffeeScript 和 SASS 文件的處理。
再次啟動(dòng)我們的文本編輯器,創(chuàng)建一個(gè)名為“webpack.config.js”的新文件,并添加以下配置:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './main.js',
output: { path: __dirname, filename: 'bundle.js' },
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
},
};
最后,我們需要對(duì)我們的 index.html 進(jìn)行一個(gè)小的修改,以包含在運(yùn)行 Webpack dev服務(wù)器時(shí)將生成的“bundle.js”文件:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello React</title>
</head>
<body>
<div id="hello"></div>
<div id="world"></div>
<script src="bundle.js"></script>
</body>
</html>
讓我們啟動(dòng) Webpack dev 服務(wù)器,看看我們的頁(yè)面上的組件是否真的能呈現(xiàn)出來:
webpack-dev-server --progress --colors

當(dāng)在終端輸入命令后成功跑起來時(shí),Webpack 成功打包了我們的組件代碼?,F(xiàn)在 Webpack dev 服務(wù)器正在運(yùn)行,我們可以瀏覽瀏覽器中的 http:// localhost:8080/webpack-dev-server(譯者注:譯者的電腦上是 http:// localhost:8081,具體情況請(qǐng)看終端),以便在頁(yè)面上看到我們的“Hello World”React 應(yīng)用程序。

接下來該干什么?
我們剛剛僅僅通過使用能解析 JSX 和 ES6 的 Babel 構(gòu)建了兩個(gè) React 組件,并使用 Webpack 將它們打包在一起從而得以在瀏覽器跑起來。這可能看起來并不是很難,但是在構(gòu)建更大的單頁(yè)應(yīng)用程序的道路上是一個(gè)堅(jiān)實(shí)的開始。我們現(xiàn)在已經(jīng)克服了一大堆的障礙使這些新技術(shù)能有機(jī)的組合在一起,我們終于可以用 React 開始制作出令人敬畏的東西了。
如果您想深入探索并構(gòu)建實(shí)際的 React 應(yīng)用程序,您可以在博客文章中查看我最近寫的關(guān)于“使用 React 創(chuàng)建一個(gè)基于 Twilio REST API 來監(jiān)控電話的儀表盤”(譯者注:或許之后會(huì)再翻譯一下這篇文章)。
您可以隨時(shí)聯(lián)系我來分享您的經(jīng)驗(yàn)或提出任何問題。
- 電郵: sagnew@twilio.com
- Twitter: @Sagnewshreds
- Github:Sagnew
- Twitch(流式直播代碼):Sagnewshreds
- Hello,我是韓亦樂,現(xiàn)任本科軟工男一枚。軟件工程專業(yè)的一路學(xué)習(xí)中,我有很多感悟,也享受持續(xù)分享的過程。如果想了解更多或能及時(shí)收到我的最新文章,歡迎訂閱我的個(gè)人微信號(hào):韓亦樂。我的簡(jiǎn)書個(gè)人主頁(yè)中,有我的訂閱號(hào)二維碼和 Github 主頁(yè)地址;我的知乎主頁(yè) 中也會(huì)堅(jiān)持產(chǎn)出,歡迎關(guān)注。
- 本文內(nèi)部編號(hào)經(jīng)由我的 Github 相關(guān)倉(cāng)庫(kù)統(tǒng)一管理;本文可能發(fā)布在多個(gè)平臺(tái)但僅在上述倉(cāng)庫(kù)中長(zhǎng)期維護(hù);本文同時(shí)采用【知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議】進(jìn)行許可。
