from:https://www.jianshu.com/p/b83a251d53db?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendationjavascript
最近在學習 Webpack,網上大多數入門教程都是基於 Webpack 1.x 版本的,我學習 Webpack 的時候是看了 zhangwang 的 <<入門 Webpack,看這篇就夠了>> 寫的很是好,不過是基於 Webpack 1.x 版本的,語法上和 Webpack 2.x 有一點不一樣.我學習時是使用 Webpack 2.6.1 版本,因此我就尋思着基於 zhangwang 的 <<入門 Webpack,看這篇就夠了>> 寫下這篇 Webpack 2.x 的入門實戰,是我學習 Webpack 的記錄.據說 Webpack 3.x 版本快要出了,不得不感嘆前端領域發展的真是太快了!css
Webpack 是前端資源模塊化管理和打包工具。html
Webpack 能夠將許多鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。前端
Webpack 能夠將按需加載的模塊進行代碼分隔,等到實際須要的時候再異步加載。java
Webpack 經過 loader 的轉換,任何形式的資源均可以視做模塊,好比 CommonJs 模塊、 AMD 模塊、 ES6 模塊、CSS、圖片、 JSON、Coffeescript、 LESS、 SASS 等。node
一圖勝千言,下圖足夠說明上面巴巴拉拉一大堆是啥了!react
對於模塊的組織,一般有以下幾種方法:webpack
在沒有學習 Webpack 以前我對 Webpack、Grunt、Gulp 的認識很模糊,只知道好像這三個東西都是前端自動化工具,都是用來使前端自動化、模塊化、工程化的,這三者是能夠替代彼此的前端工具.git
其實 Webpack 和 Gulp / Grunt 並無太多的可比性,Gulp / Grunt 是一種可以優化前端開發流程的自動化工具,而 Webpack 是一種模塊化的解決方案,不過 Webpack 的優勢使得 Webpack 能夠替代 Gulp / Grunt 一部分工做。github
Grunt / Gulp 的工做方式是:在一個配置文件中,指明對某些文件須要進行哪些處理,例如:編譯、組合、壓縮等任務的具體步驟,Grunt / Gulp 以後能夠自動替你完成這些任務。Grunt / Gulp的工做流程以下圖:
Webpack 的工做方式是:把你的項目當作一個總體,經過一個給定的主文件( 如:index.js ),Webpack 將從這個文件開始找到你的項目的全部依賴文件,使用 loaders 處理它們,最後打包爲一個瀏覽器可識別的 JavaScript 文件。Webpack工做方式以下圖:
若是實在要進行比較,Webpack 的處理速度更快更直接,由於 Webpack 的歷史包袱小.Webpack 還能打包更多不一樣類型的文件。
初步瞭解 Webpack 後,就能夠開始學習使用 Webpack。這裏會以一個小的 Demo 爲例子來一步一步進行動手學習!
1. 新建一個文件夾,命名爲 webpack-demo,webpack-demo 就是你的項目名,項目名建議使用小寫字母,而且不帶空格,不能含有大寫字母.
2. 安裝 Webpack,Webpack 可使用 npm 安裝,若是你還不知道 npm 爲什麼物,請 Google,也能夠參考 Node.js 安裝配置和 NPM 使用介紹快速瞭解、安裝 npm.
使用終端在該文件夾中執行下述指令就能夠完成安裝,因爲網絡緣由安裝過程可能須要一些時間。
//全局安裝 npm install -g webpack //安裝到你的項目目錄 npm install --save-dev webpack
Webpack 能夠全局安裝,也能夠安裝到你的項目目錄.剛開始學習 Webpack 爲了方便,建議同時全局安裝和安裝到你的項目目錄.
3. 在 webpack-demo 文件夾中建立一個 package.json 文件,這是一個標準的 npm 說明文件,裏面蘊含了豐富的信息,包括當前項目的依賴模塊,自定義的腳本任務等等。在終端中使用 npm init 命令能夠自動建立這個 package.json 文件.
npm init
輸入這個命令後,終端會問你一系列諸如項目名稱,項目版本,項目描述,入口文件,做者等信息,不過不用擔憂,若是你不許備在 npm 中發佈你的模塊,這些問題的答案都不重要,回車默認便可.這些信息從此均可以更改 package.json 來修改,因此不用擔憂.
4. 在 webpack-demo 文件夾中建立兩個文件夾 app 文件夾和 public 文件夾, app 文件夾用來存放原始數據,例如: SASS 文件、LESS 文件、JavaScript 模塊等,public 文件夾用來存放通過 Webpack 處理過的 app 文件夾數據,這也是準備給瀏覽器讀取的數據,其中包括使用 Webpack 打包後的 js 文件等。在這裏還須要在 public 文件夾中建立 index.html 文件.在 app 文件夾中建立 Greeter.js 和 main.js 文件,此時項目結構以下圖所示:
5. 在 public 文件夾中的 index.html 文件只有最基礎的 html 代碼,它惟一的目的就是加載打包後的 js 文件 bundle.js.
// index.html
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>webpack-demo</title> </head> <body> <div id='root'> </div> <script type="text/javascript" src="bundle.js"></script> </body> </html>
6. 在 app 文件夾中的 Greeter.js 只包括一個用來返回問候信息的 html 元素的函數。
// Greeter.js module.exports = function() { var greet = document.createElement('div'); greet.textContent = "Hi there and greetings!"; return greet; }
7. 在 app 文件夾中的 main.js 用來把 Greeter 模塊(其實能夠簡單的把它看做 Greeter.js)返回的節點插入頁面。
// main.js var greeting = require('./Greeter.js'); document.getElementById('root').appendChild(greeting());
Webpack 配置文件其實也是一個簡單的 JavaScript 模塊,能夠把全部與項目構建相關的信息放在裏面。在 webpack-demo 文件夾根目錄下新建一個名爲 webpack.config.js 的文件,並在其中進行最簡單的配置.以下所示,它包含入口文件路徑和存放打包後文件的地方路徑。
// webpack.config.js module.exports = { entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 } }
注:__dirname 是 node.js 中的一個全局變量,它指向當前 js 文件所在的目錄.
如今只須要在終端裏運行 webpack 命令就能夠了,這條命令會自動參考 webpack.config.js 文件中的配置選項打包你的項目,輸出結果以下:
此時項目的 public 文件夾下也會出現打包好的 bundle.js 文件.此時項目結構以下圖所示:
能夠看出 webpack 同時編譯了 main.js 和 Greeter.js,打開 public 目錄下的 index.html 文件,就能夠看到最終效果,以下圖:
經過 Webpack 配置文件和執行 webpack 命令實際上是比較煩人且容易出錯的,不過值得慶幸的是 npm 能夠引導任務執行,對其進行配置後可使用簡單的 npm start 命令來代替這些繁瑣的命令。在 package.json 中對 npm 的腳本部分進行相關設置,至關於把 npm 的 start 命令指向 webpack 命令,設置方法以下:
// package.json { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { "start": "webpack" }, "author": "", "license": "ISC" }
執行 npm start 後命令行的輸出顯示:
如今只須要使用 npm start 就能夠打包文件了.打開 public 目錄下的 index.html 文件,看到的最終效果是否是與以前的同樣.
簡單說,Source Maps 就是一個信息文件,裏面儲存着位置信息。也就是說,轉換後的代碼的每個位置,所對應的轉換前的位置.有了它,出錯的時候,除錯工具將直接顯示原始代碼,而不是轉換後的代碼。這無疑給開發者帶來了很大方便.爲了方便調試能夠利用 Webpack 生成 Source Maps.
在 Webpack 的配置文件中配置 Source Maps,須要配置 devtool,它有如下四種不一樣的配置選項,各有優缺點,描述以下:
上述選項由上到下打包速度愈來愈快,不過同時也具備愈來愈多的負面做用,較快的構建速度的後果就是對打包的文件執行有必定影響。在學習階段以及在小到中型的項目上,eval-source-map是一個很好的選項,不過記得只在開發階段使用它.
編輯 webpack-demo 文件夾下的 webpack.config.js 文件配置 devtool 選項,生成 Source Maps 文件.配置 devtool 後的 webpack.config.js 文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 } }
執行 npm start 命令後就能生成對應的 Source Maps,終端輸出信息以下圖:
此時項目中 public 文件夾下也生成了名爲 bundle.js.map 的 Source Maps 文件.此時項目結構以下圖所示:
想不想讓你的瀏覽器監測你修改的代碼,並自動刷新修改後的結果.其實 Webpack 提供一個可選的本地開發服務器,這個本地服務器基於 node.js 構建,能夠實現你想要的這些功能,不過它是一個單獨的組件,在 Webpack 中進行配置以前須要單獨安裝它做爲項目依賴.在終端中輸入下面的指令安裝對應組件.建議同時全局安裝和安裝到你的項目目錄.
//全局安裝 npm install -g webpack-dev-server //安裝到你的項目目錄 npm install --save-dev webpack-dev-server
devserver 做爲 Webpack 配置選項中的一項,具備如下配置選項
編輯 webpack-demo 文件夾下的 webpack.config.js 文件配置以上選項.
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, } }
在終端中輸入以下命令,構建本地服務器:
webpack-dev-server
終端輸出信息以下圖,表示 Webpack 構建的本地服務器已啓動.
在瀏覽器中打開 http://localhost:9000/ 就能夠看到像以前同樣的問候語頁面.
也可使用 npm 更快捷的執行任務,編輯 webpack-demo 文件夾下的 package.json 文件 scripts 選項.
// package.json { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { "start": "webpack", "dev": "webpack-dev-server --devtool eval --progress --content-base build" }, "author": "", "license": "ISC" }
在終端中執行 npm run dev 命令,輸出信息以下圖,同樣能夠啓動的本地服務器.
按 Ctrl + C 便可退出本地服務器.
Webpack 有一個不可不說的優勢,它把全部的文件均可以當作模塊處理,包括你的 JavaScript 代碼,也包括 CSS 和 fonts 以及圖片等等,只要經過合適的 Loaders,它們均可以被當作模塊被處理.
webpack 可使用 loader 來預處理文件。這容許你打包除 JavaScript 以外的任何靜態資源.經過使用不一樣的 loader,Webpack 經過調用外部的腳本或工具能夠對任何靜態資源進行處理,好比說分析 JSON 文件並把它轉換爲 JavaScript 文件,或者說把 ES6 / ES7 的 JS 文件轉換爲現代瀏覽器能夠識別的 JS 文件.對 React 開發而言,合適的 Loaders 能夠把 React 的 JSX 文件轉換爲 JS 文件.
Loaders 須要單獨安裝而且須要 在webpack.config.js 下的 modules 關鍵字下進行配置,Loaders 的配置選項包括如下幾方面:
繼續動手實踐,修改 app 文件夾下的 Greeter.js 文件,把問候消息放在一個單獨的 JSON 文件裏,經過 loader 的使 Greeter.js 能夠讀取該 JSON 文件.
1. 在 app 文件夾下建立 config.json 文件,並輸入以下代碼:
//config.json { "greetText": "Hi there and greetings from JSON!" }
2. 編輯 app 文件夾下的 Greeter.js 文件,修改後以下:
// Greeter.js var config = require('./config.json'); module.exports = function() { var greet = document.createElement('div'); greet.textContent = config.greetText; return greet; }
3. 安裝支持導入 JSON 文件的 json-loader .因爲 webpack 2.× 默認支持導入 JSON 文件.若是你使用自定義文件擴展名,可能仍然須要使用此 loader.在終端中運行以下命令,安裝 json-loader 到你的項目中.
//安裝到你的項目中 npm install --save-dev json-loader
由於 json-loader 安裝到你的項目目錄裏了,因此 webpack-demo 項目下會新增一個 node_modules 文件夾用於存放安裝的 json-loader.此時的項目結構以下:
4. 編輯 webpack.config.js 文件配置 modules 選項,添加 json-loader,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }] } }
在終端中輸入 npm start 從新編譯打包,再在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明 json-loader 配置成功了.
Babel 實際上是一個編譯 JavaScript 的平臺,它的強大之處表如今能夠經過編譯幫你達到如下目的:
Babel 實際上是幾個模塊化的包,其核心功能位於稱爲 babel-core 的 npm 包中,不過 Webpack 把它們整合在一塊兒使用,可是對於每個你須要的功能或拓展,你都須要安裝單獨的包.用得最多的是解析 ES6 的 babel-preset-es2015 包和解析 JSX 的 babel-preset-react 包.
先來安裝這些依賴包,輸入以下命令,把這些依賴包安裝到你的項目中.
// 利用 npm 一次性安裝多個依賴模塊,模塊之間用空格隔開 npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react //安裝 React 和 React-DOM npm install --save react react-dom
編輯 webpack.config.js 文件配置 modules 選項,添加 Babel 配置,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader", query: { presets: ['es2015', 'react'] } }] } }
使用 ES6 的語法,更新 app 文件夾下的 Greeter.js 文件,並返回一個 React 組件,修改後的代碼以下:
// Greeter.js import React, { Component } from 'react'; import config from './config.json'; class Greeter extends Component { render() { return (<div> { config.greetText } </div>); } } export default Greeter;
使用 ES6 的模塊定義和渲染 Greeter 模塊,修改 app 文件夾下的 main.js 文件,修改後的代碼以下:
// main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; render(<Greeter />, document.getElementById('root'));
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經成功配置了 Babel.
Babel 其實能夠徹底在 webpack.config.js 文件中進行配置,可是考慮到 babel 具備很是多的配置選項,在單一的 webpack.config.js 文件中進行配置每每使得這個文件顯得太複雜,所以一些開發者支持把 babel 的配置選項放在一個單獨的名爲 ".babelrc" 的配置文件中。咱們如今的 babel 的配置並不算複雜,不過以後咱們會再加一些東西,所以如今咱們就提取出相關部分,分兩個配置文件進行配置, Webpack 會自動調用 .babelrc 裏的 babel 配置選項.
編輯 webpack.config.js 文件配置 modules 選項,添加 Babel 配置,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }] } }
在 webpack-demo 文件夾下新建 .babelrc 文件,添加以下代碼:
// .babelrc { "presets": ['es2015', 'react'] }
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經成功配置了 Babel.
Webpack 提供兩個工具處理樣式表,css-loader 和 style-loader.
兩者組合在一塊兒使你可以把樣式表嵌入 Webpack 打包後的 JS 文件中。
先來安裝 css-loader, style-loader,輸入以下命令,把這些依賴包安裝到你的項目中.
npm install --save-dev style-loader css-loader
編輯 webpack.config.js 文件配置 modules 選項,添加處理樣式表配置,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader' //添加對樣式表的處理,感嘆號的做用在於使同一文件可以使用不一樣類型的 loader }] } }
接下來,在 app 文件夾裏建立一個名爲 main.css 的文件,在文件中添加以下代碼,對一些元素設置樣式.
// main.css html { box-sizing: border-box; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } *, *:before, *:after { box-sizing: inherit; } body { margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } h1, h2, h3, h4, h5, h6, p, ul { margin: 0; padding: 0; }
Webpack 只有單一的入口,其它的模塊須要經過 import, require, url 等導入相關位置,爲了讓 Webpack 能找到 main.css 文件,咱們把它導入 app 文件夾下的 main.js 中.修改 app 文件夾下的 main.js 文件,修改後的代碼以下:
// main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; import './main.css'; //導入css文件 render(<Greeter/>, document.getElementById('root'));
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經配置成功了.
一般狀況下,css 會和 js 打包到同一個文件中,並不會打包爲一個單獨的 css 文件,不過經過合適的配置 Webpack 也能夠把 css 打包爲單獨的文件的。
不過這也只是 Webpack 把 css 當作模塊而已,繼續看一個真的 CSS 模塊的實踐.
在過去的一些年裏,JavaScript 經過一些新的語言特性、更好的工具、更好的實踐方法(好比說模塊化)發展得很是迅速。模塊使得開發者把複雜的代碼轉化爲小的、乾淨的、依賴聲明明確的單元,且基於優化工具,依賴管理和加載管理能夠自動完成。
不過前端的另一部分,CSS 的發展就相對慢一些,大多的樣式表卻依舊是巨大且充滿了全局類名,這使得維護和修改都很是困難和複雜。
CSS modules 的技術就可以把 JS 的模塊化思想帶入 CSS 中來,經過 CSS 模塊,全部的類名,動畫名默認都只做用於當前模塊.
Webpack 從一開始就對 CSS 模塊化提供了支持,在 CSS loader 中進行配置後,你所須要作的一切就是把 modules 傳遞到須要的地方,而後就能夠直接把 CSS 的類名傳遞到組件的代碼中,且這樣作只對當前組件有效,沒必要擔憂在不一樣的模塊中具備相同的類名可能會形成的問題。
編輯 webpack.config.js 文件配置 modules 選項,添加處理樣式表配置,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules' //跟前面相比就在後面加上了 ?modules }] } }
接下來,在 app 文件夾裏建立一個名爲 Greeter.css 的文件,在文件中添加以下代碼,對一些元素設置樣式.
// Greeter.css .root { background-color: #eee; padding: 10px; border: 3px solid #ccc; }
導入 .root 到 Greeter.js 中,修改 app 文件夾下的 Greeter.js 文件,修改後的代碼以下:
// Greeter.js import React, { Component } from 'react'; import config from './config.json'; import styles from './Greeter.css'; //導入 .root 到 Greeter.js 中 class Greeter extends Component { render() { return ( <div className={styles.root}> { config.greetText } </div>); } } export default Greeter;
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經配置成功了.
CSS modules 也是一個很大的主題,有興趣的話能夠去官方文檔查看更多消息.下面兩篇文章也能夠看看:
CSS 預處理器能夠將 SASS、LESS 文件轉化爲瀏覽器可識別的 CSS 文件,如下是經常使用的CSS 預處理器 loaders.
其實也存在一個 CSS 的處理平臺 PostCSS,它能夠幫助你的 CSS 實現更多的功能,能夠看看<<PostCSS 是個什麼鬼東西?>>.
舉例來講如何使用 PostCSS,咱們使用 PostCSS 來爲 CSS 代碼自動添加適應不一樣瀏覽器,不一樣版本的 CSS 前綴。首先安裝 postcss-loader 和 autoprefixer(自動添加前綴的插件),安裝到你的項目中.
npm install --save-dev postcss-loader autoprefixer
編輯 webpack.config.js 文件配置 modules 選項,添加 postcss-loader 處理樣式表配置,編輯後的文件以下:
// webpack.config.js module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在後面加上了 !postcss-loader }] } }
在 webpack-demo 文件夾下新建 postcss.config.js 文件,添加以下代碼:
// postcss.config.js module.exports = { plugins: [ //調用autoprefixer插件,還能夠配置選項添加須要兼容的瀏覽器版本. require("autoprefixer")({ browsers: ['ie>=8', '>1% in CN'] }) ] }
如今你寫的樣式會自動根據 Can i use 裏的數據添加不一樣前綴了.在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經成功配置了 PostCSS.
插件(Plugins)是用來拓展 Webpack 功能的,它會在整個構建過程當中生效,執行相關的任務。
Loaders 和 Plugins 經常被弄混,可是他們實際上是徹底不一樣的東西,能夠這麼說,Loaders 是在打包構建過程當中用來處理源文件的(JSX,Scss,Less..),一次處理一個;插件並不直接操做單個文件,它直接對整個構建過程其做用。
Webpack 有不少內置插件,同時也有不少第三方插件,可讓咱們完成更加豐富的功能。
要使用某個插件,咱們須要經過 npm 安裝它,而後要作的就是在 Webpack 配置中的 Plugins 關鍵字部分添加該插件的一個實例.
編輯 webpack.config.js 文件配置 Plugins 選項,添加一個實現版權聲明的 BannerPlugin 插件,BannerPlugin 是內置插件不須要使用 npm 安裝.編輯後的文件以下:
// webpack.config.js var webpack = require("webpack"); module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/public/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在後面加上了 !postcss-loader }] }, plugins: [ new webpack.BannerPlugin("Copyright Flying Unicorns inc.")//在這個數組中new一個實例就能夠了 ] }
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
在瀏覽器中打開 public 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經成功配置了 BannerPlugin 插件.
給你們推薦幾個經常使用的插件
這個插件的做用是依據一個簡單的模板,幫你生成最終的 html 文件,這個文件中自動引用了你打包後的 JS 文件。每次編譯都在文件名中插入一個不一樣的哈希值。
npm install --save-dev html-webpack-plugin
在使用 HtmlWebpackPlugin 以前,須要對 webpack-demo 項目結構作一些改變.
1. 移除 public 文件夾.
2. 在 app 目錄下,建立一個文件名爲 index.tmpl.html 模板文件,在編譯過程當中,HtmlWebpackPlugin 插件會依據此模板生成最終的 html 頁面,會自動添加所依賴的 css、 js、favicon等文件.index.tmpl.html 模板文件代碼以下:
// index.tmpl.html
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>webpack-demo</title> </head> <body> <div id="root"></div> </body> </html>
3. 在 webpack-demo 文件夾下新建一個 build 文件夾用來存放最終的輸出文件.
4. 編輯 webpack.config.js 文件配置 Plugins 選項,添加 HtmlWebpackPlugin 插件,修改 output 選項.編輯後的文件以下:
// webpack.config.js var webpack = require("webpack"); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/build/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { contentBase: "./public", port: "9000", inline: true, historyApiFallback: true, }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在後面加上了 !postcss-loader }] }, plugins: [ new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在這個數組中new一個實例就能夠了 new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html" //new一個插件的實例,並傳入相關的參數 }) ] }
此時項目結構以下圖所示:
在終端中運行 npm start 命令從新編譯打包,終端輸出信息以下:
此時項目結構已經發生改變,build 文件夾下存放了最終的輸出的文件,項目結構以下圖所示:
在瀏覽器中打開 build 文件夾下的 index.html 文件,若是看到和下圖同樣的,就說明已經成功配置了 HtmlWebpackPlugin 插件.
Hot Module Replacement(HMR)也是 Webpack 裏頗有用的一個插件,它容許你在修改組件代碼後,自動刷新實時預覽修改後的效果。
在 Webpack 中使用 HMR 也很簡單,只須要作兩項配置.
不過配置完這些後,JS 模塊其實仍是不能自動熱加載的,還須要在你的 JS 模塊中執行一個 Webpack 提供的 API 才能實現熱加載,雖然這個 API 不難使用,可是若是是 React 模塊,使用咱們已經熟悉的 Babel 能夠更方便的實現功能熱加載。
整理下思路,具體實現方法以下
編輯 webpack.config.js 文件配置 Plugins / devServer 選項,添加 Hot Module Replacement 插件.編輯後的文件以下:
// webpack.config.js var webpack = require("webpack"); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/build/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { port: "9000", inline: true, historyApiFallback: true, hot: true }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在後面加上了 !postcss-loader }] }, plugins: [ new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在這個數組中new一個實例就能夠了 new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html" //new一個插件的實例,並傳入相關的參數 }), new webpack.HotModuleReplacementPlugin() //熱加載插件 ] }
安裝 react-transform-hmr 插件
npm install --save-dev babel-plugin-react-transform react-transform-hmr
編輯在 webpack-demo 文件夾下的 .babelrc 文件,編輯後的文件以下:
// .babelrc { "presets": ["react", "es2015"], "env": { "development": { "plugins": [["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }]] } } }
編輯 webpack-demo 文件夾下的 package.json 文件 scripts 選項,添加 --hot 選項開啓代碼熱替換.
// package.json { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { "start": "webpack", "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot" }, "author": "", "license": "ISC" }
在終端中執行 npm run dev 命令,輸出信息以下圖,同樣能夠啓動自動熱加載.
在瀏覽器中打開 http://localhost:9000/ 就能夠看到像以前同樣的問候語頁面.
如今當你使用 React 時,就能夠熱加載模塊了.按 Ctrl + C 便可退出自動熱加載.
咱們已經使用 Webpack 構建了一個完整的開發環境.可是在產品階段,可能還須要對打包的文件進行額外的處理,好比說優化、壓縮、緩存以及分離 CSS 和 JS.
對於複雜的項目來講,須要複雜的配置,這時候分解配置文件爲多個小的文件可使得事情層次分明,以 webpack-demo 項目來講,咱們在 webpack-demo 文件夾下建立一個名爲 webpack.production.config.js 的文件,在裏面加上基本的配置代碼,以下:
// webpack.production.config.js var webpack = require("webpack"); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/build/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在後面加上了 !postcss-loader }] }, plugins: [ new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html" //new一個插件的實例,並傳入相關的參數 }) ] }
編輯 webpack-demo 文件夾下的 package.json 文件 scripts 選項,添加 build 選項,編輯後的文件以下:
// package.json { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { "start": "webpack", "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot", "build": "webpack --config ./webpack.production.config.js --progress" }, "author": "", "license": "ISC" }
在終端中執行 npm run build 命令,輸出信息以下圖:
說明分解配置文件爲多個小的文件成功了.
Webpack 提供了一些在發佈階段很是有用的優化插件,它們大多來自於 Webpack 社區,能夠經過 npm 安裝,經過如下插件能夠完成產品發佈階段所需的功能.
咱們來看看如何使用它們,OccurrenceOrderPlugin 和 UglifyJS plugins 都是內置插件,咱們只須要安裝 ExtractTextPlugin 插件.
安裝 ExtractTextPlugin 插件
npm install --save-dev extract-text-webpack-plugin
編輯 webpack.config.js 文件配置 Plugins 選項,添加這三個插件,由於要分離 css 因此還要配置 module 下的 loaders 選項.編輯後的文件以下:
// webpack.config.js var webpack = require("webpack"); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/build/", //存放打包後文件的地方路徑 filename: "bundle.js" //打包後的文件名 }, devServer: { port: "9000", inline: true, historyApiFallback: true, hot: true }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader?modules!postcss-loader" }) }] }, plugins: [ new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在這個數組中new一個實例就能夠了 new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html" //new一個插件的實例,並傳入相關的參數 }), new webpack.HotModuleReplacementPlugin(), //熱加載插件 new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin(), new ExtractTextPlugin("style.css") ] }
在終端中執行 npm start 命令,輸出信息以下圖:
此時項目結構已經發生改變,build 文件夾下多出了抽離出來的 style.css 文件還有對應的 style.css.map 文件,項目結構以下圖所示:
若是你打開 build 文件夾下的 bundle.js 文件,就能夠看到 bundle.js 文件內容已經被壓縮處理了.
說明這三個插件已經配置成功了.
爲了加快加載速度,合理的利用緩存是必不可少的.使用緩存的最好方法是保證文件名和文件內容是匹配的.內容改變,名稱也相應改變.
Webpack 能夠把一個哈希值添加到打包文件的文件名中,添加特殊的字符串混合體([name], [id] and [hash])到輸出文件名前,便於修改 BUG 之後,對應更新用戶本地的緩存文件.
編輯 webpack.config.js 文件修改 output / plugins 選項.編輯後的文件以下:
// webpack.config.js var webpack = require("webpack"); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool: "source-map", //配置生成 Source Maps 的選項 entry: __dirname + "/app/main.js", //入口文件路徑 output: { path: __dirname + "/build/", //存放打包後文件的地方路徑 filename: "[name]-[hash].js" //打包後的文件名 }, devServer: { port: "9000", inline: true, historyApiFallback: true, hot: true }, module: { loaders: [{ test: /\.json$/, loader: "json-loader" }, { test: /\.js$/, exclude: /node_modules/, //編譯打包時須要排除 node_modules 文件夾 loader: "babel-loader" }, { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader?modules!postcss-loader" }) }] }, plugins: [ new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在這個數組中new一個實例就能夠了 new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html" //new一個插件的實例,並傳入相關的參數 }), new webpack.HotModuleReplacementPlugin(), //熱加載插件 new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin(), new ExtractTextPlugin("[name]-[hash].css") ] }
在終端中執行 npm start 命令,輸出信息以下圖:
此時項目 build 文件夾下的 main.css 和 main.js 文件都對應的加上了哈希值.項目結構以下圖所示:
若是你打開 build 文件夾下的 index.html 文件,就能夠看到引用的 css、js 文件名也對應發生了改變,這樣修改 BUG 之後,也能對應更新用戶本地的緩存文件.
其實到這裏個人這篇 Webpack 2.x 的入門實戰已經完結了!但這也只是個入門而已!在實際項目中運用仍是不夠的,還有不少細節我並沒深刻講,因此你們還想進階的話建議好好去看看 webpack-china 的文檔.
另外實戰項目 webpack-demo 的源碼,我已經放到 Github 上去了,歡迎你們提意見.
還有一點我以爲很重要,要學會看控制檯輸出信息,可以看控制檯輸出信息解決的問題,就不要上 Google 搜了!
這篇 Webpack 2.x 的入門實戰是基於 zhangwang 的 <<入門Webpack,看這篇就夠了>> 寫出來的,是我學習 Webpack 的實戰記錄.特別感謝 zhangwang 付出,若是你以爲這篇文章對你有幫助,請轉到 zhangwang 爲他點個贊.