看啥雙拱門,來學 webpack 3啊
webpack 是前端開發者一個跨不過去的編譯工具。不過由於他的快速迭代,讓很多同學在學一個版本的時候,下一個新版本就發布了,讓人感覺非常蛋疼和無奈:
「我是誰,我在幹嘛,我要做什麼?」
不過,如果你已經掌握 webpack 比較老的版本,對於新版本的學習而言,應該只需要 0.5 天的工作量就可以完成。因為,其基本理念都是以 JS 為中心,增加的只是其輔助特性。
webpack 到目前為止已經走過了三個大版本,每個版本之間都,增加了非常多可用的特性,但是每個版本的具體配置項都有些差異,很容易讓老版本用戶形成依賴。現在 webpack 3 已經走到了 3.8 版本。現版本對於 webpack 2.x 的配置項來說,最突出的就是 loader 的寫法的改變和內置了 webpack-dev-server 的特性。
所以,本文將帶你全面了解一下 webpack 3.x 版本的新特性和一些常用的 webpack 3.x 的配置。
entry-入口 JS 配置
entry 選項主要用來定製 webpack 引用 JS 文件的主入口,它可以配置多個值來定義多個 JS 主文件入口。具體配置項為:
entry可以是三種值[string | object | array]
- 字元串:如 entry:./src/index.js,字元串也可以是函數的返回值,如entry: () => ./demo。
- 數組形式,如[react,react-dom],可以把數組中的多個文件打包轉換為一個chunk;
entry:
["./app/entry1",
"./app/entry2"],
- 對象形式,如果我們需要配置的是多頁應用,或者我們要抽離出指定的模塊做為公共代碼,就需要採用這種形式了,屬性名是佔位符[name]的值,屬性值可以是上面的字元串和數組,如下:
// 值得注意的是入口文件有幾個就會生成幾個獨立的依賴圖譜。
entry:{
main:./src/index.js,
second:./src/index2.js,
vendor:
[react,react-dom]
// 將 react,react-dom 一起打包
}
有時候,開發者還會利用 require.resolve(route)
來在 entry 中引入具體路徑的文件。該方法只是用來作為路徑模塊的搜索,其返回的是指定文件的絕對路徑名。解析機制有點類似,require(route)
entry:
[
require.resolve(react-dev-utils/webpackHotDevClient),
require.resolve(./polyfills),
//返回 /Users/villainHR/Desktop/file/polyfills/index.js
require.resolve(react-error-overlay),
src/index.js
],
entry 還可以接受 function 返回的 string,array,object 值:
entry:
()
=>
./demo
context 上下文基礎目錄
context 用來設置 entry
和 loaders 的上下文索引依賴。默認情況下,entry 等參考的是當前目錄(CWD)
// 手動設置
context: path.resolve(__dirname,
"app")
通過,entry 設置的相對路徑,會優先尋找 ./app
路徑下的文件。
output-輸出 JS 配置
基礎配置項
output 裡面又很多基本的配置項,基礎配置項有:
output:{
path: path.join(__dirname,./dist),
filename:js/bundle-[name]-[hash].js,
chunkFilename:js/[name].chunk.js,
chunkLoadTimeout:
12000,
publicPath:/dist/
}
- path: 用來決定輸出目錄。通常結合 path.join/resolve() 設置絕對路徑。
- filename[alias: name]: 決定具體輸出的文件名,上面 output 選項中,可以用到很多全局的佔位符,比如:[name]、[hash] 等。
- chunkFilename: 主要是用來對沒在 entry 中定義的文件來設定具體的輸出目錄和文字的。常常用來按需的非同步載入當中,例如:
require.ensure(["modules/tips.jsx"],
function(require)
{
var a =
require("modules/tips.jsx");
// ...
},
tips);
這裡,chunkFilename 就可以將 tips.jsx 具體輸出為 js/tips.chunk.js。
- publicPath:並不是用來輸出打包路徑,而是在 runtime 的時候,手動修改 src 引用路徑的。常常配合 css/style/html-loader 來修改。例如,會將:
src="picture.jpg"Re-writes?src="/assets/picture.jpg"
。相當於,手動修改請求 url 的地址。 - chunkLoadTimeout[Number]: 設置 webpack chunk 的請求超時時間。// TODO
上面也提到了,在 output 中會存在一起全局佔位符,比如::[name]、[hash] 等。代表的含義為:
- [name]:代表打包後文件的名稱,在entry或代碼中(之後會看到)確定;
- [id]:webpack給塊分配的內部chunk id,如果你沒有隱藏,你能在打包後的命令行中看到;
- [hash]:每次構建過程中,生成的唯一 hash 值;(每次都變)
- [chunkhash]: 依據於打包生成文件內容的 hash 值,內容不變,值不變;
- [ext]: 資源擴展名,如js,jsx,png等等;
hash 控制
在全局佔位符中,有一個特殊的值 [hash]。我們可以在 webpack 中,針對 hash 輸出做相關的控制。(這裡會一併影響到 [chunkhash])
- output.hashDigest: 具體輸出 hash 的 encoding,有 hex, latin1 or base64。默認為 hex
- output.hashDigestLength: 輸出 hash 具體長度。默認為 20。
- output.hashFunction: 引入文件的具體演算法,默認為 md5。
- output.hashSalt: 給 hash 加鹽,很少用。
如果,有使用 ExtractTextWebpackPlugin
的話,它會通過 contenthash
選項,直接覆蓋上面 4 個的 hash 選項。
自定義庫的打包
在 webpack 中,如果想要自己寫一個包並發布的話,就需要獨立打包成為一個 library。這裡,在 webpack 中有指定的配置項,和我們平常寫的 webpack 打包項目不同。
獨立打包一個庫,常常會遇到應用外部庫的事情,你可以選擇大伯啊,也可以選擇不打包。這裡,除了 output 選項之外,還需要 externals
選項。下面內容主要對 output 裡面內容做詳解解釋,而 externals 會放到後面進行講解。
externals 主要是用來解決外部庫打包問題,基本設置為:
externals:
{
key:
"value"
},
- value: 用來指明 外部庫 通過全局(window,global)的方式暴露的模塊名。例如:
window.jQuery =
{
//xxx
}
webapck 會直接處理 window
或者 global
對象進行模塊化包裹。否則,則不會對指定模塊進行 externals
處理。這點非常關鍵。
- key: 具體指代,在經過 value 處理過後的外部庫,能夠在 webpack 通過 require 或者 import 的包名,例如:
externals:
{
$:
"jQuery"
}
// index.js
var $ =
require("$");
在 output 中主要有 4 個關鍵選項設置值:
- output.library[String]: 用來設置通過,CDN 引入時的全局 Name。對於,require/import 引入的沒影響(模塊引入具體是根據具體代碼中的
exports
來決定) - output.libraryExport: 限定通過模塊具體暴露的介面。例如:
libraryExport:
["MyModule",
"MySubModule"];
// 只能到處前面兩個模塊
最重要的模塊輸出選項應該是 libraryTarget
,它是用來決定模塊以何種規範輸出,在全局變數的 Name 是啥。其基本格式為:
output.libraryTarget[String]:
var
| assign |
this
| window |
global
| commonjs | commonjs2 | amd | umd
上面那些全部是都是可選項值。這裡先告訴大家,在現代 JS 的寫法中,最後一個 umd
的選項是最常用的。如果你還是想通過 script 標籤引入的話,則前面 5 個比較適合給你靈活自定義。當然, umd
選項也是適合的,不過靈活性差了點。
上面選項可以分為三種類型:
- 全局變數型[var,assign]:用來表示模塊導出,是直接在全局中定義變數。比如,jQuery 的
$
,不需要額外引入處理。 - 對象綁定型[this,window,global,commonjs]:用來將導出的模塊,綁定到具體的對象中。比如,jQuery 的 window[$],this[$] 這樣的引入綁定。
- 模塊綁定型[commonjs2,amd,umd]: 需要通過,全局 require() 方法引入的模塊。
libraryTarget 常常和 library
選項一起結合使用。下面內容,統一 library
設置為 Villainhr
:
output.library:
Villainhr
接下來,我們具體一個一個來細分講解一下:
全局變數型
var
output.libraryTarget:
var
// 默認值
在 js 腳本實際編譯結果為:
var
Villainhr
= _entry_return_;
// In a separate script...
Villainhr.doSomething();
通過 var
變數定義關鍵字來申明一個變數,將導出的模塊直接複製過去。
assign
output.libraryTarget: assign
編譯結果為:
Villainhr
= _entry_return_;
// In a separate script...
Villainhr.doSomething();
這裡,就直接全局綁定,如果前面已經定義過 Villainhr
則會默認覆蓋。其實和 var
定義沒啥區別。
對象綁定型
對象綁定則是直接通過 Object 的方法,將導出的模塊直接綁定到具體對象:
this
output.libraryTarget:
"this"
編譯結果為:
this["Villainhr"]
= _entry_return_;
// In a separate script...
this.Villainhr.doSomething();
Villainhr.doSomething();
// if this is window
導出的模塊,直接綁定在 this 上,在全局中直接使用 http://this.xxx 來進行模塊調用。
window
output.libraryTarget:
"window"
編譯結果為:
window["Villainhr"]
= _entry_return_;
window.Villainhr.doSomething();
// or
Villainhr.doSomething();
這裡就是通常的導出方案,直接將輸出模塊綁定到 window 對象上。其實也相當於 var
綁定,直接通過模塊名使用。
global
output.libraryTarget:
"global"
編譯結果為:
global["Villainhr"]
= _entry_return_;
直接通過 global 對象調用,這個通常用在 NodeJS 的環境。
commonjs
output.libraryTarget:
"commonjs"
編譯結果為:
exports["Villainhr"]
= _entry_return_;
require("Villainhr").doSomething();
在引用調用時,直接通過 require()
方法引入。
模塊綁定型
模塊綁定型有 commonjs2,amd,umd 這三個選項。他們具體的規範就是根據選項值對應的規範來的—— CommonJS
, AMD
。
commonjs2
編譯結果為:
module.exports = _entry_return_;
這和 commonjs
類似,不過遵循的是 commonjs2 的規範,是直接將其賦值到 module.exports 上的。具體使用還是需要 require()
引用:
require("Villainhr").doSomething();
amd
編譯結果為:
define("Villainhr",
[],
function()
{
// main body
});
這裡通過 amd 非同步載入的規範,來導出具體的文件模塊。具體使用是通過 require
方法直接引入使用:
require([Villainhr],
function(Villainhr)
{
// xxx
});
umd
這個模塊標準應該屬於最方便的一種,它實際上集合了 commonjs1/2,amd,this 的綁定方式。具體編譯結果為:
(function webpackUniversalModuleDefinition(root, factory)
{
if(typeof exports ===
object
&&
typeof
module
===
object)
module.exports = factory();
else
if(typeof define ===
function
&& define.amd)
define([], factory);
else
if(typeof exports ===
object)
exports["Villainhr"]
= factory();
else
root["Villainhr"]
= factory();
})(this,
function()
{
//what this module returns is what your entry chunk returns
});
這裡其實一共有 4 個綁定,不過它會優先進行綁定選擇,具體順序是:
commonjs2 > AMD > commonjs > this
也就是 4 選一,如果已經通過 commonjs2 引入的話,則不能在通過其它方式使用。比如,this.Villainhr 這樣是訪問不到的。
module 編譯設置
在 module 選項主要就是用設置 webpack 中常用的 loaders。通過 rules
規則來匹配具體應用的文件和 loaders。
noParse 防止預編譯
noParse 主要用來設置相關的匹配規則,來防止 webpack loaders 對某些文件進行預編譯。
基本設置為:
noParse:
RegExp
|
[RegExp]
|
function
通常,設置的值可以直接為:
noParse:
/jquery|lodash/
// or
noParse:
function(content)
{
return
/jquery|lodash/.test(content);
}
這樣,jquery 和 loadsh 就不會被 webpack 中的 loaders 捕獲並編譯了。
rules 設置匹配規則
module.rules 的選項具體是用來設置 loaders 匹配文件的規則。其基本接受類型為 [Array]。
module:
{
rules:
[{
test:
/.js$/,
exclude:
/node_modules/dist/,
loader:
babel-loader
}]
},
rules 裡面的每個對象都決定了 loaders 的具體類型以及 loaders 作用的具體文件。在 webpack3 中,繼承了 webpack2 的基本限定功能,比如 exclude
、 include
等,還額外加入了通過 query
匹配,以及多個 query 的 loader 匹配規則。
文件匹配
在每一條具體的 rule 裡面,用來進行匹配文件的選項有:Rule.test, Rule.exclude, Rule.include, Rule.and, Rule.or, Rule.not。
上面三個對象其實掛載到的是 Rule.resource
對象上的,你可以直接寫到 Rule 上,也可以寫到 Rule.resource 上。這裡簡單起見,以 rule
為基準。他們的值統一都為 condition
。這個概念,是 webpack 匹配文件提出的。
condition
主要用來設置匹配文件的條件規則。可接受的值有:
condition:
[string
|
RegExp
|
function
| array |
object]
- string: 匹配文件的絕對路徑
- RegExp: 匹配文件的正則
- function: 參數為 input 的路徑,根據返回的 boolean 來決定是否匹配。
- array: 裡面可以傳入多個 condition 匹配規則。
- object: 不常用,用來匹配 key。
接下來,我們來看一下 condition 在各個選項值中的具體實踐。
test
test 用來匹配符合條件的 input。設置的值為:
test:
[condition]
最常用的還是直接寫入正則:
test:
/.jsx$/
include
和 test 一樣,也是用來匹配符合條件的 input,主要用途是用來設置 依賴文件索引目錄。在 include 中,通常設置 string
或者 array of strings。
// 在 entry css 文件中,只能在 app/styles 以及 vendor/styles 中索引依賴文件
{
test:
/.css$/,
include:
[
path.resolve(__dirname,
"app/styles"),
path.resolve(__dirname,
"vendor/styles")
]
}
exclude
設置依賴文件不會存在的目錄。
實際上,上面三個命令是一起配合來提高編譯速度的。因為默認情況下,webpack loaders 會對所有引入的文件進行 loader 編譯,當然,對於 node_modules 裡面成熟的庫,我們沒比較在進行額外的 loader 編譯,直接將其 bundle 即可。
常用設置可以為:
test:
/.js$/,
loader:
babel-loader,
include:
[
path.resolve(__dirname,
"app/src"),
path.resolve(__dirname,
"app/test")
],
exclude:
/node_modules/
// 排除編譯 node_modules 中的文件
剩下的 or
和 not
也是用來設置規則,根據名字大家也可以猜出這兩者的含義:
- or[condition]:滿足其中一種條件即可。例如:
or:[/.*src/index.*/,/.*abc.*/]
- not[condition]:都不滿足所有的條件。設置方法同上
query 匹配
query 匹配具體指的是匹配 url 中的 ?
後的字元串。當然,我們也可以在 test
中通過正則來寫,不過,webpack3 既然已經提供了 query 的選項,我們也可以直接使用它的配置-- resourceQuery
。
resourceQuery
用來設置匹配 query 的規則,接受的內容是 condition
。不過,一般直接設置 正則 或者 string 就行:
// 匹配 query 含有 inline 的路徑,例如:./villainhr.css?inline
{
test:
/.css$/,
resourceQuery:
/inline/,
use:
url-loader
}
另外,如果你想對不同的 query 使用不同的 loader 話,可以直接使用 oneOf
配置。文件資源會默認找到 oneOf 中第一個匹配規則,來調用對應的 loader 處理。
{
test:
/.css$/,
oneOf:
[
{
resourceQuery:
/inline/,
// villainHR.css?inline
use:
url-loader
},
{
resourceQuery:
/external/,
// villainHR.css?external
use:
file-loader
}
]
}
loader 編譯設置
在 webpack2 的時候,主要寫法是根據 loaders
和 loader
來進行設定的。不過,在 webpack3 該為根據文件來決定 loader 的載入。這其中,最大的特點就是,將 loaders 替換為了 rules
。例如:
module:
{
loaders:
[
{test:
/.css$/, loader:
style-loader!css-loader}
]
}
// 替換為:
module:
{
rules:
[
{
test:
/.css$/,
use:[
style-loader,css-loader
]}
]
}
按照規範, use
是用來實際引入 loader 的標籤。在 webpack3 時代,還保留了 loader
欄位,廢除了 query
欄位,其實可以在 use 中找到替代。
loader
用來定義具體使用的 loader,這裡等同於: use:[loader]。
query
用來限定具體的 loader 使用的配置參數,例如 babel 的配置:
test:
/.js$/,
loader:
babel-loader,
query:
{
presets:
[es2015]
}
不過,在 webpack3 中已經廢棄了 query,使用 use
中 options
選項:
test:
/.js$/,
use:[
{
loader:
babel-loader,
options:{
presets:
[es2015]
}
}
]
resolve 模塊解析路徑
resolve 主要是用來解析具體入口文件中,引入依賴文件解析。例如,通過 import
/ require
引入的文件:
import foo from
demo/test/villainhr.js)
// or
require(demo/test/villainhr.js)
在 webpack 中,提供了 3 種路徑解析方式:
- 相對路徑:直接根據入口文件的路徑,來對路徑進行解析。相當於
path.resolve()
這個方法。
import
"../src/villainhr.js";
// 等同於 path.resolve(__dirname,../src/villainhr.js)
- 絕對路徑:根據
resolve.modules
設置的參考目錄來進行解析。默認是根據 webpack 所在的目錄。設置了之後,絕對路徑的解析,只會在設置的參考目錄中查找。
modules:
[path.resolve(__dirname,
"src"),
"node_modules"]
// 設置絕對路徑搜索目錄
import
"/villainhr.js";
// 只會搜索 src/villainhr.js 以及 node_modules/villain.js 。
- 模塊路徑:直接引入模塊,路徑前面不加任何修飾符號。例如:
import"es5";
。webpack 的模塊解析規則比上面兩個規則要複雜一點。因為還牽扯到modules
、alias
、extensions
等。主要規則為: - 搜索
resolve.modules
定義的目錄,如果有alias
標籤,則還會參考 alias 定義的模塊路徑 - 檢查引用的路徑是文件
- 檢查文件是否存在,如果沒有尾綴,則根據
resolve.extensions
定義的尾綴來索引。
- 檢查引用的路徑是目錄
- 檢查含有 package.json,根據
resolve.mainFields
定義的欄位來索引文件。 - 如果不含有 package.json,直接根據
resolve.mainFiles
來索引文件。 - 具體文件解析,根據
resolve.extensions
來解決。
具體模塊路徑解析,可以參考如下:
# /src/villain.js 存在
import VR from
villain;
/** 搜索 /src、node_modules 目錄,
找到 villain 文件,如果沒有,
根據 extensions 添加尾綴查詢。
找到 villain.js
*/
# node_modules/es6 模塊存在
import VR from
es6;
/** 搜索 /src、node_modules 目錄,
找到 es6 文件夾
查看 package.json 文件,
根據 mainFields 定義的欄位索引 packjson,找到 main 欄位定義的文件。
*/
# src/demo/dev/index.js 存在
import VR from
ABC/dev;
/** 根據 alias 定義的 ABC 查找,src/demo/ 目錄下的文件
找到 dev 目錄,裡面沒有 package.json 文件
根據 mainFiles 定義的文件名和 extensions 定義的尾綴找到 index.js 文件
// webpack.config.js
resolve:{
alias: {
ABC: path.resolve(__dirname, src/demo/)
},
modules: [path.resolve(__dirname, "src"), "node_modules"],
mainFields: ["main"],
mainFiles: ["index"],
extensions: [".js", ".json"]
}
設置模塊索引目錄
在 webpack 中,主要提供 alias
和 modules
來進行索引目錄的設置。
- alias:設置導入路徑的簡便寫法。如果你有大量的文件依賴路徑非常長的話,除了使用
modules
設置參考路徑之外,還可以根據alias
來設置路徑映射的 key。另外,它還提供了$
來進行文件的精確匹配,這個看看文檔就行,感覺不常用。例如:
alias:
{
Villainhr: path.resolve(__dirname,
src/Villainhr/)
}
# 如果要獲取 src/Villainhr/index.js 的話,可以直接在 import 寫入:
import test from
Villainhr/index;
- modules: 用來設置模塊解析的目錄。這樣,在進行模塊查找的時候,webpack 會優先遍歷你定義的目錄。如果,你還有自定義模塊在
src
目錄下,通過普通模塊解析是找不到的,這時候可以直接在modules
中添加 src。
modules:
[path.resolve(__dirname,
"src"),
"node_modules"]
package.json 索引解析
和模塊搜索最關鍵的文件是 package.json
、在 node 環境下,如果模塊文件中存在 package.json,會根據其 main
欄位定義的文件來進行索引。通過 webpack 設定的模塊索引,可以更靈活的設置查找規則。其中,主要依賴的是 mainFields
、 mainFiles
、 extensions
這三個欄位。
- mainFields[Array]: 接受的是數組,用來設置在 package.json 文件中,用來定義具體查找文件的欄位。例如:
mainFields:["browser","module","main"]
,則會按順序搜索:browser
、module
、main
這三個欄位。 - mainFiles[Array]:如果文件不含有 package.json,則直接根據
mainFiles
定義的文件來索引。 - extensions[Array]:設置默認文件後綴名。當索引文件時,如果具體路徑沒帶文件名的話,會根據
exntensions
定義的內容來獲取。
loader 簡便書寫
在 modules
指令下,添加具體調用的 loader
一定需要帶上後面的 -loader
尾綴。如果你不想帶,則會默認報錯。不想報錯的話,可以使用 moduleExtensions
指令來說明:
moduleExtensions:
[-loader]
這樣,就可以直接在 module 中直接不帶 -loader
引用:
loader:
eslint
externals 定義外部依賴
externals 是用來排除某些你並不想打包的庫,並且可以通過 import
/ require
在全局環境中調用。這個選項一般是提供給一些開源庫或者組件作者使用的。
相當於,你調用了一個庫,而最終實際打包的文件裡面剔除該庫的存在,只是留下了一個引用介面。
// 剔除 sw-router 庫
externals:
{
Router:
sw-router
}
// 在代碼中使用
import
Router
from
Router;
它可以接收如下類型:(array object function regex)
- array:用來過濾打包文件中的子模塊。
// 將 ./math 文件中的 subtract 過濾不打包。
externals:
{
subtract:
[./math,
subtract]
}
// 忽略如下文件打包:
import
{subtract}
from
./math;
- object:通過 key 值,來決定在不同模塊規範下,文件暴露的介面名。其中,commonjs 代表 require 模塊規則,amd 則代表 define 模塊規則,root 則是代表該模塊在全局環境,例如 window 訪問的對象名。
externals :
{
ex_loadsh :
{
commonjs:
"lodash",
// require(loadsh)
amd:
"lodash",
// define([loadsh])
root:
"_"
// window._
}
}
通過 externals 定義之後,我們在不同環境訪問 loadsh 的方式就變為:
// 全局環境
window.ex_loadsh;
// 模塊包中
require(ex_loadsh);
- function: 前面幾個寫法都是將需要提出的文件寫死,而 function 提供了可以靈活配置的 external list。比如,你想剔除所有 node_modules 包中的庫,而裡面又有幾個包需要引用的話,可以寫為:
externals:
[
function(context, request, callback)
{
if
(/^yourregex$/.test(request)){
// 剔除具體的包
return callback(null,
amd
+ request);
// 通過 amd 定義剔除文件的引用方式
}
callback();
}
]
不過,更方便的直接使用 webpack-node-externals 來完成。如果項目不是特別複雜,這個配置選項一般用不上。
- regexp: 使用正則選項,相當於就是通過正則的
test
方法,通過路徑名的檢查,來決定是否剔除。
externals:
/^(jquery|$)$/i;
//剔除 jquery 和 $ 文件導入
# 剔除如下文件
import $ from
jquery;
// or
import $ from
$;
target 設定打包環境
這裡,如果項目並不複雜的話,可以直接忽略該屬性設置
因為 webpack 本身都是多環境應用,你可以在 node、web、webworker 甚至其他跨平台環境中:node-webkit、electron-main。其常用選項有三個:
- node:在後台環境中使用
- web:在瀏覽器主線程環境中使用
- webworker:在 web-worker 環境中使用
具體設置方式為:
{
target:
node
}
不過,該選項常常用於複雜的打包項目中。比如,一個項目你需要同時輸出在 web 環境中和在 webworker 環境中運行的打包腳本文件。這時候,就涉及到多入口文件的 webpack.config.js 設置。這裡,可以利用 webpack-merge
來幫助我們完成多入口的合併設置。
var baseConfig =
{
target:
async-node,
entry:
{
entry:
./entry.js
},
output:
{
filename:
[name].js,
path: path.resolve(__dirname,
./dist)
}
};
let targets =
[web,
webworker,
node,
async-node,
node-webkit,
electron-main].map((target)
=>
{
let
base
= webpackMerge(baseConfig,
{
target: target,
output:
{
path: path.resolve(__dirname,
./dist/
+ target),
filename:
[name].
+ target +
.js
}
});
return
base;
});
module.exports = targets;
在導出的就會同時編譯出 web、webworker、node 等目錄,裡面的文件就是對應環境中使用的包。如果想用原生的可以直接導出,數組形式的配置項:
var path =
require(path);
var serverConfig =
{
target:
node,
output:
{
path: path.resolve(__dirname,
dist),
filename:
lib.node.js
}
};
var clientConfig =
{
target:
web,
// <=== can be omitted as default is web
output:
{
path: path.resolve(__dirname,
dist),
filename:
lib.js
}
};
module.exports =
[ serverConfig, clientConfig ];
通過,在 webpack 主文件中,具體設置需要使用的配置,即可完成指定環境的編譯操作。
node 提供模擬包
node 指令主要是讓 webpack 將在 node 環境運行的包,提供相關的設置,能夠直接在打包文件中訪問。其策略可以是提供一個樁(空對象),或者直接將現成的包直接打進去。
其基本可選擇的值主要是直接參考 node 的模塊包名:
console
global
process
__filename
__dirname
Buffer
setImmediate
不過,主要用到的還是 Buffer 和 global 兩個配置項。其打包策略選項有 4 個值:
- true: 直接將該包的 polyfill 直接打進去
- "mock": 提供空介面。可以訪問對應的介面名,但是沒有任何作用。
- "empty": 提供一個空對象。這個連介面名都不能訪問
- false: 啥都沒有。
上述默認配置值為:
node:
{
console:
false,
global:
true,
process:
true,
__filename:
"mock",
__dirname:
"mock",
Buffer:
true,
setImmediate:
true
}
這樣設置了之後,我們可以直接在主文件入口中訪問:
const
Buffer
=
require(Buffer);
// doSth()
如果你想啥都不提供,最好直接將 node
設置為 false
。
node:false
devtool 開啟 sourceMap 選項
devtool 主要是給 JS 文件添加對一個的 sourceMap 文件。不過,webpack 可以生成多種 sourceMap 文件,具體的區別是,映射還原度的區別。這裡直接參考 webpack 官方文檔即可。
其中,最常用的選項就是 source-map
和 cheap-eval-source-map
。(這裡實在太多了,各位看著選個合適的就行)如果你想關閉,sourceMap 的話,可以直接使用 hidden-source-map
,或者不傳。比如,下面的配置:
if
(COMPILE)
{
config.devtool =
hidden-source-map;
config.output.path = path.join(__dirname,public);
}
devServer 本地 localhost 調試
devServer 是 webpack 提供一個簡便的調試服務。它可以根據欄位配置,自動起一個 server 來進行調試。如果用過 webpack-dev-server
的同學,應該就很熟悉了。那如果利用 webpack,起一個簡單的 server 服務呢?這裡,直接給一份配置即可:
devServer:
{
contentBase: path.join(__dirname,
"dist"),
// 設置靜態資源訪問路徑
compress:
true,
// 執行壓縮
port:
9000
// 監聽的埠
}
不過,更常用的是利用 webpack server 的熱更新機制。配置列表為:
devServer:
{
contentBase: path.join(__dirname,
"dist"),
compress:
true,
port:
9000,
hot:
true,
hotOnly:
true
}
接著,你就可以通過 localhost:9000
來訪問你編譯過後的目錄。
剩下 server 配置,大家可以直接參考 webpack devServer。
最後說幾句
到這裡,webpack 3.x 的整個內容差不多已經闡述完了。不過,關於 plugin 的內容,我們這裡並沒有過多提及,因為,對於一般 webpack 純使用者來說,直接使用現有成熟的 plugin 即可。還有一個原因是,webpack plugin 內容真的有點多,這裡篇幅有限就不寫了。後面專門針對其內容詳述一篇。
宣傳宣傳
更多精彩內容,歡迎關注我的公眾號 前端小吉米:
推薦閱讀:
※極樂技術周報(第十二期)
※在移動端使用transform: translate代替top left marg等做位移有好處么 ?
※手淘的Flexible方案能使用雪碧圖嗎?
※極樂技術周報(第四十一期)