本文也同步發表在個人公衆號「個人天空」html
從零開始,用最少的配置、最少的代碼、最少的依賴來搭建一個最簡單的webpack+react環境。前端
最近在玩webpack+react+移動端,那麼第一步天然是搭建相關的環境,原本網上的教程很不錯,只是前端相關的東西發展太過迅猛,只相隔了半年有些東西的版本就不對了,有些配置、命令等照着以前的教程作就可能會掉到坑裏去,別問我怎麼知道的,我剛剛從坑裏爬出來,所以趕忙寫篇文章來記錄一下,也算是讓本身再鞏固一下。node
本篇徹底是從零開始,用最少的配置、最少的代碼、最少的依賴來搭建一個最簡單的webpack+react環境。會把一個小白的經歷原本來本的寫出來,遇到的坑都用紅色的坑字標註出來,因爲我也是第一次學習相關的知識點若是有不正確的地方也多多歡迎你們來指出。react
本篇文章寫做的日期是2018-7-21,所以全部依賴的版本到當前日期爲止,之後若是有升級變化的話,那也是沒法當前預料獲得的。個人操做系統是win7,所以不涉及到linux的相關知識點。編輯器是Sublime Text3.0,順便安利一下Sublime Text,好用速度又快,真心不錯!
linux
我是參考這篇教程:https://segmentfault.com/a/1190000006178770webpack
如今讓咱們開始吧,第一步咱們先配置一個webpack的web服務器。es6
webpack依賴於node.js,那麼第一步是安裝node.js,這個沒什麼好說的,windows環境的安裝就更友好了,官網下載安裝包,一路默認安裝便可,如今的node.js安裝完畢後,npm也就自帶安裝好了,後面咱們就要一路與npm打交道了。web
首先咱們要用npm初始化項目,電腦上新建一個目錄保存咱們的練習文件,隨後進入cmd命令行,轉到該目錄下。若是命令行不會操做的話,請先掌握cd這個命令。接下來在該目錄下輸入npm init命令:npm
npm init
根據提示一路回車就能夠了,不過這個地方可能會有一個坑存在,如圖:json
這裏報錯:Sorry,name can only contain URL-friendly characters。
該錯誤產生的緣由是npm初始化時,會向咱們詢問項目名,若是咱們不指定的話(一般都是如此),那麼就會用當前文件夾來命名,而咱們的文件夾的名稱爲「練習-react環境」,其包含了一箇中劃線(-),所以致使命名錯誤了。那麼咱們只要輸入一個項目名稱(譬如test)就能夠了, 或者乾脆把文件夾重命名爲符合規範的名稱就能夠了。
本例中咱們手動輸入了test,將項目名稱指定爲test:
接下來就一路回車,最後詢問「Is this OK?<y>」時輸入y後回車,完成npm初始化。
npm初始化後,在文件夾下將會出現一個node_modules文件夾(目前爲空),以及pack.json文件。其實咱們剛纔npm init命令就是爲了配置這個package.json,所以也能夠徹底本身來手動建立。
接下來安裝webpack和webpack-dev-server,執行命令:
npm install webpack webpack-dev-server --save-dev
安裝webpack很順利,沒有遇到任何問題。
安裝完畢後,node_modules文件夾中就再也不爲空了,裏面存放的都是webpack的相關依賴。package.json中也多了"dependencies"和"devDependencies"兩項,其記錄的是當前依賴及版本信息,其中"dependencies"爲空。
"devDependencies": { "webpack": "^4.16.1", "webpack-dev-server": "^3.1.4" }, "dependencies": { }
隨後在當前文件夾下新建一個public文件夾(文件夾名任意),在裏面寫一個index.html頁面,內容隨意。接下來咱們就要配置webpack了,在文件夾下新建一個webpack.config.js文件,此時目錄結構爲:
編輯webpack.config.js,因爲咱們的目的是建立一個web服務器,所以只須要配置如下內容:
module.exports={ devServer:{ contentBase:"./public" } }
devServer是webpack中web服務器的相關配置項,contentBase指定的是頁面加載目錄,而其加載頁面默認爲index.html,因爲咱們的index.html是在public目錄下,所以就將contentBase設置爲"./public「。
接下來在package.json中配置web服務啓動命令,該命令配置在scripts中的,其命令名稱爲「server」,命令詳情爲「webpack-dev-sever --open」:
"server":"webpack-dev-server --open"
將其插入scripts中:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "server": "webpack-dev-server --open" },
在命令行中輸入"npm run server」回車以便啓動web服務,此時會遇到一個坑,webpack並無啓動web服務,而是報錯:
其大意是缺乏webpack-cli,那麼咱們天然就安裝這個webpack-cli,執行命令:
npm install webpack-cli --save-dev
webpack-cli安裝過程很順利,隨後再執行「npm run server」就能夠正常啓動web服務了,而且啓動默認瀏覽器,顯示public下的Index.html頁面,web服務的默認端口是8080。
至此,咱們第一部分的目的:啓動一個web服務便完成了,總結一下,要從零開始啓動webpack的web服務須要作:
安裝node.js、npm
安裝webpack、webpack-cli、webpack-server-dev
npm初始化
編寫一個顯示頁面並命名爲index.html
建立webpack.config.js,並配置devServer信息。
配置package.json,設置web啓動命令。
到目前爲止,咱們絲毫未說起另外一位主角:react,接下來咱們就繼續搭建環境,讓其支持react。首先天然是要安裝react,咱們須要安裝react和react-dom,執行命令:
npm install react react-dom --save
因爲react是在正式環境中也須要的,所以npm安裝時沒有帶-dev參數。
接下來修改以前的index.html,無論之前是怎麼編寫的,請在HTML中增長一個 <div>,將其的ID設置爲"boot「,同時編寫外部js引入,引入的js名爲bundle.js。
<body> <div id='root'></div> <script src='bundle.js'></script> </body>
接下來在public目錄下建立index.jsx文件,注意後綴名是jsx,其內容爲:
import React from 'react' import { render } from 'react-dom' class Hello extends React.Component { render() { return ( <p>hello react!</p> ) } } render( <Hello/>, document.getElementById('root') )
react的語法細節咱們暫時不關心,只要知道最後頁面上會輸出hello react!就能夠了。
jsx是react的專用語法,HTML是沒法引用的,所以咱們須要將其轉換爲HTML可以識別的JS,而這個正是webpack大顯身手的時候,咱們開始來配置webpack,配置以前,再確認一下的當前的目錄結構:
首先咱們是經過babel來轉換jsx的,所以須要安裝babel相關的環境,咱們須要安裝:
babel-core
babel-loader
babel-preset-es2015
babel-preset-react
執行命令:
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
因爲咱們要轉換的源文件是index.jsx,轉換後的目標文件是bundle.js,所以須要在webpack中配置入口和出口,在文本webpack.config.js中增長如下內容:
entry:__dirname+"/public/index.jsx",
output:{
path:__dirname+"/public",
filename:'bundle.js'
}
entry是轉換的入口,而output是轉換的出口。
同時還要在webpack.config.js中配置loader,讓其經過外部工具來處理文件,而咱們當前要處理的是經過babel來處理jsx文件。所以到了這一步咱們大體會有些明白了,並非webpack自己幫咱們處理這些,而是像箇中介同樣,把要處理的部分與相關的工具聯繫在一塊兒。
咱們在webpack.config.js中加入:
module: { loaders: [ { test: /\.(jsx)$/, exclude: /node_modules/, loader: 'babel' } ] }
其代表jsx文件須要用babel來處理,可是對於node_modules文件夾中的文件忽略掉(exclude設置)。此時webpack.config.js的內容就是:
module.exports={ entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public" }, module: { loaders: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel' } ] } };
照理來講,到了這一步全部該作的事情都已經作完了,經過babel將index.jsx解析成bundle.js,Web服務將啓動index.html,而index.html會引入bundle.js,最後在頁面上顯示hello react!
可是,事情每每不是那麼順利的,接下里要繼續踩坑!首先咱們先執行npm run server看看是什麼狀況:
立刻就遇到坑,刺眼的紅色錯誤提示,意思竟然是loaders屬性無效?!問題出如今webpack版本上,咱們安裝的版本是4.16.1,此時webpack.config.js中loaders的寫法已通過時,應該用rules,同時babel也應該用babel-loader來替代,實際的寫法爲:
module: { rules: [ { test: /\.(jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] }
此時webpack.config.js的內容爲:
module.exports={ entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public" }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] } };
接下來繼續試試npm run server,依然報錯:
此處仍然有一坑!因爲咱們的jsx是用es6語法編寫的,所以須要經過label來解析,那麼實際上此處還缺乏一個文件,就是「.babelrc」,注意這是一個名稱很奇葩的文件,只有擴展名而沒有文件名,該文件在windows環境下是沒法經過資源管理器建立的,須要到命令行下執行type null>.babelrc命令:
type null>.babelrc
雖然提示「系統找不到指定的文件」,可是實際上已經建立了.babelrc文件,隨後用文本編輯器將該文件打開,輸入內容:
{ "presets": ["react", "es2015"], "env": { "dev": { "plugins": [["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }]] } } }
至此,再執行npm run server,終於能夠看到頁面正常顯示了!
如果此時頁面還不能正常顯示的話,也許就要清理下緩存,從新生成bundle.js文件。或者在package.json中的scripts中增長「start「命令,其值爲「webpack」,即:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" },
這樣在命令行中執行「npm start」就能夠從新編譯jsx爲bundle.js了。
npm start
再總結一下咱們遇到的坑:
npm初始化時的項目名稱要合規,特別是不能出現中劃線下劃線。
安裝webpack-cli。
loaders已過期,須要替換爲rules。
須要建立.babelrc文件。
至此咱們便搭建了一個最簡單的webpack+react環境,當咱們修改index.jsx中的內容時,頁面刷新後也會發生改變,接下來就能夠好好學習react了!
固然,咱們能夠更改webpack.config.js中的devServer,添加inline:true,這樣即可以實現jsx更改後,頁面會自動刷新,不用咱們每次修改後都去手動刷新去看效果了。另外再增長mode:"development",這樣刷新的速度會大大加快!
最終的文件目錄結構爲:
各文件的最終內容:
index.html
<!DOCTYPE html> <html> <head> </head> <body> <div id='root'></div> <script src='bundle.js'></script> </body> </html>
index.jsx
import React from 'react' import { render } from 'react-dom' class Home extends React.Component{ render(){ return( <p>Hello react!</p> ) } } render( <Hello />,document.getElementById('root') )
.babelrc
{ "presets": ["react", "es2015"], "env": { "dev": { "plugins": [["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }]] } } }
package.json
{ "name": "test", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "webpack": "^4.16.1", "webpack-dev-server": "^3.1.4" }, "dependencies": { "react": "^16.4.1", "react-dom": "^16.4.1", } }
webpack.config.js
module.exports={
mode:"development", entry:__dirname+"/app/index.jsx", output:{ path:__dirname+"/app", filename:'bundle.js' }, devServer:{ contentBase:"./public",
inline:true
}, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader' } ] } };