webpack 是一個現(xiàn)代 JavaScript 應用程序的靜態(tài)模塊打包器(module bundler)粹舵。當 webpack 處理應用程序時勺届,它會遞歸地構(gòu)建一個依賴關系圖(dependency graph),其中包含應用程序需要的每個模塊摇幻,然后將所有這些模塊打包成一個或多個 bundle(包,捆)。webpack 是高度可配置的牵舵,從 webpack v4.0.0 開始,可以不用引入配置文件倦挂。
開始前你需要先理解四個核心概念:
入口(entry)
輸出(output)
loader
插件(plugins)
入口
入口起點(entry point)指示 webpack 應該使用哪個模塊畸颅,來作為構(gòu)建其內(nèi)部依賴圖的開始。進入入口起點后妒峦,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的重斑。每個依賴項隨即被處理,最后輸出到稱之為 bundles 的文件中肯骇。
可以通過在 webpack 配置中配置 entry
屬性窥浪,來指定一個入口起點(或多個入口起點)。默認值為 ./src
笛丙。
webpack.config.js
---
module.exports = {
entry: './path/to/my/entry/file.js'
};
//上面的代碼是entry 屬性的單個入口語法漾脂,是下面的簡寫:
const config = {
entry: {
main: './path/to/my/entry/file.js'
}
};
分離 應用程序(app) 和 第三方庫(vendor) 入口
webpack.config.js
---
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
//上面的代碼表示webpack 從app.js和vendors.js開始創(chuàng)建依賴圖(dependency graph)。這些依賴圖是彼此完全分離胚鸯、互相獨立的(每個 bundle 中都有一個 webpack 引導(bootstrap))骨稿。這種方式比較常見于,只有一個入口起點(不包括 vendor)的單頁應用程序(single page application)中。此設置允許你使用 `CommonsChunkPlugin` 從「應用程序 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle坦冠,并把引用 vendor 的部分替換為__webpack_require__()調(diào)用形耗。如果應用程序 bundle 中沒有 vendor 代碼,那么你可以在 webpack 中實現(xiàn)被稱為長效緩存的通用模式辙浑。
webpack.config.js
---
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
//上面的代碼表示webpack 需要 3 個獨立分離的依賴圖
//在多頁應用中激涤,當頁面跳轉(zhuǎn)時服務器將為你獲取一個新的 HTML 文檔。頁面重新加載新文檔判呕,并且資源被重新下載倦踢。使用CommonsChunkPlugin 為每個頁面間的應用程序共享代碼創(chuàng)建 bundle。由于入口起點增多侠草,多頁應用能夠復用入口起點之間的大量代碼/模塊辱挥,從而可以極大地從這些技術中受益。每個 HTML 文檔只使用一個入口起點边涕。
出口
output 屬性告訴 webpack 在哪里輸出它所創(chuàng)建的 bundles晤碘,以及如何命名這些文件,默認值為 ./dist奥吩。
webpack.config.js
---
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
//上面的代碼中哼蛆,output.filename是我們要生成的webpack bundle 的名稱,output.path是我們想要 bundle 生成(emit)到哪里霞赫。上面導入的 path 模塊是一個 Node.js 核心模塊腮介,用于操作文件路徑。
如果配置創(chuàng)建了多個單獨的 "chunk"(例如叠洗,使用多個入口起點或使用像 CommonsChunkPlugin 這樣的插件),則應該使用占位符(substitutions)來確保每個文件具有唯一的名稱旅东。
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 寫入到硬盤:./dist/app.js, ./dist/search.js
2灭抑、高級進階-使用 CDN 和資源 hash 的復雜示例:
config.js
---
output: {
path: "/home/proj/cdn/assets/[hash]",
publicPath: "http://cdn.example.com/assets/[hash]/"
}
在編譯時不知道最終輸出文件的 publicPath
的情況下,publicPath
可以留空抵代,并且在入口起點文件運行時動態(tài)設置腾节。如果你在編譯時不知道 publicPath
,你可以先忽略它荤牍,并且在入口起點設置 __webpack_public_path__
案腺。
__webpack_public_path__ = myRuntimePublicPath
// 剩余的應用程序入口
loader
loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript,但loader 能夠 import 導入任何類型的模塊康吵,其他打包程序或任務執(zhí)行器的可能并不支持)劈榨。loader 可以將所有類型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊,然后你就可以利用 webpack 的打包能力晦嵌,對它們進行處理同辣。
本質(zhì)上拷姿,webpack loader 將所有類型的文件,轉(zhuǎn)換為應用程序的依賴圖(和最終的 bundle)可以直接引用的模塊旱函。
在更高層面响巢,在 webpack 的配置中 loader 有兩個目標:
1.test 屬性,用于標識出應該被對應的 loader 進行轉(zhuǎn)換的某個或某些文件棒妨。
2.use 屬性抵乓,表示進行轉(zhuǎn)換時,應該使用哪個 loader靶衍,也可以指定多個 loader。
在使用前要先安裝相對應的 loader茎芋,例如:
npm install --save-dev css-loader
npm install --save-dev raw-loader
webpack.config.js
---
const path = require('path');
const config = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
//當遇到.txt文件時颅眶,先用raw-loader轉(zhuǎn)換一下
]
}
};
module.exports = config;
插件
loader 被用于轉(zhuǎn)換某些類型的模塊,而插件的范圍包括田弥,從打包優(yōu)化和壓縮涛酗,一直到重新定義環(huán)境中的變量。插件接口功能極其強大偷厦,可以用來處理各種各樣的任務商叹。
想要使用一個插件,你只需要 require() 它只泼,然后把它添加到 plugins 數(shù)組中剖笙。多數(shù)插件可以通過選項(option)自定義。你可能在一個配置文件中因為不同目的而多次使用同一個插件请唱,這時需要通過使用 new 操作符來創(chuàng)建它的一個實例弥咪。
webpack.config.js
---
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝
const webpack = require('webpack'); // 用于訪問內(nèi)置插件
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
模式
通過選擇 development
或 production
之中的一個,來設置 mode
參數(shù)十绑,你可以啟用相應模式下的 webpack 內(nèi)置的優(yōu)化聚至。
module.exports = {
mode: 'production'
};
// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin(),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
// webpack.production.config.js
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}