webpack4筆記
快速了解幾個(gè)基本的概念
mode 模式
通過選擇 development
, production
或 none
之中的一個(gè)遏插,來設(shè)置 mode
參數(shù),你可以啟用 webpack 內(nèi)置在相應(yīng)環(huán)境下的優(yōu)化渤弛。其默認(rèn)值為 production。
- development:開發(fā)模式,會(huì)將process.env.NODE_ENV 的值設(shè)為 development 甚带。啟用NamedChunksPlugin 和 NamedMoudulesPlugin她肯。
- production:生產(chǎn)模式,會(huì)將process.env.NODE_ENV 的值設(shè)為 production 鹰贵。啟用FlagDependencyUsagePlugin辕宏,F(xiàn)lagIncludedChunksPlugin,ModuleConcatenationPlugin砾莱,NoEmitOnErrorsPlugin瑞筐,OccurrenceOrderPlugin,SideEffectsFlagPlugin 和UglifyJsPlugin
// webpack.config.js
module.exports = {
mode: 'production',
}
入口文件(entry)
入口起點(diǎn)(entry point)指示 webpack 應(yīng)該使用哪個(gè)模塊,來作為構(gòu)建其內(nèi)部依賴圖的開始聚假。進(jìn)入入口起點(diǎn)后块蚌,webpack 會(huì)找出有哪些模塊和庫是入口起點(diǎn)(直接和間接)依賴的。
默認(rèn)值./src/index.js
膘格,可以在 webpack 的配置文件中配置入口峭范,配置節(jié)點(diǎn)為: entry
,當(dāng)然可以配置一個(gè)入口,也可以配置多個(gè)瘪贱。
// webpack.config.js
module.exports = {
+ entry: './src/index.js' //單入口
}
// webpack.config.js
module.exports = {
entry: { //多入口
main: './src/index.js',
other: './src/other.js'
}
}
輸出(output)
output 屬性告訴 webpack 在哪里輸出它所創(chuàng)建的 bundles纱控,以及如何命名這些文件。
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'
}
};
loader
loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)菜秦。loader 可以將所有類型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊甜害,然后你就可以利用 webpack 的打包能力,對(duì)它們進(jìn)行處理球昨。
插件(plugins)
loader 被用于轉(zhuǎn)換某些類型的模塊尔店,而插件則可以用于執(zhí)行范圍更廣的任務(wù)。插件的范圍包括主慰,從打包優(yōu)化和壓縮嚣州,一直到重新定義環(huán)境中的變量。插件接口功能極其強(qiáng)大共螺,可以用來處理各種各樣的任務(wù)该肴。
安裝webpack
使用webpack需要安裝node.js,可直接在node.js官網(wǎng)下載安裝
//查看node是否安裝成功
$ node -v //查看node版本 顯示版本號(hào)表示安裝完成
$ npm -v //查看npm版本 node內(nèi)置npm
//創(chuàng)建項(xiàng)目文件
$ mkdir webpack-test && cd webpack-test //新建一個(gè)項(xiàng)目文件夾webpack-test
$ npm init -y //創(chuàng)建一個(gè)默認(rèn)的package.json文件[在項(xiàng)目文件夾下執(zhí)行]
本地安裝
$ npm install webpack webpack-cli -D //本地安裝
全局安裝【不推薦】
在全局狀態(tài)下安裝webpack
$ npm install webpack webpack-cli -g //全局安裝【不推薦全局安裝
注意:不推薦全局安裝 webpack藐不。這會(huì)將你項(xiàng)目中的 webpack 鎖定到指定版本沙庐,并且在使用不同的 webpack 版本的項(xiàng)目中,可能會(huì)導(dǎo)致構(gòu)建失敗佳吞。
這里是使用npm來安裝的拱雏,也可以使用cnpm,yarn
簡單入門
項(xiàng)目結(jié)構(gòu)
webpack-test
+ |- package.json
+ |- /dist
+ |- index.html
+ |- /src
+ |- index.js
webpack4支持 0 配置打包
項(xiàng)目根目錄執(zhí)行[npx] webpack
會(huì)默認(rèn)將src/index.js打包到dist/main.js
默認(rèn)配置文件
webpack4默認(rèn)會(huì)在項(xiàng)目根目錄找webpack.config.js或者webpackfile.js作為配置文件
也可以通過--config指定配置文件,例如: webpack --config webpack.config.test.js
基礎(chǔ)配置
項(xiàng)目根目錄新建webpack.config.js文件
//webpack.config.js
const path = require('path')
module.exports = {
//入口文件
entry: './src/index.js',
//開發(fā)模式 開發(fā):development, 生產(chǎn):production
mode: 'development',
//出口文件
output: {
//打包完的文件名
filename: "bundle.js",
//打包后的路徑
path: path.resolve(__dirname,"dist"),
//公共路徑
publicPath: '/',
},
//配置loader
// module: {},
//配置插件
// plugins: []
}
- entry 入口文件
//多入口
entry: {
main: './src/index.js',
other: './src/other.js'
}
mode 模式
development:開發(fā)模式底扳,代碼不壓縮
production:生產(chǎn)模式铸抑,會(huì)壓縮代碼output 出口文件
//打包多入口文件,也可以通過[name]來生成不同的打包文件,
//[name]是entry中生成 通過[hash]可以生成hash戳
output: {
filename: "bundle-[name].js", //bundle-main.js bundle-other.js
path: path.resolve(__dirname,"dist"), //修改path可以打包到對(duì)象的path文件夾下
}
通過上面webpack.config.js簡單配置執(zhí)行打包 [npx] webpack
會(huì)將src/index.js打包到dist/bundle.js
webpack-dev-server
安裝yarn add webpack-dev-server -D
webpack-dev-server會(huì)通過express(node框架)啟動(dòng)一個(gè)http服務(wù)
配置devServer
//webpack.config.js
module.exports = {
//開發(fā)服務(wù)器配置
devServer: {
port: 3000,//修改端口號(hào)
progress: true,//進(jìn)度條
contentBase: './dist',//默認(rèn)訪問目錄
overlay: true,//是否在頁面展示錯(cuò)誤衷模,(創(chuàng)建腳手架一般都會(huì)開啟)
hot: true, //熱更新
// open: true,//自動(dòng)打開瀏覽器
},
}
配置script
每次通過[npx] webpack等命令比較麻煩鹊汛,可以配置script
//package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --config webpack.config.js"
},
"devDependencies": {
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.1"
}
}
這樣就可以通過yarn build|dev
或npm run build|dev
執(zhí)行相應(yīng)的script
打包非js文件
打包html文件
安裝yarn add html-webpack-plugin -D
html-webpack-plugin可以將htm模板打包
//webpack.config.js
const path = require('path')
const HtmlWabpackPlugin = require('html-webpack-plugin')
module.exports = {
//入口文件
entry: './src/index.js',
//打包環(huán)境 開發(fā):development, 生產(chǎn):production
mode: 'development',
//出口文件
output: {
filename: "bundle.js",//打包完的文件名
path: path.resolve(__dirname,"dist"),//打包后的路徑
publicPath: '/',//公共路徑
},
//配置loader
// module: {},
//配置插件
plugins: [
new HtmlWabpackPlugin({
template: './src/index.html',//打包html模板文件 源
filename: 'index.html',//打包的文件名
minify: {
// removeAttrbuteQuotes: true,//刪除雙引號(hào)
collapseWhitespace: true,//壓縮成一行
},
// hash: true,//生成hash
})
]
}
處理樣式
css-loader,style-loader
當(dāng)引入css文件阱冶,webpack是無法識(shí)別的刁憋,這就需要使用相應(yīng)的css插件|loader
安裝yarn css-loader style-loader -D
css-loader 使webpack能夠解析css @import 'xx.css'
style-loader 將css插入到html文件head標(biāo)簽中
//配置loader
module: {
rules: [
//loader解析是從右向左執(zhí)行
//用法單一,一般一個(gè)loader處理一件事
{
test: /\.css$/,
use: [
{
loader: 'style-loader',//把css插入head標(biāo)簽中 【對(duì)象形式木蹬,可以添加參數(shù)】
options: {
// insertAt: 'top',//插入head位置 注:添加這個(gè)配置(還有wabpack文檔中介紹的個(gè)別其他屬性)報(bào)錯(cuò)至耻,不明所以
}
},
{
loader: 'css-loader'
}
// 'css-loader',//解析@import 【字符串形式】
]
}
]
}
上面通過配置module的rules,通過正則匹配.css文件,陪通過use指定使用相應(yīng)的loader
loader大致分以下幾種
- pre 前置loader //設(shè)置loader可以添加options:{enforce:'pre'}
- normal 普通loader //默認(rèn)
- 內(nèi)鏈loader //import !jquery'
- post 后置loader //設(shè)置loader可以添加options:{enforce:'postloader'}
loader解析是從右向左[從后往前]執(zhí)行尘颓,也可以設(shè)置options修改執(zhí)行順序(options:{enforce:'pre'}優(yōu)先執(zhí)行)
webpack需要先解析css走触,然后再插入到head標(biāo)中,所以應(yīng)該先配置style-laoder,再配置css-loader
使用sass,less樣式預(yù)處理疤苹,需要安裝相應(yīng)的loader(例如:sass-loader[看下面配置]互广,less類似),并配置在css-loader后面(需要先解析)
解析sass
配置sass-loader
安裝yarn add sass-loader node-sass -D
{
test: /\.css$/,
use: [
{
loader: 'style-loader',//把css插入head標(biāo)簽中 【對(duì)象形式,可以添加參數(shù)】
options: {
// insertAt: 'top',//插入head位置 注:添加這個(gè)配置(還有wabpack文檔中介紹的個(gè)別其他屬性)報(bào)錯(cuò)卧土,不明所以
}
},
{
loader: 'css-loader'
}
+ 'sass-loader'
]
}
上面通過css-loader,style-loader可以將引入的css文件插入到html文件的head標(biāo)簽中,
抽離css到文件
還可以通過mini-css-extract-plugin
插件將css抽離到文件中
安裝yarn add mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
plugins: [
///***
new MiniCssExtractPlugin({ //將樣式抽離到文件中
filename: 'main.css'
})
],
module: {
rules: [
//loader解析是從右向左執(zhí)行
//用法單一惫皱,一般一個(gè)loader處理一件事
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
}
// 'css-loader',//解析@import 【字符串形式】
]
}
]
}
css添加前綴
安裝yarn add postcss-loader autoprefixer -D
css-loader后面添加postcss-loader
module: {
rules: [
//loader解析是從右向左執(zhí)行
//用法單一,一般一個(gè)loader處理一件事
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
}
{
loader: 'postcss-loader'
}
]
}
]
}
postcss-loader會(huì)在根目錄查找postcss.config.js作為配置
在根目錄新建postcss.config.js文件
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
打包圖片
安裝yarn add file-loader url-loader -D
- js創(chuàng)建圖片
file-loader 默認(rèn)會(huì)在內(nèi)部生成一張圖片尤莺,到build目錄下旅敷,返回圖片地址
import logo from './logo.png' //引入圖片,返回新的圖片地址
let img = new Image();
img.src = logo;
document.body.appendChild(img);
css中引入背景圖片 可以直接引入
background: url('./logo.png')img標(biāo)簽引入 使用html-withimg-loader
安裝yarn add html-withimg-loader -D
//webpack.config.js
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader'
}
]
}
配置圖片相應(yīng)loader
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 10 * 1024, //設(shè)置當(dāng)圖片小于10KB就轉(zhuǎn)為base64
outputPath: '/img/' //圖片打包到img文件下
}
}
},
]
}
開發(fā)相關(guān)輔助
babel轉(zhuǎn)碼js
雖然現(xiàn)代的瀏覽器已經(jīng)兼容了96%以上的ES6的語法了缝裁,但是為了兼容老式的瀏覽器,我們需要把最新的ES6的語法轉(zhuǎn)成ES5的足绅。這時(shí)就可以使用babel-loader
了
安裝yarn add babel-loader @babel/core @babel/preset-env -D
配置
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: { //使用babel-loader es6 -> es5
presets: [ //也可以在配置在外面[.babelrc文件中配置]
[
"@babel/preset-env",
{
"targets": {
"chrome": "58",
"ie": "10"
}
}
]
]
}
}
]
}
]
}
targets配置的意思就是讓babel根據(jù)你寫入的兼容平臺(tái)來做代碼轉(zhuǎn)換捷绑。
使用@babel/polyfill
includes
作為數(shù)組的實(shí)例方法,在某些瀏覽器其實(shí)是不支持的氢妈,babel默認(rèn)的轉(zhuǎn)換對(duì)于這種場(chǎng)景并不會(huì)做處理粹污,同樣不會(huì)處理的包括WeakMap, WeakSet, Promise等es6新引入的類,所以我們需要@babel/polyfill為我們這些實(shí)例方法等等打上補(bǔ)丁首量。
安裝yarn add @babel/polyfill
很多項(xiàng)目會(huì)在入口文件頂部引入@babel/polyfill
壮吩,或者指定webpack的entry為數(shù)組,第一項(xiàng)引入@babel/polyfill
加缘,這樣配置是可以達(dá)到目錄鸭叙,但可能我們只使用了少量polyfill的api,這時(shí)全局引入就不太劃算了拣宏,這時(shí)我們可以使用babel的useBuiltIns來配置。如下
//這里配置在.babelrc文件(項(xiàng)目根目錄中新建`.babelrc`文件)
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"targets": {
"chrome": "58",
"ie": "10"
}
},
]
]
}
babel幫我們做好了代碼分析勋乾,在需要用到polyfill的地方引入這個(gè)單獨(dú)的補(bǔ)丁宋下,這樣就實(shí)現(xiàn)了按需引入
class支持
當(dāng)打包如下簡單代碼
class A{
a = 1 //報(bào)錯(cuò)
}
這時(shí)可以安裝yarn add @babel/plugin-proposal-class-properties -D
插件
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"targets": {
"chrome": "58",
"ie": "10"
}
},
]
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
裝飾器@Decorator
當(dāng)處理以下代碼時(shí)也是會(huì)報(bào)錯(cuò)
@log //報(bào)錯(cuò)
class A{
a = 1
}
function log(tag){
console.log(tag)
}
安裝相關(guān)插件yarn add @babel/plugin-proposal-decorators -D
配置
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"targets": {
"chrome": "58",
"ie": "10"
}
},
]
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
Babel優(yōu)化
babel-loader可以配置如下幾個(gè)options:
cacheDirectory
:默認(rèn)值為 false。當(dāng)有設(shè)置時(shí)辑莫,指定的目錄將用來緩存 loader 的執(zhí)行結(jié)果涧尿。之后的 webpack 構(gòu)建否过,將會(huì)嘗試讀取緩存,來避免在每次執(zhí)行時(shí),可能產(chǎn)生的并鸵、高性能消耗的 Babel 重新編譯過程(recompilation process)刊咳。如果設(shè)置了一個(gè)空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 將使用默認(rèn)的緩存目錄 node_modules/.cache/babel-loader,如果在任何根目錄下都沒有找到 node_modules 目錄昭躺,將會(huì)降級(jí)回退到操作系統(tǒng)默認(rèn)的臨時(shí)文件目錄。cacheIdentifier
:默認(rèn)是一個(gè)由 babel-core 版本號(hào)伪嫁,babel-loader 版本號(hào)领炫,.babelrc 文件內(nèi)容(存在的情況下),環(huán)境變量 BABEL_ENV 的值(沒有時(shí)降級(jí)到 NODE_ENV)組成的字符串张咳〉酆椋可以設(shè)置為一個(gè)自定義的值,在 identifier 改變后脚猾,強(qiáng)制緩存失效葱峡。forceEnv
:默認(rèn)將解析 BABEL_ENV 然后是 NODE_ENV。允許你在 loader 級(jí)別上覆蓋 BABEL_ENV/NODE_ENV龙助。對(duì)有不同 babel 配置的砰奕,客戶端和服務(wù)端同構(gòu)應(yīng)用非常有用提鸟。
注意:sourceMap 選項(xiàng)是被忽略的胸哥。當(dāng) webpack 配置了 sourceMap 時(shí)(通過 devtool 配置選項(xiàng)),將會(huì)自動(dòng)生成 sourceMap赡鲜。
babel 在每個(gè)文件都插入了輔助代碼空厌,使代碼體積過大.babel 對(duì)一些公共方法使用了非常小的輔助代碼,比如 _extend银酬。 默認(rèn)情況下會(huì)被添加到每一個(gè)需要它的文件中嘲更。你可以引入 babel runtime
作為一個(gè)獨(dú)立模塊,來避免重復(fù)引入揩瞪。
安裝
yarn add @babel/plugin-transform-runtime -D
yarn add @babel/runtime
@babel/plugin-transform-runtime
插件是幫我們把一些babel的輔助方法由直接寫入代碼專為按需引入模塊的方式引用
配置:
webpack.config.js
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
}
}
]
修改.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"targets": {
"chrome": "58",
"ie": "10"
}
},
]
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
}
此時(shí)哮内,webpack打包的時(shí)候,會(huì)自動(dòng)優(yōu)化重復(fù)引入公共方法的問題壮韭。
資源打包不同文件夾下
- js
output: {
filename: "js/[name].js",//打包完的文件名
path: path.resolve(__dirname,"dist"),//打包后的路徑
// publicPath: '',//公共路徑
},
- css
//css打包到css文件夾下
plugins:[
new MiniCssExtractPlugin({ //將樣式抽離到文件中
filename: 'css/main.css' //打包到css文件夾
}),
]
- img
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 10 * 1024, //設(shè)置當(dāng)圖片小于10KB就轉(zhuǎn)為base64北发,否則用file-loader處理
outputPath: '/img/' //打包到img文件夾
}
}
},
]
}
module 配置補(bǔ)充
模塊(module): 這些選項(xiàng)決定了如何處理項(xiàng)目中的不同類型的模塊。
webpack 模塊可以支持如下:
- ES2015 import 語句
- CommonJS require() 語句
- AMD define 和 require 語句
- css/sass/less 文件中的 @import 語句喷屋。
- 樣式
(url(...))
或 HTML 文件(<img src=...>)
中的圖片鏈接(image url)
module.noParse
值的類型: RegExp | [RegExp] | function
防止 webpack 解析那些任何與給定正則表達(dá)式相匹配的文件琳拨。忽略的文件中不應(yīng)該含有 import, require, define 的調(diào)用,或任何其他導(dǎo)入機(jī)制屯曹。忽略大型的 library 可以提高構(gòu)建性能狱庇。
module.exports = {
mode: 'devleopment',
entry: './src/index.js',
...
module: {
noParse: /jquery|lodash/,
// 從 webpack 3.0.0 開始,可以使用函數(shù)惊畏,如下所示
// noParse: function(content) {
// return /jquery|lodash/.test(content);
// }
}
...
};
module.rules
創(chuàng)建模塊時(shí),匹配請(qǐng)求的規(guī)則數(shù)組密任。這些規(guī)則能夠修改模塊的創(chuàng)建方式颜启。這些規(guī)則能夠?qū)δK(module)應(yīng)用 loader,或者修改解析器(parser)浪讳。
module.exports = {
...
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
...
};
module Rule
- Rule 條件詳解
- 字符串:匹配輸入必須以提供的字符串開始缰盏。是的。目錄絕對(duì)路徑或文件絕對(duì)路徑淹遵。
- 正則表達(dá)式:test 輸入值口猜。
- 函數(shù):調(diào)用輸入的函數(shù),必須返回一個(gè)真值(truthy value)以匹配透揣。
- 條件數(shù)組:至少一個(gè)匹配條件济炎。
- 對(duì)象:匹配所有屬性。每個(gè)屬性都有一個(gè)定義行為辐真。
Rule.test
- { test: Condition }:匹配特定條件须尚。一般是提供一個(gè)正則表達(dá)式或正則表達(dá)式的數(shù)組,但這不是強(qiáng)制的侍咱。
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
...
};
其他的條件比如:
-
{ include: Condition }
:匹配特定條件耐床。一般是提供一個(gè)字符串或者字符串?dāng)?shù)組,但這不是強(qiáng)制的放坏。 -
{ exclude: Condition }
:排除特定條件咙咽。一般是提供一個(gè)字符串或字符串?dāng)?shù)組老玛,但這不是強(qiáng)制的淤年。 -
{ and: [Condition] }
:必須匹配數(shù)組中的所有條件 -
{ or: [Condition] }
:匹配數(shù)組中任何一個(gè)條件 -
{ not: [Condition] }
:必須排除這個(gè)條件
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
include: [
path.resolve(__dirname, "app/styles"),
path.resolve(__dirname, "vendor/styles")
],
use: ['style-loader', 'css-loader']
}
]
}
...
};
Rule.use
應(yīng)用于模塊指定使用一個(gè) loader。
Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured).
加載器可以鏈?zhǔn)絺鬟f蜡豹,從右向左進(jìn)行應(yīng)用到模塊上麸粮。
use: [
'style-loader',
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
];
傳遞字符串(如:use: [ "style-loader" ])是 loader 屬性的簡寫方式(如:use: [ { loader: "style-loader "} ])。
清理 dist 目錄
每次構(gòu)建镜廉,我們的 /dist
文件夾都會(huì)保存生成的文件弄诲,然后就會(huì)非常雜亂。
通常娇唯,在每次構(gòu)建前清理 /dist
文件夾齐遵,是比較推薦的做法
clean-webpack-plugin
是一個(gè)比較普及的管理插件,讓我們安裝和配置下塔插。
yarn add clean-webpack-plugin -D
webpack.config.js
const path = require('path');
....
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
+ new CleanWebpackPlugin()
...
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
...
};
現(xiàn)在執(zhí)行 npm run build
梗摇,再檢查 /dist
文件夾。如果一切順利想许,你現(xiàn)在應(yīng)該不會(huì)再看到舊的文件伶授,只有構(gòu)建后生成的文件断序!
由于最新版本變化@2.0.1之前的寫法已經(jīng)不能使用:
new CleanWebpackPlugin(['/dist'])
。
官方文檔地址:https://www.npmjs.com/package/clean-webpack-plugin
可以直接設(shè)置一個(gè)對(duì)象參考:
new CleanWebpackPlugin({cleanOnceBeforeBuildPatterns: ['**/*', '!static-files*']})
壓縮代碼
css使用optimize-css-assets-webpack-plugin插件糜烹,
js使用uglifyjs-webpack-plugin插件
安裝yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
配置
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
optimization: { //配置優(yōu)化項(xiàng)
minimizer: [
new OptimizeCssAssetsWebpackPlugin(),
new UglifyjsWebpackPlugin()
]
}
//也可以配置插件
//plugins: [
// new OptimizeCssAssetsWebpackPlugin(),
// new UglifyjsWebpackPlugin()
//]
}
定義環(huán)境變量
使用webpack.DefinePlugin插件可以定義變量
例如:
//webpack.config.js
plugins: [
new webpack.DefinePlugin({
DEV: JSON.stringify('dev'), //定義字符串時(shí)违诗,不能直接使用'dev',取結(jié)果:dev
})
]
//index.js
if(DEV){
***
}
webpack-merge合并配置文件
可以為不同環(huán)境配置不同的配置文件疮蹦,比如有
webpack.base.js //基礎(chǔ)配置文件
webpack.dev.js //開發(fā)環(huán)境配置
webpack.prod.js //生產(chǎn)環(huán)境配置
//webpack.dev.js
let { smart } = reqiure('webpack-merge')
let base = require('./webpack.base.js')
module.exports = smart(base,{
mode: 'development',
//其他配置
})
//webpack.prod.js
let { smart } = reqiure('webpack-merge')
let base = require('./webpack.base.js')
module.exports = smart(base,{
mode: 'production',
//其他配置
})
全局變量
當(dāng)我們引入第三方模塊時(shí)诸迟,該模塊作用域只在當(dāng)前模塊中。當(dāng)需要設(shè)置全局時(shí)挚币,可以添加loader處理
yarn add expose-loader -D
import $ from 'jquery'
console.log(window.$) // -> underfine 【全局訪問不到】
import $ from 'expose-loader?$!jquery' //通過expose-loader將jquery導(dǎo)出為全局($)
console.log(window.$) // ? ( selector, context ) { *** } 【全局變量】
//或者配置webpack.config.js
module: {
rules: [
{
test: require.reslove('jqeury'),
use: 'expose-loader?$'
}
]
}
另外還可以通過webpack.ProvidePlugin插件亮蒋,讓每個(gè)模塊都插入某變量|模塊
//webpack.config.js
const webpack = require('webpack')
plugins: [
new webpack.ProvidePlugin({
$: 'jquery' //在每個(gè)模塊都注入$(jquery)
})
]
webpack跨域
- 代理
devServer: {
proxy: {
'/api':{
target: 'http:localhost:8081',
pathRewrite: {
'/api': '' //重寫路徑
}
}
}
}
//接口:http:localhost:8081/user
//webpack服務(wù)http:localhost:8080
//以上配置,當(dāng)請(qǐng)求'/api/user',直接轉(zhuǎn)化了到http:localhost:8081/user
- mock數(shù)據(jù)
devServer: {
before(app){
app.get('/user',(req,res) => {
res.json({code: 200,msg: '成功'})
})
}
}
- 使用webpack-dev-middleware
安裝yarn add webpack-dev-middleware
//server.js
let express = require('express')
let app = express();
let webpack = require('webpack')
//中間件
let middle = require('webpack-dev-middle')
//引入配置文件
let config = require('./webpack.config.js')
//處理配置文件
let compiler = webpack(config)
//使用中間件妆毕,當(dāng)開啟服務(wù)的時(shí)候慎玖,將webpack服務(wù)也一并開啟
app.use(middle(compiler))
app.get('/user',(req,res) => {
res.json({code: 200,msg: '成功'})
})
app.listen(300)
devtool映射文件
通過配置devtool可以配置映射文件
source-map
單獨(dú)生成source-map文件,出錯(cuò)顯示行和列
devtool: 'source-map'eval-source-map
不會(huì)生成單獨(dú)的文件笛粘,出錯(cuò)會(huì)顯示行和列
devtool: 'eval-source-map'cheap-module-source-map
不產(chǎn)生列趁怔,但是一個(gè)單獨(dú)映射文件(和文件沒有關(guān)聯(lián))⌒角埃可以保存起來調(diào)試使用
devtool: 'cheap-module-source-map'cheap-module-eval-source-map
不生成文件润努,集成到打包后的文件中,不顯示列
devtool: 'cheap-module-eval-source-map'
watch監(jiān)聽(熱更新)
當(dāng)代碼修改時(shí)示括,可以時(shí)時(shí)打包铺浇。
devServer也可以實(shí)現(xiàn)重新打包,但感覺有點(diǎn)慢
module.exports = {
devServer: {
hot: true, //熱更新
}
}
配置watch
module.exports = {
watch: true,
watchOptions: { //監(jiān)控選項(xiàng)
poll: 1000,//1分鐘詢問1000次
aggregateTimeout: 500,//防抖 輸入停止后500ms后打包文件
ignored: /node_module/, //不監(jiān)控的文件
}
}
解析(resolve)
配置模塊如何解析垛膝。比如: import _ from 'lodash'
,其實(shí)是加載解析了lodash.js文件鳍侣。此配置就是設(shè)置加載和解析的方式。
resolve.alias
創(chuàng)建 import 或 require 的別名吼拥,來確保模塊引入變得更簡單倚聚。例如,一些位于 src/ 文件夾下的常用模塊:
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
+ resolve: {
+ alias: {
+ vue$: path.resolve(__dirname, 'src/lib/vue/dist/vue.esm.js'),
+ '@': path.resolve(__dirname, 'src/')
+ }
+ }
...
}
// index.js
// 在我們的index.js文件中凿可,就可以直接import
import vue from 'vue';
// 等價(jià)于
import vue from 'src/lib/vue/dist/vue.esm.js';
-
resolve.extensions
的應(yīng)用
自動(dòng)解析確定的擴(kuò)展惑折。
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
resolve: {
alias: {
vue$: path.resolve(__dirname, 'src/lib/vue/dist/vue.esm.js'),
'@': path.resolve(__dirname, 'src/')
},
+ extensions: [".js", ".vue",".json"] // 默認(rèn)值: [".js",".json"]
}
...
}
給定對(duì)象的鍵后的末尾添加 $,以表示精準(zhǔn)匹配
- resolve一般配置
//webpack.config.js
module.exports = {
resolve: { //解析第三方包
modules: [
path.resolve('node_modules'), //在當(dāng)前node_modules文件查找包
],
mainFields: [ //查找字段
'style',
'main'
],
mainfiles: [ //入口文件名字
'index.js'
],
alias: { //別名
bootstrap: 'bootstrap/dist/css/bootstrap.css'
},
extensions: [ //添加后綴 當(dāng)import xx from './xx'
'.js', //先找xx.js
'.css' //沒找到再找xx.css
]
}
}
外部擴(kuò)展(externals)
externals 配置選項(xiàng)提供了「從輸出的 bundle 中排除依賴」的方法枯跑。 文檔
例如惨驶,從 CDN 引入 jQuery,而不是把它打包:
index.html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
webpack.config.js
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
alias: {
extensions: [".js", ".vue",".json"] // 默認(rèn)值: [".js",".json"]
vue$: path.resolve(__dirname, 'src/lib/vue/dist/vue.esm.js'),
'@': path.resolve(__dirname, 'src/')
},
+ externals: {
+ jquery: 'jQuery'
+ },
...
}
這樣就剝離了那些不需要改動(dòng)的依賴模塊敛助,換句話粗卜,下面展示的代碼還可以正常運(yùn)行:
import $ from 'jquery';
$('.my-element').animate(...);
具有外部依賴(external dependency)的 bundle 可以在各種模塊上下文(module context)中使用,例如 CommonJS, AMD, 全局變量和 ES2015 模塊辜腺。外部 library 可能是以下任何一種形式:
- root:可以通過一個(gè)全局變量訪問 library(例如休建,通過 script 標(biāo)簽)乍恐。
- commonjs:可以將 library 作為一個(gè) CommonJS 模塊訪問。
- commonjs2:和上面的類似测砂,但導(dǎo)出的是 module.exports.default.
- amd:類似于 commonjs茵烈,但使用 AMD 模塊系統(tǒng)。
不同的配置方式:
externals : {
react: 'react'
}
// 或者
externals : {
lodash : {
commonjs: "lodash",
amd: "lodash",
root: "_" // 指向全局變量
}
}
// 或者
externals : {
subtract : {
root: ["math", "subtract"] // 相當(dāng)于: window.math.substract
}
}
構(gòu)建目標(biāo)(targets)
webpack 能夠?yàn)槎喾N環(huán)境或 target 構(gòu)建編譯砌些。想要理解什么是 target 的詳細(xì)信息呜投,請(qǐng)閱讀 target 概念頁面。
target
: 告知 webpack 為目標(biāo)(target)指定一個(gè)環(huán)境存璃。
可以支持以下字符串值:
選項(xiàng) | 描述 |
---|---|
async-node | 編譯為類 Node.js 環(huán)境可用(使用 fs 和 vm 異步加載分塊) |
electron-main | 編譯為 Electron 主進(jìn)程仑荐。 |
electron-renderer | 編譯為 Electron 渲染進(jìn)程,使用 JsonpTemplatePlugin, FunctionModulePlugin 來為瀏覽器環(huán)境提供目標(biāo)纵东,使用 NodeTargetPlugin 和 ExternalsPlugin 為 CommonJS 和 Electron 內(nèi)置模塊提供目標(biāo)粘招。 |
node | 編譯為類 Node.js 環(huán)境可用(使用 Node.js require 加載 chunk) |
node-webkit | 編譯為 Webkit 可用,并且使用 jsonp 去加載分塊偎球。支持 Node.js 內(nèi)置模塊和 nw.gui 導(dǎo)入(實(shí)驗(yàn)性質(zhì)) |
web | 編譯為類瀏覽器環(huán)境里可用(默認(rèn)) |
webworker | 編譯成一個(gè) WebWorker |
例如洒扎,當(dāng) target 設(shè)置為 "electron",webpack 引入多個(gè) electron 特定的變量.
webpack.config.js
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
alias: {
extensions: [".js", ".vue",".json"] // 默認(rèn)值: [".js",".json"]
vue$: path.resolve(__dirname, 'src/lib/vue/dist/vue.esm.js'),
'@': path.resolve(__dirname, 'src/')
},
externals: {
jquery: 'jQuery'
},
+ target: 'node'
...
}
相關(guān)的loader列表
webpack
可以使用 loader 來預(yù)處理文件衰絮。這允許你打包除 JavaScript 之外的任何靜態(tài)資源袍冷。你可以使用 Node.js 來很簡單地編寫自己的 loader。
文件
-
raw-loader
加載文件原始內(nèi)容(utf-8) -
val-loader
將代碼作為模塊執(zhí)行猫牡,并將 exports 轉(zhuǎn)為 JS 代碼 -
url-loader
像 file loader 一樣工作胡诗,但如果文件小于限制,可以返回 data URL -
file-loader
將文件發(fā)送到輸出文件夾淌友,并返回(相對(duì))URL
JSON
-
json-loader
加載 JSON 文件(默認(rèn)包含) -
json5-loader
加載和轉(zhuǎn)譯 JSON 5 文件 -
cson-loader
加載和轉(zhuǎn)譯 CSON 文件
轉(zhuǎn)換編譯(Transpiling)
-
script-loader
在全局上下文中執(zhí)行一次 JavaScript 文件(如在 script 標(biāo)簽)煌恢,不需要解析 -
babel-loader
加載 ES2015+ 代碼,然后使用 Babel 轉(zhuǎn)譯為 ES5 -
buble-loader
使用 Bublé 加載 ES2015+ 代碼亩进,并且將代碼轉(zhuǎn)譯為 ES5 -
traceur-loader
加載 ES2015+ 代碼症虑,然后使用 Traceur 轉(zhuǎn)譯為 ES5 -
ts-loader
或awesome-typescript-loader
像 JavaScript 一樣加載 TypeScript 2.0+ -
coffee-loader
像 JavaScript 一樣加載 CoffeeScript
模板(Templating)
-
html-loader
導(dǎo)出 HTML 為字符串缩歪,需要引用靜態(tài)資源 -
pug-loader
加載 Pug 模板并返回一個(gè)函數(shù) -
jade-loader
加載 Jade 模板并返回一個(gè)函數(shù) -
markdown-loader
將 Markdown 轉(zhuǎn)譯為 HTML -
react-markdown-loader
使用 markdown-parse parser(解析器) 將 Markdown 編譯為 React 組件 -
posthtml-loader
使用 PostHTML 加載并轉(zhuǎn)換 HTML 文件 -
handlebars-loader
將 Handlebars 轉(zhuǎn)移為 HTML -
markup-inline-loader
將內(nèi)聯(lián)的 SVG/MathML 文件轉(zhuǎn)換為 HTML归薛。在應(yīng)用于圖標(biāo)字體,或?qū)?CSS 動(dòng)畫應(yīng)用于 SVG 時(shí)非常有用匪蝙。
樣式
-
style-loader
將模塊的導(dǎo)出作為樣式添加到 DOM 中 -
css-loader
解析 CSS 文件后主籍,使用 import 加載,并且返回 CSS 代碼 -
less-loader
加載和轉(zhuǎn)譯 LESS 文件 -
sass-loader
加載和轉(zhuǎn)譯 SASS/SCSS 文件 -
postcss-loader
使用 PostCSS 加載和轉(zhuǎn)譯 CSS/SSS 文件 -
stylus-loader
加載和轉(zhuǎn)譯 Stylus 文件
清理和測(cè)試(Linting && Testing)
-
mocha-loader
使用 mocha 測(cè)試(瀏覽器/NodeJS) -
eslint-loader
PreLoader逛球,使用 ESLint 清理代碼 -
jshint-loader
PreLoader千元,使用 JSHint 清理代碼 -
jscs-loader
PreLoader,使用 JSCS 檢查代碼樣式 -
coverjs-loader
PreLoader颤绕,使用 CoverJS 確定測(cè)試覆蓋率
框架(Frameworks)
-
vue-loader
加載和轉(zhuǎn)譯 Vue 組件 -
polymer-loader
使用選擇預(yù)處理器(preprocessor)處理幸海,并且require()
類似一等模塊(first-class)的 Web 組件 -
angular2-template-loader
加載和轉(zhuǎn)譯 Angular 組件 - Awesome 更多第三方 loader祟身,查看 awesome-webpack 列表。
其他小插件
- cleanWebpackPlugin
每次打包會(huì)先刪除文件
let CleanWebpackPlugin = require('clean-webpack-pulgin')
plugins: [
new CleanWebpackPlugin('./dist'), //每次打包會(huì)先刪除dist文件夾物独,可以傳數(shù)組['./dist','./assets']
]
- copyWebpackPlugin
拷貝插件
let CopyWebpackPlugin = require('copy-webpack-pulgin')
plugins: [
new CopyWebpackPlugin([
{from: 'md',to:''},// 將md文件夾的內(nèi)容拷貝到打包目錄下
]),
]
- bannerPlugin //webpack內(nèi)置插件
版權(quán)申明插件
let webpack = require('webpack')
plugins: [
new webpack.BannerPlugin('make by 2020 Echo'), //打包出來的每個(gè)js文件頭部都會(huì)插入 /*make by 2020 Echo*/
]
打包分析
webpack-bundle-analyzer
插件可以幫助我們分析打包后的圖形化的報(bào)表袜硫。
僅僅在開發(fā)環(huán)境使用。
安裝yarn add webpack-bundle-analyzer -D
+ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
+ new BundleAnalyzerPlugin()
]
}
自動(dòng)生成一個(gè)網(wǎng)頁報(bào)表挡篓,如下所示:
[圖片上傳失敗...(image-33e3e3-1586335983662)]
優(yōu)化
webpack自帶優(yōu)化
- tree_shaking
使用import語法導(dǎo)入模塊婉陷,只會(huì)打包用了的方法(刪除掉沒使用的代碼)
例如:
//test.js
let fun1 = () => {}
let fun2 = () => {}
module.exports = {fun1,fun2}
//index.js
import test from './test.js'
test.fun1();//這里只用了fun1方法我碟,當(dāng)使用import導(dǎo)入瞬内,生產(chǎn)環(huán)境打包時(shí)fun2函數(shù)(沒使用)并不會(huì)打包
使用es6(require)導(dǎo)入會(huì)把結(jié)果放到default
let test = require('./test.js')
test.default.fun1()
- 省略無用代碼
let a = 1,b = 2;
console.log(a+b);
打包后:console.log(3)
動(dòng)態(tài)鏈接庫
使用webpack內(nèi)置插件dllPulgin
當(dāng)引入react
,react-dom
,打包會(huì)將其一起打包到一個(gè)文件夾漆羔,這樣文件會(huì)比較大戏羽。
我們可以將react
,react-dom
打包到單獨(dú)文件担神,或稱為動(dòng)態(tài)連接庫,并在html文件中引入該文件
//新建webpack.react.js配置文件始花,用于打包react,react-dom
let path = require('path')
let webpack = require('webpack')
module.exports = {
entry: {
react: ['react','react-dom']
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname,'dist'),
library: '_dll_[name]', //打包的js前面添加 var _dll_react = (原先打包內(nèi)容)
// libraryTarget: 'var', //添加方式 var: var dll = ***; commmonjs: exports(dll) = ***; ...
},
mode: 'development',
devServer: {
port:3000,
contentBase: './dist',
},
plugins: [
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.resolve(__dirname,'dist','manifest.json')
})
]
}
打包完dist文件下生成_dll_react.js
和manifest.json
兩文件
然后在html文件中引入_dll_react.js
//項(xiàng)目文件
import React from 'react'
import { render } from 'react-dom'
項(xiàng)目中引入的react
,react-dom
還是會(huì)打包杏瞻,所以需要添加配置,告知到動(dòng)態(tài)連接庫中查找
//項(xiàng)目正式配置文件webpack.config.js
let path = require('path')
let HtmlWebpackPulgin = require('html-webpack-plugin')
let webpack = require('webpack')
module.exports = {
//配置多入口
entry: {
main: './src/react.js'
// other: './src/other.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname,'dist')
},
mode: 'production',
devServer: {
port:3000,
contentBase: './dist'
},
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname,'dist','manifest.json')
}),
new HtmlWebpackPulgin({
template: './src/index.html',
filename: 'index.html',
})
],
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
},
include: /src/,
exclude: /node_modules/
}
]
}
}
還有前面提到的externals可以設(shè)置不打包的模塊衙荐,CDN引入捞挥。
happypack多線程打包
安裝yarn add happypack -D
//webpack.config.js
let Happypack = require('happypack')
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'Happypack/loader?id=js'
},
{
test: /\.css$/,
use: 'Happypack/loader?id=css'
}
]
},
plugins: [
new Happypack({
id: 'js',
use: [
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
]
}),
new Happypack({
id: 'css',
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader"
]
})
]
}
抽離公共模塊
//webpack.config.js
module.exports = {
optimization: {
splitChunks: { //分割代碼塊
cacheGroups: { //緩存組
common: { //公共模塊
chunks: 'initial', //入口處開始
minSize: 0, //大于0的公用代碼塊
minChunks: 2, //公用了2次以上
}
vendor: { //第三方
priority: 1, //優(yōu)先抽離
test: /node_modules/,
chunks: 'initial', //入口處開始
minSize: 0, //大于0的公用代碼塊
minChunks: 2
}
}
}
}
}
更過optimization
配置請(qǐng)看webpack文檔
最后
到此,筆記結(jié)束忧吟。如有錯(cuò)誤砌函,歡迎在指出。
如果覺得可以溜族,幫忙點(diǎn)個(gè)贊讹俊。如有不對(duì)還忘指出,謝謝煌抒。
傳送門git筆記