最小白的webpack+react環境搭建
本文也同步發表在我的公眾號“我的天空”
從零開始,用最少的配置、最少的代碼、最少的依賴來搭建一個最簡單的webpack+react環境。
最近在玩webpack+react+移動端,那麽第一步自然是搭建相關的環境,本來網上的教程很不錯,只是前端相關的東西發展太過迅猛,只相隔了半年有些東西的版本就不對了,有些配置、命令等照著之前的教程做就可能會掉到坑裏去,別問我怎麽知道的,我剛剛從坑裏爬出來,因此趕緊寫篇文章來記錄一下,也算是讓自己再鞏固一下。
本篇完全是從零開始,用最少的配置、最少的代碼、最少的依賴來搭建一個最簡單的webpack+react環境。會把一個小白的經歷原原本本的寫出來,遇到的坑都用紅色的坑
本篇文章寫作的日期是2018-7-21,因此所有依賴的版本到當前日期為止,以後如果有升級變化的話,那也是無法當前預料得到的。我的操作系統是win7,因此不涉及到linux的相關知識點。編輯器是Sublime Text3.0,順便安利一下Sublime Text,好用速度又快,真心不錯!
我是參考這篇教程:https://segmentfault.com/a/1190000006178770
現在讓我們開始吧,第一步我們先配置一個webpack的web服務器。
webpack依賴於node.js,那麽第一步是安裝node.js,這個沒什麽好說的,windows環境的安裝就更友好了,官網下載安裝包,一路默認安裝即可,現在的node.js安裝完畢後,npm也就自帶安裝好了,後面我們就要一路與npm打交道了。
首先我們要用npm初始化項目,電腦上新建一個目錄保存我們的練習文件,隨後進入cmd命令行,轉到該目錄下。如果命令行不會操作的話,請先掌握cd這個命令。接下來在該目錄下輸入npm init命令:
npm init
根據提示一路回車就可以了,不過這個地方可能會有一個坑存在,如圖:
這裏報錯: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‘ } ] } };
最小白的webpack+react環境搭建