參考
Webpack傻瓜式指南 第一章:Webpack 緣起和入門
Webpack傻瓜式指南 第二章 Webpack進(jìn)階:實(shí)戰(zhàn)技巧
Webpack傻瓜式指南 github code
webpack 2 打包實(shí)戰(zhàn)
入門Webpack,看這篇就夠了
一、webpack Helloworld
1.安裝
npm install webpack -g
這里我安裝的時(shí)候,版本已經(jīng)是4.17.2了。使用webpack命令時(shí)會出現(xiàn)提示安裝cli
PS E:\node\webpack> webpack -v
One CLI for webpack must be installed.
These are recommended choices, delivered as separate packages:
- webpack-cli (https://github.com/webpack/webpack-cli)
The original webpack full-featured CLI.
- webpack-command (https://github.com/webpack-contrib/webpack-command)
A lightweight, opinionated webpack CLI.
We will use "npm" to install the CLI via "npm install -D".
Which one do you like to install (webpack-cli/webpack-command):
以下參考初探webpack4
webpack4將命令行相關(guān)的操作抽離到了webpack-cli中,所以,要使用webpack4,必須安裝webpack-cli。當(dāng)然,如果你不想使用webpack-cli,社區(qū)也有替代方案webpack-command,雖然它與webpack-cli區(qū)別不大,但是還是建議使用官方推薦的webpack-cli。
webpack-cli除了能在命令行接受參數(shù)運(yùn)行webpack外,還具備migrate和init功能。
- migrate用來升級webpack配置,能將webpack1的api升級到webpack2,現(xiàn)在用處不大。
- init可以快速生成一個(gè)webpack配置文件的模版,不過用處也不大,畢竟現(xiàn)在的腳手架都集成了webpack的配置。
更詳細(xì)介紹請查看webpack-cli的文檔
注意看,我這個(gè)Demo文件夾名字就叫webpack,所以在執(zhí)行本地安裝npm i -D webpack時(shí),報(bào)錯(cuò)了,需要改改名字。參考 局部安裝webpack提示無法依賴
說明你執(zhí)行命令的目錄里有一個(gè)package.json文件,并且該文件里的name字段就叫webpack。
因?yàn)橹暗奈募A名字叫webpack,然后使用npm init命令時(shí),又使用了默認(rèn)配置,所以package.json的名字也叫webpack了。
2.Webpack 天生支持 ES6 import 和 export 的模塊語法,可以直接使用。當(dāng)然你也可以使用 common.js 來寫。
本節(jié)代碼可以參見 /codes/part1/
在同一個(gè)文件夾下新建兩個(gè)文件。
//hello.js
export default function () {
alert('from anohter planet')
}
//index.js
import hello from './hello'
//調(diào)用這個(gè)方法
hello()
當(dāng)然現(xiàn)在如果直接在 html 頁面里面引用 index.js 是無法執(zhí)行的,瀏覽器是無法處理 ES6 模塊或者是 common.js 規(guī)范的。 那么現(xiàn)在使用 webpack 來處理我們的入口文件。使用 webpack cli 可以傳入兩個(gè)參數(shù),第一個(gè)是入口文件,這里就是 index.js, 第二個(gè)是輸出文件的名字,這里命名為 bundle.js,暫時(shí)不管 bundle.js 里面是什么內(nèi)容,做了哪些工作,但是可以知道就是 webpack 使用一定的魔力,把兩個(gè)文件的依賴和運(yùn)行在 bundle.js 完成了。
webpack index.js bundle.js

又報(bào)錯(cuò)了,版本問題,參考簡單地使用webpack進(jìn)行打包,改成
webpack index.js -o bundle.js即可。
現(xiàn)在發(fā)現(xiàn) bundle.js 被創(chuàng)建出來,再創(chuàng)建一個(gè) html 頁面來引用它。
<html>
<head>
<title> Our first webpack exmaple </title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
現(xiàn)在用瀏覽器打開這個(gè) html 頁面,發(fā)現(xiàn) alert 出現(xiàn)了,任務(wù)完成,慶祝一下!我們可以用 ES6 來完成模塊化開發(fā)啦。
3.使用配置文件
本節(jié)代碼可以參見 /codes/part2/
現(xiàn)在每次都要使用 webpack index.js bundle.js 命令來生成文件,這種每次都要加參數(shù)的做法是程序員痛恨的,webpack 提供配置文件可以很容易的完成這項(xiàng)工作。在項(xiàng)目文件夾中新建 webpack.config.js 文件
module.exports = {
// 入口文件名稱
entry: './index.js',
// 輸出文件名稱
output: {
filename: 'bundle.js'
}
}
然后在項(xiàng)目文件夾中運(yùn)行
webpack
然后發(fā)現(xiàn)配置文件成功,文件生成成功啦!
4使用 Loader
本節(jié)代碼可以參見 /codes/part3/
上面的例子幫我們了解了 webpack 最基本的工作方式,下面來介紹一下 webpack 的一個(gè)強(qiáng)大功能,在開始 Loader 之前,要先知道另外一個(gè)概念 module,上面已經(jīng)說過了這個(gè) module(模塊),上面所說的就是 common.js 或者說是 ES2015格式的import/export 的模塊,在 webpack 中這兩種類型的文件是天生支持的,但是 webpack 可以引入的 module,遠(yuǎn)遠(yuǎn)不止這些,可以是一個(gè)樣式文件(less/css/sass)或者是一個(gè)圖片文件(jpg/png/webp等等)或者是 svg文件 還可能是 coffeescript/typescript 類型,你聽到這里也許有點(diǎn)震驚,在js文件中引進(jìn)一個(gè)樣式文件?應(yīng)該沒有人會這樣做吧,那好的,讓我們來試試吧。
創(chuàng)建一個(gè)新文件 style.css
body {
background: yellow;
}
在 index.js 中直接引入這個(gè)文件
//index.js
import hello from './hello'
// 引入樣式文件
import './style.css'
hello()
在這里我建議將 webpack 的依賴安裝在本地的 package.json 里面。
npm install webpack --save-dev
然后運(yùn)行 webpack 命令,發(fā)現(xiàn)出現(xiàn)了一行錯(cuò)誤,看來我們還是太天真了。
ERROR in ./style.css
Module parse failed: /Users/vzhang/Public/webpack-for-fools/codes/part3/style.css Unexpected token (1:5)
You may need an appropriate loader to handle this file type.
| body {
| background:yellow;
| }
@ ./index.js 2:0-20
翻譯過來的意思就是需要一個(gè)合適的loader來處理這個(gè)類型的文件(css文件)。webpack可以自動處理js類型的文件,但是css文件它不知道該如何處理,這里偉大的loader就出現(xiàn)了,其實(shí)通俗來說 loader 就是一系列的插件來處理不同類型的文件,并將它們成功的引入你的文件中。 Loaders describe to webpack how to process non-JavaScript modules and include these dependencies into your bundles.
在項(xiàng)目目錄下運(yùn)行,來安裝處理css文件需要的兩個(gè)Loader:
npm install style-loader css-loader --save-dev
添加完這兩個(gè)loader之后,我們要教會 webpack 用什么Loader處理什么類型的文件。在 webpack.config.js 中修改:
module.exports = {
// 入口文件名稱
entry: './index.js',
// 輸出文件名稱
output: {
filename: 'bundle.js'
},
// 這里是我們新添加的處理不同類型文件需要的 Loader
module: {
rules: [
{ test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ]}
]
}
}
仔細(xì)分析一下這一句語法:
{ test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ]}
前面 test 傳入一個(gè)正則表達(dá)式,代表你要處理什么類型的文件,這里指的是后綴名為.css的文件,后面的 use 傳入一個(gè)數(shù)組,代表著這個(gè)文件會被這兩個(gè)loader所處理,一個(gè)文件可以被 多個(gè)loader 所處理:
Loaders can be chained. They are applied in a pipeline to the resource. A chain of loaders are compiled chronologically. The first loader in a chain of loaders returns a value to the next. At the end loader, webpack expects JavaScript to be returned.
讀者也許會問處理 css 文件一個(gè) css-loader 不就夠了嗎? 那么 style-loader 是做什么的?這里先賣一個(gè)小關(guān)子,之后會解釋原因。
配置文件改好以后,運(yùn)行 webpack 命令。這次沒有報(bào)錯(cuò),bundle.js 文件生成了,用瀏覽器打開 index.html ,發(fā)現(xiàn)頁面的背景變成了黃色,loader 運(yùn)行成功了!
本節(jié)最后再回到之前的問題,為什么需要兩個(gè) Loader ? 將 style-loader 刪除掉以后,再次運(yùn)行 webpack,發(fā)現(xiàn)并沒有報(bào)錯(cuò),說明 css 文件可以成功的解析并且處理,但是打開 index.html 發(fā)現(xiàn) css 并沒有生效。可以大膽猜測 style-loader 作用是將樣式動態(tài)的使用 js 插入到頁面中去,如果你看 index.html 源代碼也發(fā)現(xiàn)我們并沒有引入任何的樣式文件,這正是 webpack 的特點(diǎn)之一,任何類型的模塊(資源文件),理論上都可以通過被轉(zhuǎn)化為 Javascript 代碼實(shí)現(xiàn)與其他模塊的合并與加載。
你可以在官方網(wǎng)站找到各種webpack 的 loaders 列表: Webpack Loader List
官方網(wǎng)站的圖完美解釋了Webpack在做什么:

二、gulp和webpack究竟有什么區(qū)別?
Gulp 的定位是 Task Runner, 就是用來跑一個(gè)一個(gè)任務(wù)的。
放在以前比如我想用sass寫css, coffee寫js, 我必須手動的用相應(yīng)的compiler去編譯各自的文件,然后各自minify。這時(shí)候designer給你了兩張新圖片,好嘞,接著用自己的小工具手動去壓縮圖片。后來前端人不能忍了,搞出個(gè)自動化這個(gè)流程的 Grunt/Gulp, 比如你寫完代碼后要想發(fā)布production版本,用一句 gulp build 就可以
-
rm掉 dist文件夾中以前的舊文件 - 自動把sass編譯成css, coffee編譯成js
- 壓縮各自的文件,壓縮圖片,生成圖片sprite
- 拷貝minified/uglified 文件到 dist 文件夾
但是它沒法解決的是 js module 的問題,是你寫代碼時(shí)候如何組織代碼結(jié)構(gòu)的問題.
之前大家可以用 require.js, sea.js 來 require dependency, 后來出了一個(gè) webpack 說 我們能不能把所有的文件(css, image, js) 都用 js 來 生成依賴,最后生成一個(gè)bundle呢? 所以webpack 也叫做file bundler.同時(shí) webpack 為了解決可以 require 不同文件的需求引入了loader, 比如面對sass文件有
- sass-loader, 把sass 轉(zhuǎn)換成 css
- css-loader, 讓 webpack 能識別處理 css
- style-loader, 把識別后的 css 插入到 html style中
- 類似的識別es6 有babel-loader
本來這就是 webpack 的初衷,require everything, bundle everything. 一開始 webpack 剛出來的時(shí)候大家都是把它結(jié)合著 gulp 一起用的, gulp 里面有個(gè) gulp-webpack,就是讓 webpack 專門去做module dependency的事情, 生成一個(gè)bundle.js文件,然后再用 gulp 去做一些其他雜七雜八minify, uglify的事情。 后來人們發(fā)現(xiàn) webpack 有個(gè)plugins的選項(xiàng), 可以用來進(jìn)一步處理經(jīng)過loader 生成的bundle.js,于是有人寫了對應(yīng)的插件, 所以minify/uglify, 生成hash的工作也可以轉(zhuǎn)移到webpack本身了,擠掉了gulp這部分的市場份額。 再后來大家有發(fā)現(xiàn) npm/package.json 里面的scripts 原來好好用啊,調(diào)用任務(wù)的時(shí)候就直接寫一個(gè)簡單的命令,因?yàn)?gulp 也不就是各種插件命令的組合呀,大部分情況下越來越不需要 gulp/grunt 之類的了 ref. 所以你現(xiàn)在看到的很多新項(xiàng)目都是package.json里面scripts 寫了一堆,外部只需要一個(gè)webpack就夠了。
打個(gè)不恰當(dāng)?shù)谋确?,webpack就像微信一樣,本來就是做聊天(module dependency)的,后來生生搞出一個(gè)微信小程序(processing files),大家面對簡單的需求發(fā)現(xiàn)這個(gè)比原生app方便使用啊,于是開發(fā)原生的人越來越少一樣。
所以 LZ 一開始就模仿其他項(xiàng)目用 npm scripts + webpack 就好了,當(dāng)你發(fā)現(xiàn)有哪些任務(wù)你沒法用 webpack 或者npm scripts 解決起來麻煩, 這個(gè)時(shí)候再引入task runner 也不遲