webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(static module bundler),簡單來講,是一個前端模塊化打包編譯工具,基本的功能包括代碼轉換,文件優化,代碼分割,自動刷新等。
複製代碼
webpack配置文件是基於node.js,而且遵循common.js來開發,
一般咱們會在根目錄下新建一個webpack.config.js文件,基本的結構目錄以下圖所示:
複製代碼
初始化:webpack3中,webpack和cli是在同一個包中,webpack4中已經分開。 yarn add webpack webpack-clicss
entry: {
main: './src/index.js' //單入口
}
複製代碼
entry: {
main: './src/index.js', //多入口
test: './src/test.js'
}, //提示webpack把哪一個文件做爲構建文件的入口
output: {
path: path.resolve(__dirname,'dist'),//必須是絕對路徑
//filename: 'bundle.js'
filename:'[name].[hash:8].js'//打包多個文件,各自名字,而且加上md5戳,8位
}, //構建結束輸出的位置
複製代碼
打包後的js文件,名字bundle.js,若是想運行這個js,可是不能每次打包後都本身手動添加一個html,所以須要一個自動打包html的插件,而且可以自動把打包後的js添加上去。 第一個webpack插件 html-webpack-plugin 打包html做用 單入口html
let HtmlWebpackPlugin = rquire('html-webpack-plugin') //類
plugins: [
new HtmlWebpackPlugin({
fileName: 'index.html',//默認就是index.html
template: './public/index.html',
//以public下的index.html爲模板打包
minify: {
removeAttributeQuotes: true, //去除引號
removeEmptyAttributes: true //清除全部的空屬性
...
},
hash: true, //html引js避免緩存
...
})
]
複製代碼
多入口自動打包引入js,利用循環前端
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
minify: {
removeAttributeQuotes: true,
removeEmptyAttributes: true
},
chunks: ['main'],//指定入口文件名字,自動引入相應js文件
hash: true
}),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'test.html',
chunks: ['test'],
hash: true
})
]
複製代碼
每次更改完代碼,不能每次都手動打包,所以須要創建本地開發服務器,插件webpack-dev-server,而且它是在內存中打包,並不會看到dist目錄,和build不一樣;而且修改代碼會實時刷新。java
devServer: {//開發服務器配置,這裏單獨列出,不在plugins內
before(app){//若是不用轉發,dev-server開啓以前,前端本身mock數據
app.get('/api/user',function(req,res){
res.json({name:"fight"})
})
},
contentBase: path.join(__dirname, 'dist'),//來自dist目錄的文件提供服務,默認是output輸出位置
port: '3000',//更改端口號
progress: true,//打包時候進度條
compress:true //啓動gzip壓縮
<!--proxy: {//node代理,假如頁面訪問api,node自動轉發到3000端口-->
<!-- '/api':{-->
<!-- target: 'http://localhost:3000',--> <!-- pathRewrite: {--> <!-- '/api': ''//假如路徑中有/api,重寫置空--> <!-- } --> <!-- }--> <!--}--> }, 複製代碼
loader有三種寫法,字符串,數組和對象 當js須要樣式的時候,import並不能解析,所以須要loader來轉換模塊node
module: {
rules: [
//css-loader 解析文中@import,style-loader 再以style方式插入樣式
//less 下載less less-loader,scss 下載node-sass sass-loader
{
test: /\.(css|less)$/,
use: ['style-loader','css-loader','less-loader']//順序不能變,不然報錯
}
]
},
複製代碼
module.exports = {
plugins: [require('autoprefixer')]
}
複製代碼
let MiniCssExtractPlugin = require(mini-css-extract-plugin)
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader, //抽取樣式到Link標籤中 mini-css-extract-plugin
{
loader: 'css-loader',
options: {}
},
'less-loader',
'postcss-loader' //兼容前綴
]
}
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css' //href名字,以下圖所示
})
]
複製代碼
目標:把ES6語法或者更高級別語法編譯成ES5語法react
{
test: /\.js$/,
exclude: 'node_modules',
use:
[
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
"plugins": [
['@babel/plugin-proposal-decorators',{"legacy":true}],//解析裝飾器
['@babel/plugin-proposal-class-properties',{"loose":true}],
[ "@babel/plugin-transform-runtime"] //該插件依賴安裝@babel/runtime,解析高級語法,好比yiled
]
}
},
'eslint-loader' //根目錄新建.eslintrc.json 配置代碼規則 add eslint eslint-loader -D
],
exclude: /node_modules/
}
複製代碼
yarn add babel-polyfill 解析實例上的高級語法,在index中import進去 若是引入jquery,全局引用的話,暴露$,module中配置expose-loaderjquery
{
test: require.resolve('jquery'),
use: {
loader: 'expose-loader?$',
}
}
複製代碼
引入圖片有三種方式: 1:new Image() 2.css background:url() 3.html中建立 yarn add file-loader html-withimg-loader -Dwebpack
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader' //解決html中引入img不識別圖片的問題
},
{
test:/\.(png|jpg|gif)$/,
use: 'file-loader' //會自動建立一個MD5戳的名字,而後把圖片拷貝到打包後的dist
}
]
}
複製代碼
可是圖片過多會引發資源請求過多,所以url-loader會優化這個問題 yarn add url-loader -Dgit
{
test:/\.(png|jpg|gif)$/,
//url-loader會調用file-loader,優化:避免過多發請求,把小的圖片或icon轉換成base64,體積變大,不適用大圖片
//use: 'file-loader' //會自動建立一個MD5戳的名字,而後把圖片拷貝到dist
use: {
loader: 'url-loader',
options: {
limit: 8*1024 //小於8k的圖片會轉換成base64,避免請求
}
}
}
複製代碼
output:{},
watch:true,//實時監控
watchOptions:{
poll:1000,
aggregateTimeout: 2000,//若是2秒內沒動做,自動打包, 防抖
ignored:/node_modules/
},
module:{}
複製代碼
resolve: {
modules: [path.resolve('node_modules')],//只查找當前路徑的node_modules
extensions: ['.js','.less','.json','.css'],//引入文件時省略擴展名
alias: {//別名
componets: './src/components/'
}
}
複製代碼
1.每次打包後都會生成新的dist目錄,clean-webpack-plugin 自動清空打包後的目錄
let CleanWebpackPlugin = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin('./dist'),
]
複製代碼
let webpack = require('webpack')
plugins:[
new Webpack.DefinePlugin({ //定義環境變量
PRODUCTION:JSON.stringify('dev') // 定義PRODUCTION 是 dev環境
})
new Webpack.BannerPlugin('make by jeffywin'),//版權聲明,自帶插件
]
複製代碼
當mode爲production的時候,默認css是不壓縮的,須要插件,直接在module.export中配置optimization
let UglifyJsPlugin = require('uglifyjs-webpack-plugin')
let OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
optimization: {//優化
minimizer: [//mode必須是production纔有做用
new UglifyJsPlugin({
cache: true,
parallel: true //並行,加速壓縮
}),
new OptimizeCssAssetsPlugin({})//壓縮css
]
}
複製代碼
在一般的打包過程當中,你所引用的好比bootstrap、react、react-router、antd、vue、vue-router、vuex 等等衆多庫每次開發打包都會打包進dist目錄中,隨着文件愈來愈大,打包的時間和代碼體積也愈來愈大,因爲這些庫的內容基本不會發生改變,每次打包加入它們無疑是一種巨大的性能浪費。所以DllPlugin的出現就是解決這一問題,用某種方法實現了拆分 bundles,同時還大大提高了構建的速度。
let path = require('path')
let webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
react: ['react','react-dom',...]
},
output: {
filename: '_dll_[name].js', // 打包後的名字
path: path.resolve(__dirname,'dist'),
libraryTarget: 'commonjs2',
libraryTarget: 'var',
library: '_dll_[name]'//打包後會自動添加var _dll_[name] = {},來拿到內部的react,暴露出 (也叫作放入全局域) dll 函數
},
plugins:[
new webpack.DllPlugin({//聲明動態連接庫
name: '_dll_[name]', //暴露出的 DLL 的函數名
path: path.resolve(__dirname,'dist','mainfest.json')//manifest json 文件的絕對路徑 (輸出文件)
})
]
}
複製代碼
運行 yarn run build -- --config webpack.dll.js,會生成兩個文件
new ReferencePlugin({//開發優化 減小打包體積
manifest:path.resolve(__dirname,'dist','mainfest.json') //html中還須要全局引用
})
複製代碼
manifest包含 content 和 name 的對象,或者在編譯時(compilation)的一個用於加載的 JSON manifest 絕對路徑,也就是引用DllPlugin打包後的文件
按需打包前
總結: webpack.dll.js:DllPlugin 打包生成打包後的文件 和 mainfest.json關係映射文件
webpack.config.js: 主配置文件DllReferencePlugin經過mainfest映射到json文件,json文件調用提早打包好的緩存文件
當項目比較大時,經過happypack插件,它將任務分配給多個子進程去併發執行,子進程處理完再發給主進程,從而減小構建時間,可是項目比較小時,不建議使用,子進程分配時間反而可能增長構建時間。
使用:經過把原來module中的配置移到plugins中
let Happypack = require('happypack')
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=js',
exclude: /node_modules/,
include: path.resolve('src')
}
]
}
plugins: [
new Happypack(
{
id: "js",
use:[{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
"plugins": [
['@babel/plugin-proposal-decorators', { "legacy": true }],//解析裝飾器
['@babel/plugin-proposal-class-properties', { "loose": true }],
['@babel/plugin-transform-runtime'] //該插件依賴安裝@babel/runtime,解析高級語法,好比yiled
] //es7高級語法,順序不能變
}
}],
//'eslint-loader' //根目錄新建.eslintrc.json 配置代碼規則
}
)
]
複製代碼
繼續優化 yarn add webpack webpack-cli html-webpack-plugin @babel/core babel-loader @babel/preset-env @babel/preset-react
假如項目中引用了jquery等,能夠用noParse來不去解析有關的依賴項 還有excludes,includes
module: {
noParse: /jquery/,//不去解析jquery中的依賴項
rules: [
{
test: /\.js$/,
exclude: /node_modules/,//排除
include: path.resolve(src),//包含
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
複製代碼
假如引用了moment時間插件,會自動下載本地語言文件,致使打包文件過大,能夠用webpack自帶插件 webpack.IgnorePlugin
plugins: [
//若是引入了monent,去除掉本地的語言插件,若是須要能夠單獨引用
new webpack.IgnorePlugin(/\.\/local/,/moment/),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './public/index.html'
})
]
複製代碼
配置以後
多頁面模塊打包抽取公共代碼和第三方庫 假如同時引入了兩個文件,或者jquery等第三方庫,而且是多頁面打包,能夠將公共部分提早抽取出來打包
optimization: {
splitChunks: {
cacheGroups: {
common:{
chunks: 'initial',
minSize: 0, //超過0個字節
minChunks: 2,//用過2次以上就抽離出來
},
venor: {//第三方
priority: 1,//權重,優先抽離
test: /node_modules/,
chunks: 'initial',
minSize: 0, //超過0個字節
minChunks: 2,//用過2次以上就抽離出來
}
}
},
},
複製代碼