webpack-react之webpack篇(http://www.jianshu.com/p/794d573d2c53)

構建一個小項目——FlyBird,學習webpack和react。
(本文成文於2017/2/25)javascript

從webpack開始
本篇從零開始,詳細記錄webpack的各個方面。
文章中將會放入不少連接以便擴展,我也會概括總結,不讀擴展不會影響到對本文的理解,可是有時間仍是看看吧。css

聲明:html

在閱讀本文列出的連接文章時,若遇到與本文不一樣的,由於文章的時效性問題——前端

請以本文爲標準java

當前時間2017/2/26 在此以後出現的文章,讀者請注意對比,自行判斷node

開始

最近在學習react,不免看到網上各類webpack+react的文章,發現有些很全面的資料,內容卻有些過期(好比有個gitbook的書,是在react尚未分離react react-dom的時候寫的),而有的資料則雖然挺新,可是每每只談一個方面。

種種緣由,我決定,結合官網,記錄下webpack的各個方面,系統學習一下。

從零開始構建小項目-FlyBird(源代碼可在文章結尾處找到)

這是原始數據目錄(原生寫的)


Paste_Image.png

能夠看到,整個項目有一些js文件,一堆img文件,一個css文件。未來咱們也要一步步親自實現他們,這個目錄展現了整個項目大概須要些什麼。讓咱們使用webpack構建工做流來管理將來咱們將要寫的代碼吧。

webpack安裝與配置

1.npm

建立一個文件夾,並在文件夾下打開命令行


Paste_Image.png

咱們須要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" }
  • name,version是必須的,也是最重要的,他們表示包的名稱和版本,構成了包的惟一標示。假如咱們只是用npm來管理依賴,他們天然不重要,可是若是咱們在製做一個供他人使用的工具包,便必須正確的書寫他們,以便他人查找和使用。具體的規則請查看以前的網站。
  • description main author license
    這些屬性,僅在須要製做工具包時關注。description author license 顧名思義,main則表示當別人引用(require)你的工具包時,入口文件在哪。
  • scripts則與實際開發過程有關,是咱們會常常用到的。
    經過它,咱們能夠定義npm腳本,好比
    //只看,不用寫後邊須要動手寫,我會說 "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恢復原樣。
    詳情請移步:
    阮一峯——npm scripts使用指南 
    npm-scripts官方文檔(英文)

好吧,其實過高級的並木有卵用,目前,只知道能夠懶省事就行啦(^o^)/~,好比npm run dev,若是每次都打一長串,會瘋的。

2.webpack

是時候安裝webpack了!不過在安裝以前,還要介紹一些概念。

概念——開發與發佈

一個項目一般都會有,開發,發佈這兩種狀態,也就是本身瞎搗鼓,和放網上讓別人用。無論是哪一種狀態,咱們的項目均可能會依賴別人的包。那麼天然而然,由於狀態的不一樣,依賴的包也不太同樣。好比,在開發階段,每每須要進行測試,看看能不能跑通,而測試工具顯然在發佈時是沒必要要的。

爲了分別管理,npm在package.json提供了這樣的字段

  • devDependencies 聲明—僅開發依賴
  • dependencies 依賴包

在下載別人的包時,若是隻指望下載一個發佈的可運行版本,而不但願對此包進行任何開發,能夠利用npm install --production僅下載dependencies字段中的依賴。

好吧,對於咱們的項目並無什麼卵用,由於咱們將使用webpack管理整個工做流程,npm只是用來下載東西(囧),我只是說明一下。

開發與部署

開發到必定階段須要發佈一個版本,咱們每每須要一個文件夾來保存整合後的項目。這個過程,就叫作部署"deploy"。這也是webpack的工做,會用到一個和開發階段不一樣的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`也就能夠運行了。 },

注意,不推薦全局安裝 webpacknpm i webpack g。這會鎖定 webpack 到指定版本,而且在使用不一樣的 webpack 版本的項目中可能會致使構建失敗。

webpack的使命

從上邊目錄圖中也能夠看到,咱們須要用webpack管理不少東西,依賴包,本身寫的jsx,css,各類各樣的圖片,也許還有字體。

爲了性能,咱們須要根據依賴關係,對各類jsx,css,img進行壓縮整合爲數量跟少的幾個文件。
爲了開發方便,咱們須要瀏覽器自動刷新,sass/less自動轉換的功能等等。

這些,就是webpack的使命,讓咱們的開發更高效。

構建目錄

能夠簡單的劃分爲來源——去處,如圖


目錄
  • app文件夾,就全部咱們手寫的文件放的地方
  • 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>

對於部署文件夾來講,通常是這樣


部署
  • dist文件夾,用來保存咱們的發佈版。

因此,最終,在app中寫東西,打包到build中調試、看效果,不錯的話,發佈到dist文件夾裏。

配置webpack

架子已經搭好了,如今,咱們須要控制webpack的各類行爲,添加各類功能。

能夠有三種途徑

  • cli——即命令行形式,通常都會動過package.json中寫入scripts字段的形式
  • 配置文件webpack.config.js文件中寫入字段,webpack在啓動時會讀取它,並依據其工做
  • node api——其實配置文件也算node api,更廣義的來說,node api是一套配置文件的生成系統,根據不一樣的輸入(從cli傳參數--a=b),實現不一樣的配置。

對於第三種,本文不作過多介紹,在文章最後,我會貼出一位前輩的node api模板地址,有興趣的同窗能夠移步文章結尾。

注意:當使用node api同時又使用了webpack.config.js時,webpack.config.js將不會生效

咱們經過配置文件,此時你的目錄應該是這樣(新建文件)


配置文件

由於咱們會往兩個地方打包,那麼天然,得倆配置文件了。

  • webpack.config.js目標build
  • webpack.production.config.js目標dist
    接下來,經過webpack.config.js的配置來詳細介紹配置屬性(到部署時候再說後production配置)

進行以下配置

//動手寫 // 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中文指南——趙達(模塊系統)

一個一個來講

基本配置屬性介紹(一)——entry

1.基本概念
表示模塊的來源,入口,起點。它的值能夠是

  • 字符串 entry: '某模塊' 表示一個單一模塊做爲起點(固然,單一入口也能夠用後邊兩種寫),把這個模塊須要的東西打包成一堆
  • 數組 entry: ['模塊1', '模塊2']
    模塊1與模塊2互相之間並無依賴,可是咱們還想把他們打包在一塊兒,此時就用數組值的方式,webpack從左到右把各個模塊及他們的依賴打包在一塊兒([第一堆,第二堆]),而後從左到右首尾相連的拼接成一個文件。最終也是打包成一堆。
  • 對象
    //只看 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]來生成對應打包堆特殊的名字。
  • 混合使用,不在贅述
    entry的官方文檔

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.pathinfoloader項下的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" } };
基本配置屬性介紹(二)output

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這個服務器工具

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指令(推薦)

  • 配置文件(Node API)
    // 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
讓咱們寫一些具體的東西,測試一下它的效果

  • 首先在app文件夾下新建main.js
    它長這樣
    // 新建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模式,請看:


實時刷新測試

實時刷新測試2.png

可是,難道不能啓動iframe模式了麼?非也,請看


iframe

那麼,咱們並無啓動iframe模式啊?這與上邊的hotOnly那一塊說的一個意思,是咱們手動啓動了服務

咱們能夠關閉默認啓動的inline模式:--no-inline命令


iframe2

可是想要看到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.另外一種可能——緩存

緩存簡述

博主遇到過沒法自動刷新的問題,找不到緣由,次日莫名其妙好了。
當我想要重現錯誤時,它死活不會錯,關因而不是緩存致使,沒有辦法驗證。

咱們都知道瀏覽器會緩存請求的文件,當咱們再次請求時,首先從緩存列表查找,沒有再去請求。這會提升性能。


緩存1.png


很明顯,咱們的bundle.js並非從磁盤緩存中來的(細心的同窗會說,哇,bundle.js爲何那麼大?!這牽扯甚廣,又是一篇文章的量啊)


緩存2


點開bundle.js查看他的http請求頭,cache-control:max-age=0此項用來表示不緩存。

若是緩存,緩存多久?

  • max-age指示客戶機能夠接收生存期不大於指定時間(以秒爲單位)的響應(不超過這個秒數的,都用緩存裏的)
  • Expires表示存在時間,容許客戶端在這個時間以前不去檢查(發請求),等同max-age的
    效果。可是若是同時存在,則被Cache-Control的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模塊用來實現熱替換功能。
兩種方式開啓它:

  • cmd
  • nodeapi

無論咱們用那種方式,只要開啓,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中引用了它。


Paste_Image.png

接下來,必須將webpack.config.js中,output下的publicPath與devServer下的publicPath設置爲同樣

// webpack.config.js ··· output: { ···  publicPath: '/', ··· } ··· devServer: { ···  publicPath: '/', ··· } ···

下面關於兩種配置方式

  • cmd
    --hot
    設置它以後,啓動服務,在瀏覽器能夠看到:


    hot模塊
    • HMR是hot模塊產生
    • WDS是webpack-dev-server模塊產生
  • 配置文件
    Node.js API方式須要作兩個配置:

    • new webpack.HotModuleReplacementPlugin()加入到webpack配置文件的plugins項;
    • hot:true加入到webpack-dev-server的配置項(devServer)裏面。
      兩項都必須加你們能夠自行驗證一下,博主已經一一驗證了。

Paste_Image.png

熱加載nodeapi
  • 關於webpack/hot/only-dev-server前文也介紹了,雖然不加沒錯,可是仍是加上比較好。

  • 在研究熱加載的過程當中,有一些很讓我生氣的事

    下邊的寫法是錯誤的!!!!!!
    webpack/hot/dev-server添加到entry中


    熱加載錯誤.png


    把它改成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;

react熱替換成功!

不少朋友還在使用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庫,也放上來

一些我以爲應該仔細看看的文章:

未完待續,敬請期待

相關文章
相關標籤/搜索