構建一個小項目——FlyBird,學習webpack和react。
(本文成文於2017/2/25)javascript
從webpack開始
本篇從零開始,詳細記錄webpack的各個方面。
文章中將會放入不少連接以便擴展,我也會概括總結,不讀擴展不會影響到對本文的理解,可是有時間仍是看看吧。css
聲明:html
在閱讀本文列出的連接文章時,若遇到與本文不一樣的,由於文章的時效性問題——前端
請以本文爲標準java
當前時間2017/2/26 在此以後出現的文章,讀者請注意對比,自行判斷node
核心資料:react
webpack2官網doc中文版——小書 後文中的簡稱—小書—專指此連接
此文檔很是詳細,最近一次修訂時間爲——2017 年 2 月十幾號
目前閱讀起來,儘管放心。本文爲教程,小書爲手冊,二合一,棒棒噠。(您能夠親自去看看他是啥時候又更新了,若是依然比較新,或許不少問題,能夠在裏邊找到答案)linux
其餘較完整的小書型資料:webpack
webpack_github庫doc
webpack.js.org(小書的英文原文)
webpack for React英文
webpack傻瓜教程(較老)
webpack中文教程——趙達(老書)nginx
後邊的雖然是老書,可是,多條資料,就多一條路,不是麼?
有助於學習理解的代碼庫
在文章結尾
最近在學習react,不免看到網上各類webpack+react的文章,發現有些很全面的資料,內容卻有些過期(好比有個gitbook的書,是在react尚未分離react react-dom的時候寫的),而有的資料則雖然挺新,可是每每只談一個方面。
種種緣由,我決定,結合官網,記錄下webpack的各個方面,系統學習一下。
從零開始構建小項目-FlyBird(源代碼可在文章結尾處找到)
這是原始數據目錄(原生寫的)
能夠看到,整個項目有一些js文件,一堆img文件,一個css文件。未來咱們也要一步步親自實現他們,這個目錄展現了整個項目大概須要些什麼。讓咱們使用webpack構建工做流來管理將來咱們將要寫的代碼吧。
建立一個文件夾,並在文件夾下打開命令行
咱們須要node-npm來安裝和運行webpack,關於node和npm不懂得同窗請自行百度。
擁有node-npm後
在當前文件夾初始化npm的package.json文件npm init
相關問題隨便填。這會建立 package.json文件,不用擔憂問題填錯,你能夠以後修改它。
這句命令就表示,咱們把當前文件夾,初始化爲一個npm包,它處於npm的管理之下。
咱們能夠經過npm下載其餘人的包,構成了本身包的依賴;當咱們完成了咱們的包,也能夠發佈它,讓別人下載。最主要的是使用npm來管理依賴。
package.json文件用來配置當前包,配置文件含有不少屬性,反映着包的不一樣信息,後文中,遇到一個介紹一個,而不作全面介紹。
(詳情請移步package.json屬性詳解)
當init後,咱們有以下package.json
//package.json { "name": "mydemo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
//只看,不用寫後邊須要動手寫,我會說 "scripts": { "build": "webpack", "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build" }
當咱們在命令行npm run build
時,就等於webpack
,原理很簡單,在執行npm run
命令時,會新建立一個Shell,並將當前目錄的/node_modules/.bin/
加入到PATH
變量(環境變量),以後運行腳本命令,結束後,將PATH
恢復原樣。好吧,其實過高級的並木有卵用,目前,只知道能夠懶省事就行啦(^o^)/~,好比npm run dev
,若是每次都打一長串,會瘋的。
是時候安裝webpack了!不過在安裝以前,還要介紹一些概念。
概念——開發與發佈
一個項目一般都會有,開發,發佈這兩種狀態,也就是本身瞎搗鼓,和放網上讓別人用。無論是哪一種狀態,咱們的項目均可能會依賴別人的包。那麼天然而然,由於狀態的不一樣,依賴的包也不太同樣。好比,在開發階段,每每須要進行測試,看看能不能跑通,而測試工具顯然在發佈時是沒必要要的。
爲了分別管理,npm在package.json提供了這樣的字段
在下載別人的包時,若是隻指望下載一個發佈的可運行版本,而不但願對此包進行任何開發,能夠利用npm install --production
僅下載dependencies字段中的依賴。
好吧,對於咱們的項目並無什麼卵用,由於咱們將使用webpack管理整個工做流程,npm只是用來下載東西(囧),我只是說明一下。
開發與部署
開發到必定階段須要發佈一個版本,咱們每每須要一個文件夾來保存整合後的項目。這個過程,就叫作部署"deploy"。這也是webpack的工做,會用到一個和開發階段不一樣的webpack配置文件,它只是將輸出目錄換成了另外一個而已。
在咱們的小項目進入到這個階段後,再細說。
npm install webpack --save-dev
這將在本地(當前文件夾下)安裝webpack並在開發依賴字段(devDependencies )中保存信息。
webpack顯然只須要在開發階段用到
若是想要運行它,進入node_modules/.bin
,並運行它webpack
。
固然,咱們也能夠在上文提到的package.json中的scripts字段中配上
//動手寫
"scripts": { "build": "webpack" //因爲scripts將node_modules/.bin加入到環境變量PATH中,因此腳本Shell能夠搜索到webpack指令,`npm run a`等價的`webpack`也就能夠運行了。 },
注意,不推薦全局安裝 webpack
npm i webpack g
。這會鎖定 webpack 到指定版本,而且在使用不一樣的 webpack 版本的項目中可能會致使構建失敗。
webpack的使命
從上邊目錄圖中也能夠看到,咱們須要用webpack管理不少東西,依賴包,本身寫的jsx,css,各類各樣的圖片,也許還有字體。
爲了性能,咱們須要根據依賴關係,對各類jsx,css,img進行壓縮整合爲數量跟少的幾個文件。
爲了開發方便,咱們須要瀏覽器自動刷新,sass/less自動轉換的功能等等。
這些,就是webpack的使命,讓咱們的開發更高效。
能夠簡單的劃分爲來源——去處,如圖
build文件夾,則是通過webpack打包,自動生成的文件的去處。
在build文件夾下,新建index.html用來表示咱們的索引頁
它長這樣,其中的div用來給作一些頁面修改什麼的用
// index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>FlyBird</title> </head> <body> <div id="div1"></div> <script src="bundle.js"></script> </body> </html>
對於部署文件夾來講,通常是這樣
因此,最終,在app中寫東西,打包到build中調試、看效果,不錯的話,發佈到dist文件夾裏。
架子已經搭好了,如今,咱們須要控制webpack的各類行爲,添加各類功能。
能夠有三種途徑
webpack.config.js
文件中寫入字段,webpack在啓動時會讀取它,並依據其工做--a=b
),實現不一樣的配置。對於第三種,本文不作過多介紹,在文章最後,我會貼出一位前輩的node api模板地址,有興趣的同窗能夠移步文章結尾。
注意:當使用node api同時又使用了webpack.config.js時,webpack.config.js將不會生效
咱們經過配置文件,此時你的目錄應該是這樣(新建文件)
由於咱們會往兩個地方打包,那麼天然,得倆配置文件了。
webpack.config.js
目標buildwebpack.production.config.js
目標dist進行以下配置
//動手寫 // webpack.config.js var path = require("path"); module.exports = { entry: path.join(__dirname, '/app/main.js'), output: { path: path.join(__dirname, '/build'),//打包後的文件存放的地方 filename: "bundle.js"//打包後輸出文件的文件名 } };
__dirname 是當前運行的js所在的目錄
模塊的依賴書寫方式:
方式取決於模塊系統,上文中很明顯是commonJS的方式。
webpack支持最新的模塊系統——es6的模塊系統(ES6 module import),
可是,注意:這並非說它支持es6。
也就是說,咱們能夠直接使用如import/export
語句來導入模塊,可是,若是咱們想要打包含有其餘es6語法的模塊時,依然須要babel轉換器
關於模塊系統這裏有大略的介紹——webpack中文指南——趙達(模塊系統)
一個一個來講
1.基本概念
表示模塊的來源,入口,起點。它的值能夠是
entry: '某模塊'
表示一個單一模塊做爲起點(固然,單一入口也能夠用後邊兩種寫),把這個模塊須要的東西打包成一堆entry: ['模塊1', '模塊2']
//只看 entry: { page1: "./page1", page2: ["./entry1", "./entry2"] }
這將會打包成兩堆,每一堆都有一個[name]屬性,值爲對應entry中的屬性名。 //只看 output: { // Make sure to use [name] or [id] in output.filename // when using multiple entry points path: '/build', filename: "[name].bundle.js", chunkFilename: "[id].bundle.js" }
在filename中使用[name]來生成對應打包堆特殊的名字。2.各類問題
entry值的寫法問題
上網大眼一看,有三種
entry: path.resolve(__dirname, 'app'); entry: path.join(__dirname, 'app'); entry: __dirname + '/app';
在linux,mac環境下這三種是同樣的,而在windows環境下,最後一種是錯誤的
這是由於,node的path模塊的方法,在解析路徑時候,會使用當前平臺的路徑分隔符,windows的是\
。
若是咱們直接使用+
號拼接,天然發生錯誤。
path.resolve與path.join
join方法僅僅進行路徑拼接
resolve方法則會作一些解析工做,它會將參數從右到左拼起來,直到遇到一個絕對路徑。path的node官網文檔
總結一下路徑符號
'.'表示當前目錄 `..`表示上一級目錄 `/`表示路徑起點——絕對路徑的標誌,一般爲當前運行腳本所處的位置。
因此在使用resolve的時候要注意。
context配置——entry的根目錄
//只看 { context: path.join(__dirname, 'app'), entry: "entry", }
咱們也能夠經過context來定義entry的根目錄,這也同時定義了後邊output.pathinfo
、loader項下的reslove(v2版本新改動,可在小書中查看)
的根目錄。
若是咱們不聲明context字段,默認爲process.cwd()
cwd()
是當前執行node命令時候的文件夾地址__dirname
是被執行的js 文件的地址
小結語
對於咱們的FlyBird項目來講,顯然僅僅是一個單頁面應用,只須要一個入口,因此entry設置極其簡單
//沒啥變化 module.exports = { entry: path.join(__dirname, '/app/main.js'), output: { path: path.join(__dirname, '/build'), filename: "bundle.js" } };
1.基本概念
output規定了如何將打包後的一堆堆的東西,寫在磁盤裏。
它的內容真的很是多,我會挑出以後要用的,具體說說;想了解具體的,請看小書
2.各類問題
output.filename多個chunk輸出?
也就是上邊entry是對象狀況,咱們必須保證輸出的名字惟一性。每一個chunk都有一些屬性來幫助咱們達到目的
[name]
最簡單,就是在entry裏邊的屬性名[hash]
is replaced by the hash of the compilation[chunkhash]
is replaced by the hash of the chunk後倆不明白?他們牽扯到了緩存,我會在下文作簡述,而且以後會專門寫一篇關於webpack緩存的總結
瞭解更多,請移步這裏——hash-chunkhash的理解,區別。(這篇文章從概念上講解了hash和chunkhash,在下文的緩存簡述裏,我會作進一步的說明)
2017/2/25 21:02更新——照如今這進度,想寫緩存總結不知到猴年馬月了,您仍是看看下邊的文章吧(下文簡述已經寫好了)
filename與chunkFIlename區別?
請移步——filename與chunkFIlename區別
output.path與output.publicPath?
output.path值爲輸出目錄的絕對路徑,也可用[hash]
output.publicPath項則被許多Webpack的插件用於在生產模式下更新內嵌到css、html文件裏的url值,在熱加載模塊應當關注它,必須經過這個屬性來告訴熱加載模塊去哪加載
關於他倆的區別的具體解釋,請移步path與publicPath(往下翻,第4條,固然前邊也能夠看看)
3.小結語
好了,關於output經常使用就這幾個。忍不住吐槽下,它屬性真的太多了,還大部分不知道有啥用(想了解更多,去看小書哦)
到此咱們已經完成了最簡單的webpack.config.js的配置,經過這個配置webpack能夠將main.js打包成bundle.js
下面讓咱們來試一試是否有效
~~
webpack-dev-server可讓瀏覽器實時刷新,顯示咱們對文件的改動,不如趁着驗證main.js和bundle.js的過程,也一併嘗試一下。
webpack-dev-server是一個小型的node.js Express服務器,爲webpack打包生成的資源文件提供Web服務。webpack-dev-server發送關於編譯狀態的消息到客戶端,客戶端根據消息做出響應。
——想看更多能夠瀏覽這個webpack-dev-server解讀
~
若是你不但願使用webpack-dev-server來啓動服務,(要麼是你有服務器了,要麼是你想知道不用它怎麼啓動服務),詳情請參考
小書——開發(若是你有服務器,請翻到此連接最後,查看webpack-dev-middleware,本文不會對這種狀況作過多討論)
1.安裝
這個功能是一個獨立的模塊實現的,因此咱們首先要安裝這個模塊
npm install --save-dev webpack-dev-server
默認狀況下,它將在當前文件夾下啓動一個websocket服務,端口號爲8080
兩種方法配置服務(選擇其一)
1.配置文件 ——Node API
2.cmd指令(推薦)
// webpack.config.js加入 //只看 devServer: { port: 8080 //設置監聽端口(默認的就是8080) contentBase: "./build",//本地服務器所加載的頁面所在的目錄 colors: true,//終端中輸出結果爲彩色 historyApiFallback: true,//不跳轉,用於開發單頁面應用,依賴於HTML5 history API 設置爲true點擊連接仍是指向index.html }
若是你須要以server.js的形式寫出相關配置,也不是什麼難事 const WebpackDevServer = require('webpack-dev-server'); const webpack = require('webpack'); const config = require('./webpack.config.js'); const path = require('path'); const compiler = webpack(config); const server = new WebpackDevServer(compiler, { contentBase: 'www', hot: true, filename: 'bundle.js', publicPath: '/', stats: { colors: true, }, }); server.listen(8080, 'localhost', function() {});
關於如何以server.js方式定義配置,將會在文章最後給出模板連接,已經有前輩作好了一切(伸手就有,感受真好!上邊代碼裏不認識的沒關係,)cmd指令
webpack-dev-server --devtool eval-source-map --progress --colors --content-base ./build // --表明一個指令,與上邊各個屬性對應 // 此處展現的是常常會在網上看到的寫法,並不是個人寫法
--devtool eval-source-map
與webpack-dev-server不要緊,先不談,會在調試模塊詳細說明--progress --colors
:前着表示顯示打包過程,後者是給顯示出來的進度加點顏色(一篇綠,一點紅,手動滑稽~)。--content-base
:設置目錄
注意:
有一些在前邊出現的屬性,並無被對應的寫在cmd指令中。事實上,大多數配置都有兩種寫法,好比:historyApiFallback: true
對應--history-api-fallback
port:8080
對應--port 8080
這些並非我介紹的重點,若是你想要了解更多細節,請移步
小書api章節
若是你但願看到一些具體例子,請移步
webpack-github的examples文件夾
若是咱們使用cmd指令,每次都打那麼長,絕對要瘋,因此~~~
//動手寫 // package.json "scripts": { "build": "webpack", "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --content-base ./build" },
目前,最簡單的配置已經完備。咱們有了一個服務器,它的端口號默認是8080
讓咱們寫一些具體的東西,測試一下它的效果
// 新建main.js document.write('我');
裏邊的內容天然你隨便寫。npm run dev
localhost:8080
訪問,此時,咱們在本地作出更改,而後瀏覽器將自動刷新,便可看到效果。可是,若是觀察頁面:
咱們的頁面整個都被刷新了,這顯然是不高效的,爲何?
假如工程很是的龐大(實際開發中,每每都是‘很是龐大’),頁面像我這篇文章同樣,很長,,,修改一個很小的地方,若是頁面整個刷新,第一,須要等待頁面刷新完,很難過,第二,刷新出來,咱還得滾動半天到我們修改的地方看效果。等等。都是不高效的。
因此咱們須要另外一個功能
然而實現這個功能的過程當中會遇到不少問題,接下來我將經過——問與答逐個說明
問題一:自動刷新功能的兩種模式?以及如何配置?
這個是個用來承上啓下的問題,首先,咱們要更深刻的瞭解一下自動刷新功能。
1.兩種模式
webpack-dev-server自帶就有自動刷新功能,並且它是有兩種啓動模式的
iframe模式
在iframe模式下:頁面是嵌套在一個iframe下的,在代碼發生改動的時候,這個iframe會從新加載
關於iframe是什麼請自行百度,這不是個人重點。
inline模式
在inline模式下:一個小型的webpack-dev-server客戶端會做爲入口文件打包,這個客戶端會在後端代碼改變的時候刷新頁面
什麼叫做爲入口文件打包?它其實相似這樣,請看
entry: [ 'webpack-dev-server/client?http://0.0.0.0:9090',//資源服務器地址 'webpack/hot/only-dev-server', path.resolve(__dirname, "app") ] // 數組第一項就是那個小型服務器
這樣的寫法,網上webpack文章上常常見,聯想一下上文介紹的entry的數組值的意思。沒錯,inline模式就是作了這樣的事情。
關於數組第二項:它是一個api,然而它只有node api的寫法,沒有cli的寫法。在瀏覽小書的api章節,你會發現一些相似的。hotOnly: true
那麼咱們還能夠像上邊那樣寫,也就是手動的啓動了這個服務。(揪住此功能的實體,把他強制打包進來)。
或許你在網上還見過另外一種方式,經過index.html在bundle.js以前插入它。其實道理是同樣的。
2.配置
webpack-dev-server默認開啓inline模式,請看:
可是,難道不能啓動iframe模式了麼?非也,請看
那麼,咱們並無啓動iframe模式啊?這與上邊的hotOnly那一塊說的一個意思,是咱們手動啓動了服務
咱們能夠關閉默認啓動的inline模式:--no-inline
命令
可是想要看到iframe模式,依然須要再瀏覽器中端口號後加上/webpack-dev-server/
注意:在網上,你會看到各類各樣的奇怪說法,請依據你的demo結果,結合本文理解。(包括本文引用的文章裏,好多都說的很奇葩,就連小書也沒有說清楚這一塊)
最後,總結一下:
實時刷新功能,根本不用咱們管,webpack-dev-server已經作好了一切。
問題二:明明設置正確,卻不會自動刷新,爲何?
1.編輯器
一些文本編輯器有「safe write」(安全寫入)功能,而且默認啓用。所以,保存文件後並不老是會致使 webpack 從新編譯。
每一個編輯器都有不一樣的方式來禁用這一功能,如下是一些最多見的:
- Sublime Text 3 - 在用戶設置(preference)中增長 "atomic_save": false。
- IntelliJ - 在設置中查找 「safe write」而且禁用它。
- Vim - 在設置中增長 :set backupcopy=yes。
- WebStorm - 在 Preferences > Appearance & Behavior > System Settings 中取消選中 Use "safe write"。
摘錄自————小書—開發
2.另外一種可能——緩存
緩存簡述
博主遇到過沒法自動刷新的問題,找不到緣由,次日莫名其妙好了。
當我想要重現錯誤時,它死活不會錯,關因而不是緩存致使,沒有辦法驗證。
咱們都知道瀏覽器會緩存請求的文件,當咱們再次請求時,首先從緩存列表查找,沒有再去請求。這會提升性能。
很明顯,咱們的bundle.js並非從磁盤緩存中來的(細心的同窗會說,哇,bundle.js爲何那麼大?!這牽扯甚廣,又是一篇文章的量啊)
點開bundle.js查看他的http請求頭,cache-control:max-age=0
此項用來表示不緩存。
若是緩存,緩存多久?
max-age
指示客戶機能夠接收生存期不大於指定時間(以秒爲單位)的響應(不超過這個秒數的,都用緩存裏的)Expires
表示存在時間,容許客戶端在這個時間以前不去檢查(發請求),等同max-age的關於緩存概念的更多信息請移步————
HTTP頭的Expires與Cache-control
前端緩存策略與基於Webpack的靜態資源版本管理
緩存是解決性能問題的一大幫手,我會專門寫一個文章來分析它(不知到什麼時候才能成文),此處再也不多說。
到目前爲止,並無再發生奇怪的錯誤。
問題三熱替換Hot Module Replacement、react-hot-loader與react-transform
1.基本概念
什麼是熱替換?就是局部刷新,這樣,提升開發效率,節約時間。前邊咱們使用inline方式,每次都會刷新整個頁面,而iframe模式會刷新整個iframe標籤,顯然不是咱們想要的高效
按照大部分網上教的,弄的我暈頭轉向,到最後還作不出來一個熱替換效果。深受其害,,,無力吐槽
webpack-dev-server自帶的Hot Module Replacement模塊用來實現熱替換功能。
兩種方式開啓它:
無論咱們用那種方式,只要開啓,webpack就會向咱們的模塊暴露module.hot
所以,咱們可使用 module.hot
鉤子函數爲特定資源啓用 HMR。這裏最重要的 API 是 module.hot.accept,它指定如何處理對特定依賴的更改。
因此,咱們一步步本身測試一下
// 在main.js的目錄下建立component.js // component.js var oDiv = document.querySelector("#div1"); oDiv.textContent = "我是佈雷佈雷,你好啊";
// main.js require("./component.js"); if(module.hot) { module.hot.accept(); }
咱們模擬了一個組件,並在main.js中引用了它。
接下來,必須將webpack.config.js中,output下的publicPath與devServer下的publicPath設置爲同樣
// webpack.config.js ··· output: { ··· publicPath: '/', ··· } ··· devServer: { ··· publicPath: '/', ··· } ···
下面關於兩種配置方式
cmd--hot
設置它以後,啓動服務,在瀏覽器能夠看到:
配置文件
Node.js API方式須要作兩個配置:
new webpack.HotModuleReplacementPlugin()
加入到webpack配置文件的plugins
項;hot:true
加入到webpack-dev-server的配置項(devServer)裏面。關於webpack/hot/only-dev-server
前文也介紹了,雖然不加沒錯,可是仍是加上比較好。
在研究熱加載的過程當中,有一些很讓我生氣的事
下邊的寫法是錯誤的!!!!!!
將webpack/hot/dev-server
添加到entry中
把它改成webpack/hot/dev-server.js
名字寫全,就能夠了。還不清楚爲何報錯,有知道的小夥伴,請指教一二!
說到底仍是命令行方式最簡單——像下邊這樣寫就好
//你的應該也長這樣 "scripts": { "build": "webpack", "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --content-base ./build " },
其餘配置選項
--quiet 控制檯中不輸出打包的信息 --compress 開啓gzip壓縮 --progress 顯示打包的進度
更多配置信息——官網webpack-dev-server-cli
~~
2.三個模塊
以上配置好後,咱們已經能夠熱加載實時刷新了,可是咱們的項目FlyBird(我都快把他給忘了)想要用到react,組件化的react給熱加載帶來了一些麻煩。
react-hot-loader
來解決問題
咱們都知道react組件是狀態機,有state對象來表示狀態,假如由於一些小改動,致使要渲染整個組件,此時現有狀態就會丟失。react-hot-loader
就是來解決這個問題的。因此它是必須的。
react-transform
被棄用react-transform
也是用來解決這個問題,不過它已經老早就中止維護了,因此不要使用它,我們按官網上的,都是使用react-hot-loader
因爲react使用的是jsx+es6語法,因此咱們不能僅僅只是打個包完事,還要在打包過程當中使用babel對其進行編碼轉換。
總結一下:
react-hot-loader
babel
(babel不懂的,請自行百度教程)npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2
由於,默認安裝的仍是v1版本的react-hot-loader,咱們要使用的是最新的版本,必定要帶上版本號。 npm install --save-dev react-hot-loader@3.0.0-beta.6
npm install --save react react-dom
新建.babelrc
並配置 // 新建.babelrc { "presets": [ ["es2015", {"modules": false}], // webpack如今已經支持原生的import語句了, 而且將其運用在tree-shaking特性上 "stage-2", // 規定JS運用的語言規範層級 // Stage 2 是 "草案", 4 是 "已完成", 0 is "稻草人(strawman)"。 // 詳情查看 https://tc39.github.io/process-document/ "react" // 轉譯React組件爲JS代碼 ], "plugins": [ "react-hot-loader/babel" // 開啓react代碼的模塊熱替換(HMR) ] }
配置webpack.config.js,由於咱們已經使用babel轉義es6因此,盡情使用吧const { resolve } = require('path'); const webpack = require('webpack'); module.exports = { context: __dirname, entry: [ 'react-hot-loader/patch', 'webpack/hot/only-dev-server', './app/main.js' ], output: { path: resolve(__dirname, 'build'),//打包後的文件存放的地方 filename: "bundle.js",//打包後輸出文件的文件名 publicPath: "/" }, devServer: { contentBase: resolve(__dirname, 'build'), hot: true, publicPath:'/' }, module: { rules: [ { test: /\.jsx?$/, use: [ 'babel-loader', ], exclude: /node_modules/ }, ], }, plugins: [ new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), ], devtool: "cheap-eval-source-map", };
編寫main.js,寫一段react測試一下,也是好的
import React from 'react'; import ReactDOM from 'react-dom'; import { AppContainer } from 'react-hot-loader'; import Cpt from './component'; const render = (Component) => { ReactDOM.render( <AppContainer> <Component /> </AppContainer>, document.getElementById('div1') ) }; render(Cpt); if(module.hot) { module.hot.accept('./component', () => { render(Cpt) }); }
最關鍵的就是module.hot,必定要寫,它用來告訴webpack怎麼去熱替換
這是咱們的組件component.js,它長這樣
import React from 'react'; const Cpt = () => ( <div> <h1>我是蓋世英雄!</h1> </div> ); export default Cpt;
不少朋友還在使用v1版本的react-hot-loader,網上不少教程也都是v1版本的,小夥伴們在看資料時候必定要注意區別。
若是你想了解更多——
react-hot-loader的github能夠在這裏瞭解到api,與之前的區別,還能夠看到不少模板。
這裏是一些區別的討論
都是英文的,小夥伴要有點耐心讀哦
這是react-hot-loader的網站
1.一些話
戛然而止,,,好吧,是個人錯,我小小的解釋一下。
寫這篇文章,徹底超出了個人預計,我覺得兩天就能寫完,然而整整用了五天,從早上8點坐下來,一直到晚上11點,有兩天午餐都忘吃了。
中間遇到了不少困難,,好比研究緩存那一塊,由於莫名出錯又莫名其妙好了,我想還原錯誤,猜想是否是緩存問題,就去清緩存,瀏覽器自帶的緩存清理不給力,我就手動把我谷歌下的user data文件夾給刪了。。。刪完以後才意識到,本身書籤還沒備份,,,唉,上百個書籤,都是心血啊,又花了點錢買數據恢復,也沒恢復過來,又白賠進去幾百塊錢。
相似種種吧,這會兒真的有點累,昨天熬夜到4點多,想着能搞定,誰知道仍是今天才弄完。
固然,其實這些都不是最關鍵的,累了,休息休息就好。
最主要的是,博主仍是學生,立刻要去找工做了,,,然而,我尚未開始複習。。。僵硬。。。因此,必須暫時停下來了。
2.關於這個項目
FlyBird,,,好吧,我都快把它給忘了。其實按計劃,今天是可以作完的,由於只是一個簡單的重構,就像todoMVC同樣。
忙完這一段我依然會着手完成它,就像作,下面對接下來須要討論的問題彙總一下,以備之後使用
未解決的問題:
緩存策略
| 插件、loader
打包策略
| 插件、loader、同步異步加載
生產環境構建
| 插件、loader
| 使用node api構建配置文件生成系統
懶加載
| 插件、loader
測試功能
| 插件、loader
兼容問題
| 插件、loader
v1到v2版本的改動
| 插件、loader、api接口、書寫方式等等一大堆
關於webpack,小書上其實很全面了,並且比較新,你們能夠放心去查閱,固然,也要關注官網的最新的消息。
react部分,其實沒有什麼好說的,由於網上的教材也比較全了,固然,這不是我之後偷懶的理由。
我會回來完善這篇文章的,讓它成爲一個完整的,友好的引導。這是我對本身的承諾。
3.放在最後的資料
文章小例子github庫——
FlyBird這個從哪來的?感謝這篇文章帶給個人一些衝動
JavaScript實現Fly Bird小遊戲有一些很棒的github庫,也放上來
- webpack-dev-server的github,能夠在examples文件夾裏找到例子
- create react app 兩萬多的星。。。
- webpack-hmr-3-ways 名字已經說明了一切,很不錯
- react-learn
- react-redux-webpack模板
- react-hot-loader的github
- react-static-boilerplate
- react-hot-boilerplate
一些我以爲應該仔細看看的文章: