[TOC]
## 前言
webpack作為當下最流行的前端打包工具,如果你對它還一無所知,那就可能找不到一份好的工作?其實我們學習或者不學習不僅僅因為某個公司是否在用這個框架,更要因為使用這個框架具有什么特點,能幫我們解決什么問題,會帶來其他什么問題,使用成本如何,難度如何,可拓展性如何。
## 使用場景
在前端生態日益完善的今天,各種針對前端工程化提出的解決方案層出不窮,這些方案一般都能大幅度的提高或者改善我們的開發過程,但是卻可能不能直接用于生產環境使用,這些方案可能有:
* js模塊化,針對工具性質的、ui性質的組件模塊化開發
* es6或者typescript語言編寫的程序
* 樣式預處理器比如less sass編寫的樣式
* html模板引擎比如jade等
綜上:這些開發階段使用的技術產物不能直接用于生產環境部署使用,我們手動去操作這些又過于繁瑣,所以提出來webpack這一個工具,可以實現將一切資源進行配置化打包的思想,來簡化我們的工作。
## 是什么,與其他工具什么區別
* 概念理解
WebPack可以看做是模塊打包機:它做的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),并將其轉換和打包為合適的格式供瀏覽器使用。換句話說,它將根據模塊的依賴關系進行靜態分析,然后將這些模塊按照指定的規則生成對應的靜態資源。
* 圖解webpack以及與其他框架的對比

* 表格說明
| 名稱 | 類型 | 特點描述 |
| --- | --- | --- |
| grunt | 前端流程工具 | 基于配置,較繁瑣 ,需要不斷的修改配置文件,入手難度大 |
| gulp | 前端流程工具| 基于管道,基于stream,非常快,更加便利,可以靈活的把若干插件配置到管道任務中 |
| browserify | 預編譯模塊化方案 | |
| seajs/requirejs | 在線模塊化方案 | 通過引入,在線把你的文件進行模塊化,不同的只是兩個的模塊規范不同 |
| webpack | 預編譯模塊化方案 | 更加智能化 , |
* 工作流程區別


* [與其他工具的區別](https://survivejs.com/webpack/appendices/comparison/)(如果你外語水平有限,建議chrome打開,然后右鍵翻譯為中文)
* 優點
> **代碼拆分**
Webpack 有兩種組織模塊依賴的方式,同步和異步。異步依賴作為分割點,形成一個新的快。在優化了依賴樹后,每一個異步區塊都作為一個文件被打包。
**Loader**
Webpack 本身只能處理原生的 JavaScript 模塊,但是 loader 轉換器可以將各種類型的資源轉換成 JavaScript 模塊。這樣,任何資源都可以成為 Webpack 可以處理的模塊。
**智能解析**
Webpack 有一個智能解析器,幾乎可以處理任何第三方庫,無論它們的模塊形式是 CommonJS、 AMD 還是普通的 JS 文件。甚至在加載依賴的時候,允許使用動態表達式 require("./templates/" + name + ".jade")。
**插件系統**
Webpack 還有一個功能豐富的插件系統。大多數內容功能都是基于這個插件系統運行的,還可以開發和使用開源的 Webpack 插件,來滿足各式各樣的需求。
**快速運行**
Webpack 使用異步 I/O 和多級緩存提高運行效率,這使得 Webpack 能夠以令人難以置信的速度快速增量編譯。
## 能解決什么問題
webpack簡單點來說就就是一個配置文件,所有的魔力都是在這一個文件中發生的。 這個配置文件主要分為三大塊:
> entry 入口文件 讓webpack用哪個文件作為項目的入口,所有的項目主要通用依賴通過這個文件作為入口,其他跳轉的頁面依賴的資源在單獨的組件中去加載。
> output 出口 讓webpack把處理完成的文件放在哪里
>module 模塊 要用什么不同的模塊來處理各種類型的文件
## 如何使用
### 準備工作
* 安裝webpack
~~~
//全局安裝
npm install -g webpack
//安裝到你的項目目錄
npm install --save-dev webpack
~~~
* 項目初始化
~~~
//填寫基本的項目信息,會生成一個package.json的文件,如果有這個文件忽略
cnpm init
// webpack安裝到包依賴之中,可以安裝穩定版本的,webpack@1.12.x
npm install --save-dev webpack
~~~
* 項目結構
建立兩個文件夾,app以及public,app文件夾用來存放原始數據和我們將寫的JavaScript模塊,public文件夾用來存放之后供瀏覽器讀取的文件(包括使用webpack打包生成的js文件以及一個index.html文件)。接下來我們再創建三個文件:index.html --放在public文件夾中;module.js-- 放在app文件夾中;main.js-- 放在app文件夾中;
此時的項目結構如圖所示:

* 初始化一些文件內容
1.我們在index.html文件中寫入最基礎的html代碼,它在這里目的在于引入打包后的js文件(這里我們先把之后打包后的js文件命名為bundle.js,之后我們還會詳細講述)。
~~~
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack demo文件</title>
</head>
<body>
<div id='app'>
</div>
<script src="bundle.js"></script>
</body>
</html>
~~~
2.在module.js中定義一個返回包含問候信息的html元素的函數,并依據CommonJS規范導出這個函數為一個模塊:語法中我們可以充分利用es6的常量,模塊,模板字符串,解構等語法,非常方便。(創建文件可以用`pico filename`)
~~~javascript
// module.js
const HELLO="Hello word!";
var hello= function(name) {
var greet = document.createElement('h1');
greet.textContent =`HELLO${HELLO}`;
return greet;
}
module.exports = {
hello
}
~~~
3.main.js文件中我們寫入下述代碼,用以把module模塊返回的節點插入頁面。
~~~
const {hello}=require("./module");
document.querySelector("#app").appendChild(hello('zhangsan'));
~~~
* 終端使用webpack模塊
備注:無論哪種環境中,文件路徑是必備的常識,如果你不太清楚絕對路徑,相對路徑,根路徑請參考我另外一篇技術文檔,點擊跳轉。
~~~
# {extry file}出填寫入口文件的路徑,本文中就是上述main.js的路徑,
# {destination for bundled file}處填寫打包文件的存放路徑
# 填寫路徑的時候不用添加{},建議在項目根目錄下的文件地址最前面不用加任何路徑
webpack {entry file} {destination for bundled file}
webpack 'app/main.js' 'public/bundle.js'
~~~
編譯成功后查看頁面,已經生效并打包到了對應文件中。從這個結果中可以看到,webpack只能適用于將某些資源打包為一個模塊,用于一個頁面中,如果你想批量操作打包或者引入文件,還是需要gulp輔助。(在打包成功的報文中,我們可以看到,Webpack 會分析入口文件,解析包含依賴關系的各個文件。這些文件(模塊)都打包到 bundle.js 。Webpack 會給每個模塊分配一個唯一的 id 并通過這個 id 索引和訪問模塊。在頁面啟動時,會先執行 entry.js 中的代碼,其它模塊會在運行 require 的時候再執行。)


* 使用配置文件進行打包
雖然可以使用終端工具以及對應的模塊可以進行很多操作,但為了方便管理,我們還是把這部分操作放在了文件中,比如loader,plugin等。在當前練習文件夾的根目錄下新建一個名為webpack.config.js的文件,我們在其中寫入如下所示的簡單配置代碼,目前的配置主要涉及到的內容是入口文件路徑和打包后文件的存放路徑。
~~~
//注:“__dirname”是node.js中的一個全局變量,它指向當前執行腳本所在的目錄。
module.exports = {
entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后輸出文件的文件名
}
}
~~~
有了這個配置之后,再打包文件,只需在終端里運行webpack命令就可以了,這條命令會自動引用webpack.config.js文件中的配置選項,省略了若干的參數。
進一步簡化:你可以通過修改package.json文件中的scripts來把一些常用命令放到npm命令中,比如寫入`"start":"webpack"`就可以通過npm start就實現webpack打包。
* 拓展閱讀
scripts屬性可以自定義很多你想要的任務,其中start是比較特殊的,定義之后直接運行npm start,其他的則需要通過`npm run task`,如果你不清楚有哪些可執行命令,可以通過`npm run` 得到所有的可執行命令列表:

### 正式使用強大功能
#### 生成Source Maps(使調試更容易)
通過簡單的配置,webpack就可以在打包時為我們生成的source maps,這為我們提供了一種對應編譯文件和源文件的方法,使得編譯后的代碼可讀性更高,也更容易調試。
在webpack的配置文件中配置source maps,需要配置devtool,它有以下四種不同的配置選項,各具優缺點,描述如下:
| devtool選項 | 配置結果 |
| --- | --- |
| source-map | 在一個單獨的文件中產生一個完整且功能完全的文件。這個文件具有最好的<code>source map</code>,但是它會減慢打包速度 |
| cheap-module-source-map | 在一個單獨的文件中生成一個不帶列映射的<code>map</code>,不帶列映射提高了打包速度,但是也使得瀏覽器開發者工具只能對應到具體的行,不能對應到具體的列(符號),會對調試造成不便; |
| eval-source-map | 使用<code>eval</code>打包源文件模塊,在同一個文件中生成干凈的完整的<code>source map</code>。這個選項可以在不影響構建速度的前提下生成完整的<code>sourcemap</code>,但是對打包后輸出的JS文件的執行具有性能和安全的隱患。在開發階段這是一個非常好的選項,在生產階段則一定不要啟用這個選項; |
| cheap-module-eval-source-map |這是在打包文件時最快的生成<code>source map</code>的方法,生成的<code>Source Map</code> 會和打包后的<code>JavaScript</code>文件同行顯示,沒有列映射,和<code>eval-source-map</code>選項具有相似的缺點; |
> 以上文件從上到下,打包越來越快,中小項目我們一般使用eval-source-map,大型項目為了降低成本,我們可以使用cheap-module-eval-source-map。對應的配置寫法:`devtool: 'eval-source-map',`加了這個配置之后就可以看到你開發的源文件,找到其代碼,不加的話是看不到原開發代碼文件,只有壓縮文件顯示的。
> `module.exports = { devtool: 'eval-source-map'}`

#### 使用webpack作為本地服務器
* 基本使用
瀏覽器監聽你的代碼的修改,并自動刷新顯示修改后的結果,使用并配置webpack-dev-server即可。需要將它加入到項目依賴。點擊查看[官網配置說明](https://webpack.js.org/configuration/dev-server/)。
這里只說明比較重要的幾個配置,port:8080,訪問端口,默認為8080,如果你同時開發兩個應用,端口要修改其中一個。
~~~
// 終端安裝模塊
cnpm i webpack-dev-server
//webpack中配置dev-server
devServer: {
contentBase: "./public",//本地服務器所加載的頁面所在的目錄
historyApiFallback: true,//不跳轉
inline: true//實時刷新
}
//package.json中配置啟動腳本
"server":"webpack-dev-server --open"
// 啟動服務器
cnpm run server
~~~
* 可能遇到的問題:
1.開啟錯誤 提示地址解析錯誤`getaddrinfo ENOTFOUND localhost`。解決辦法:設置host文件`127.0.0.1 localhost`的映射
2.如果你不想每次啟動都打開一個窗口,設置:`open:false`,否則設置true則默認打開
3.希望時時更新展示 inline:true ,那么更新內容后會時時更新頁面部分得到打包后的結果
#### 使用babel轉化
babel的用途:可以使用最新的js語言版本;可以支持js拓展之后的語言比如jsx。(潛在的原因是因為瀏覽器不支持部分es6的語法,需要通過babel把它轉化為es5,如果不用原來的es6語法就會保留,舊版瀏覽器不支持就會出現報錯)。babel具有非常多的配置選項,在單一的webpack.config.js文件中進行配置往往使得這個文件顯得太復雜,因此一些開發者支持把babel的配置選項放在一個單獨的名為 ".babelrc" 的配置文件中
~~~
// npm一次性安裝多個依賴模塊,模塊之間用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
// 配置babel的解析器 其中 resolve是解析路徑的
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader",
},
include:[resolve('app'), resolve('test')],
exclude: /node_modules/
}
]
}
//.babelrc
{
"presets": ["react", "es2015"]
}
~~~
* 注意事項
每一項后綴名的文件都需要追加其對應的loader,否則就會提示你需要正確的loader加載它,導致打包失敗。所以對于文件中有多少文件類型需要追加loader都需要詳細區分。
`error:You may need an appropriate loader to handle this file type`.
## 參考入門項目
* [webpack-demo項目](https://github.com/robinson90/webpack-demo.git)
## 建議
目前三大框架都有基于webpack做的較好的腳手架,如果自己不是特別想鉆研或者浪費時間的話,建議直接基于腳手架開發自己的項目,如果對應的配置環境不夠,自己根據prod的部分額外增加幾個配置即可。
- [create-react-app](https://github.com/facebook/create-react-app)
- [vue-cli](https://github.com/vuejs/vue-cli/)
- [angular-cli](https://github.com/angular/angular-cli)
## 參考文檔
* [github官網地址](https://github.com/webpack/webpack)
* [webpack2.0中文文檔](http://www.css88.com/doc/webpack2/guides/development/)
* [webpack入門--張旺--推薦閱讀](http://www.jianshu.com/p/42e11515c10f)
* [webpack入門到工程化實踐--張旺](http://mp.weixin.qq.com/s/5v7x8tzZzTmB8v5ComfiSA)
* [webpack入門教程(菜鳥教程)](http://www.runoob.com/w3cnote/webpack-tutorial.html)
* [webpack是什么?(http://www.css88.com)](http://www.css88.com/archives/6992#more-6992)
* [webpack知乎傻瓜指南](https://zhuanlan.zhihu.com/p/20367175)
* [極客學院webpack教程](http://wiki.jikexueyuan.com/project/webpack-handbook/)
* [webpack3系列教程](https://www.rails365.net/groups/webpack)
* 掘金小冊 webpack教程
* [從入門到工程實踐](https://mp.weixin.qq.com/s/5v7x8tzZzTmB8v5ComfiSA)
- 前端工程化
- 架構總綱
- 001
- 美團技術架構
- 前端工程化說明
- 歷史背景說明
- 架構說明
- 前端工程化技術棧
- 技術文檔說明
- 功能模塊說明
- 前端模塊管理器簡介
- 框架對比分析
- vue&react&ng對比分析(一)
- vue&react&ng對比分析(二)
- vue&react&ng對比分析(三)
- 工程化專題系列
- 需要解決的問題
- 001
- 002
- 003
- 常見代碼錯誤
- jslint中常見的錯誤
- css規范常見錯誤
- html規范常見錯誤
- 工程化目錄
- 工程化初始化
- 項目構建流程
- 項目打包優化
- 上線與迭代注意事項
- 前端部署發布
- jetkins部署
- 部署需求整理
- 前端監控
- 工程化實踐指南
- dock持續部署
- 系列文章
- 插拔式前端的設計
- 其他實踐
- 工程化的前端管理
- 宋小菜借鑒
- 大前端團隊介紹
- 人員組成
- 人員發展
- 研發流程
- 任務分類
- 前端基礎建設與架構
- 技術棧以及技術方案
- 業務目錄大綱
- 前端大綱
- api管理
- 后端api工具
- 前端easymock
- api攔截與代理
- api優化
- api請求時長策略設計
- 前端架構專題
- 架構專題一
- 產品原型對接
- 與ui對接
- 圖片專題
- 圖片工程化大綱
- 圖片優化
- 圖標字體
- 圖標字體vs雪碧圖
- 工程化的前端矩陣
- 螞蟻金服前端矩陣分享
- BFF架構
- 概念解析
- 前端腳手架
- 初始化項目
- 個性化配置
- 部署與發布
- 性能優化專題
- http專題
- https常識
- http優化1
- http優化2
- http優化3
- http緩存
- 常規web性能優化攻略
- 性能優化大綱
- 樣式優化
- js優化
- 第三方依賴優化
- 代碼分割優化
- 圖片優化
- 打包優化
- 服務器優化
- 緩存優化
- 交互優化
- pc事件優化
- 手機事件優化
- 推薦文章
- 01
- 前端安全專題
- 前端安全大綱
- 前端第三方庫
- seo優化
- web框架的對比
- 001
- 學習資源
- 珠峰前端架構
- npm教程
- npm入門
- cnpm入門
- cnpm搭建
- 你該知道的js模塊
- browserSync
- opn
- js-cookie
- npm-script進階
- 入門篇
- 進階篇
- 高階篇
- 實踐篇
- yarn入門
- nodejs教程
- axios&&fetch
- xhr
- axios
- fetch
- babel專題
- babel入門
- profill入門
- nodejs入門
- 快速入門
- 大綱介紹
- node基礎
- global obj
- assert斷言
- procss-進程
- child_process子進程
- cluster集群
- console控制臺
- crypto-加密
- dgram-數據報
- dns-域名服務器
- error-異常
- events-事件
- global-全局變量
- http-基本協議
- https-安全協議
- modules-模塊
- os-操作系統
- path-路徑
- querystring-查詢字符串
- readline-逐行讀取
- fs-文件系統
- net-網絡操作
- 命令行工具
- 內存泄露
- 代碼的組織與部署
- 異步編程
- orm模塊
- 異步編程解決方案
- node-lessons
- 環境準備
- nodejs實踐
- 項目搭建
- 異步優化
- 創建web和tcp服務器
- 終端問答程序
- 爬蟲系統
- mongleDb
- mongoDB簡介
- 基本使用
- 實用技巧
- 匯總001
- 餓了么后臺搭建
- nodejs干貨
- 滬江基于node的實踐
- 蘇寧基于nodejs優化
- 基于nodejs開發腳手架
- 書籍干貨
- 深入淺出nodejs
- 異步I/O(一)
- gulp教程
- gulp入門
- gulp常用插件(1)
- gulp常用插件(2)
- gulp創建目錄
- 經驗普及貼
- webpack教程
- webpack入門
- 簡單入門
- entry配置
- output配置
- 插件使用01
- 插件使用02
- loader使用
- dev-server介紹
- 構建css
- css模塊化
- 使用less和sass
- 構建圖片
- 引入字體
- babel配置攻略
- eslint
- 001
- webpack進階
- 分不同文件檢出
- 優化打包大小
- 優化打包速度
- 自定義配置
- 單頁以及多頁如何配置
- 優化實踐
- 文章導讀
- 001
- 優化指南
- 參考列表
- webpack4
- 多入口程序構建
- 參考教程
- 項目實踐
- 環境區分
- 常見問題
- 解讀webpack
- 從vuejs權威指南中解決
- 深入淺出webpack
- rollup
- 入門
- parcel
- 入門篇
- express教程
- nuxt教程
- 入門
- 基本入門
- koa教程
- koa基本入門
- koa開發注意事項
- koa實踐指南
- 關于路由
- koa優化指南
- 001
- Vuejs
- vuejs入門系列
- vue-cli入門
- vue2基本認識
- vuejs入門教程
- 樣式綁定
- vuex入門學習筆記
- vue組件生命周期
- 組件的使用
- vue-router入門
- vue-filter
- 計算屬性使用
- 開發注意事項
- mixins
- 組件通訊
- vuejs進階
- 進階資源
- router進階
- 官網介紹
- 前進與后退優化
- keep-alive基本使用
- keep-alive原理詳解
- 鉤子函數進階
- 計算屬性&監聽&方法
- vue服務端渲染技術
- 項目實踐之路
- 實踐大綱
- 插槽專題篇
- vue-cli升級
- 進階入門
- vuejs架構
- nuxt
- vuejs項目實踐
- vue實踐常見問題
- 001
- 002
- 003
- 004
- 005
- 改造api參數探索
- 007
- 008
- 009
- 010
- 項目技術棧
- vue性能問題以及優化方案
- vue-spa應用的理解
- vue-ssr的部署與使用
- 滴滴出行實踐案例
- 2.0重構
- vue-element-admin實踐
- 準備工作
- 菜單設計
- 權限設計
- 依賴模塊
- vue-betterScroll
- 性能優化懶加載
- 京東組件實踐
- vue2項目小結
- vue探索與實踐
- 去哪實踐
- 介紹
- 餓了么項目實踐
- 項目解析
- vue骨架屏實踐
- vue生態推薦
- ui框架
- elementUI
- 001
- 002
- VUE-material
- vant-ui
- 解讀入門
- iview
- 使用問題匯總
- vux
- mint-ui
- loadmore
- vue資源導航
- vueconf
- 源碼解讀
- vm
- 雙向綁定
- 基本原理
- 數組雙向綁定
- 報錯機制
- 封裝方法
- 運行環境
- 入門
- 指令
- vue-router解讀
- util
- vue-props
- 流程邏輯
- 推薦文章
- 源碼解讀
- 文章導讀
- 001
- vuejs實戰
- 基礎篇
- 進階篇
- 實踐篇
- 面試專題
- angularjs教程
- angularjs入門系列
- 基本入門
- ng2入門
- ng進階
- ng項目實踐
- 源碼解讀
- typescript
- reactjs教程
- reactjs入門系列
- react的基本入門
- react組件
- virtalDom認識
- react-cli入門
- react組件的生命周期
- 基本知識點
- react-router教程
- react進階
- 基本實踐
- react加載性能優化指南
- react屬性封裝
- 進階45講
- 01概述
- 02jsx
- 06高階組件&函數子組件
- contextApi
- react-router
- 入門章節
- 進階
- 高階組件
- react進階組件
- 基本介紹
- render props
- render props的封裝
- render props getter
- react-native入門
- 源碼解讀
- 001
- 002-reactDemo
- 參考教程
- 參考教程1
- 了解react-hooks
- ui框架
- pc端ui框架推薦
- 項目實踐
- weatherApp
- 001
- 002
- 不同生命周期使用場景
- react項目結構和組件的命名
- 常見問題解答
- 參考書籍
- react全棧
- 前言
- react與redux進階
- 常見誤解
- 反模式
- react設計模式與最佳實踐
- 7美化組件
- 7.2行內樣式
- 7.4css模塊
- 深入react技術棧
- react學習手冊
- 序
- mobx教程
- 入門
- 大佬推薦
- 001
- react面試
- 001
- linux教程
- linux入門
- 基本入門
- 文件管理
- 文件傳輸
- 文檔編輯
- 磁盤管理
- 磁盤維護
- 網絡通訊
- 系統管理
- 系統設置
- 備份壓縮
- 設備管理
- 查看系統信息
- linux其他
- webhook
- rsync入門教程
- ssh免登陸設置
- 安裝nodejs
- nginx教程
- 入門教程
- 安裝
- 基本配置
- 服務基本使用
- 高性能nginx
- 001
- pm2教程
- shell教程
- 入門大綱
- echo命令
- 參考文獻
- linux常用命令2
- linux常見問題
- 001
- python
- 入門教程
- 機器學習
- 準備工作
- 服務器常識
- tomcat
- 入門常識
- iis
- redis教程
- 入門第一篇
- redis進階
- 項目實踐
- redis使用問題
- mongleDB
- 入門
- 使用進階
- 項目實踐
- 常見問題
- electron
- 入門系列
- 前言
- 小程序
- 入門
- 準備工作
- 路由
- 參考文檔
- 001
- 小程序開發--雙路視頻調研
- 準備工作
- 參考資源
- 參考網址
- docker
- 入門
- 基本認識
- 安裝與使用
- docker安裝nginx
- docker安裝jetkins(1)
- docker部署jenkins(2)
- 進階
- 實踐總結
- docker群分享
- docker部署前端應用
- 文章導讀
- docker其他
- 網絡安全
- 入門
- 大綱
- 項目解析
- schoolpal.web
- 功能模塊大綱
- 目錄結構大綱
- 前端國際化
- 國際化方案
- 其他
- bower入門教程
- weex
- 入門
- memcached
- 入門
- sails
- 入門