從零開始,用最少的配置、最少的代碼、最少的依賴來搭建一個最簡單的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' } ] } };