webpack plugin:
compression-webpack-plugin 是一个用于在 Webpack 构建过程中压缩资源文件的插件。它可以生成压缩版本的资源文件,并通过 Content-Encoding 头部来提供这些文件,从而减少文件传输的大小,提高加载速度。
npm install compression-webpack-plugin --save-dev
在 Webpack 配置文件中引入并配置该插件:
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin({
filename: '[path][base].gz', // 输出压缩文件的名称
algorithm: 'gzip', // 使用的压缩算法,默认为 'gzip'
test: /\.(js|css|html)$/, // 匹配需要压缩的文件类型
threshold: 10240, // 只压缩大于该大小的文件,默认为 0
minRatio: 0.8, // 只有压缩率大于该值的文件才会被压缩,默认为 0.8
deleteOriginalAssets: false, // 是否删除源文件
}),
],
};
image-webpack-loader 是一个用于 Webpack 的图像加载器模块,主要用于压缩和优化 PNG、JPEG、GIF、SVG 和 WEBP 格式的图像文件。它依赖于 imagemin 库来处理和压缩图片。
npm install image-webpack-loader --save-dev
在 Webpack 配置文件(通常是 webpack.config.js)中,添加以下配置来使用 image-webpack-loader:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 60 // JPG 输出的质量
},
optipng: {
enabled: true
},
pngquant: {
quality: [0.5, 0.65],
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
}
]
}
};
UglifyJS Webpack Plugin 是一个用于压缩 JavaScript 代码的 Webpack 插件。它使用 uglify-js 来最小化 JavaScript 文件,从而减少文件大小并提高加载速度。以下是如何在项目中使用该插件的详细步骤。
npm install uglifyjs-webpack-plugin --save-dev
在 Webpack 配置文件中添加该插件。以下是一个基本的配置示例:
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
optimization: {
minimizer: [new UglifyJsPlugin()],
},
};
vue.config.js 详细配置如下:
// vue.config.js
const path = require('path');
const CompressionWebpackPlugin = require("compression-webpack-plugin"); // 开启gzip压缩, 按需引用
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i; // 开启gzip压缩, 按需写入
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; // 打包分析
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV);
const resolve = (dir) => path.join(__dirname, dir);
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/site/vue-demo/' : '/', // 公共路径
indexPath: 'index.html' , // 相对于打包路径index.html的路径
outputDir: process.env.outputDir || 'dist', // 'dist', 生产环境构建文件的目录
assetsDir: 'static', // 相对于outputDir的静态资源(js、css、img、fonts)目录
lintOnSave: false, // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码
runtimeCompiler: true, // 是否使用包含运行时编译器的 Vue 构建版本
productionSourceMap: !IS_PROD, // 生产环境的 source map
parallel: require("os").cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
pwa: {}, // 向 PWA 插件传递选项。
chainWebpack: config => {
config.resolve.symlinks(true); // 修复热更新失效
// 如果使用多页面打包,使用vue inspect --plugins查看html是否在结果数组中
config.plugin("html").tap(args => {
// 修复 Lazy loading routes Error
args[0].chunksSortMode = "none";
return args;
});
config.resolve.alias // 添加别名
.set('@', resolve('src'))
.set('@assets', resolve('src/assets'))
.set('@components', resolve('src/components'))
.set('@views', resolve('src/views'))
.set('@store', resolve('src/store'));
// 压缩图片
// 需要 npm i -D image-webpack-loader
config.module
.rule("images")
.use("image-webpack-loader")
.loader("image-webpack-loader")
.options({
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: [0.65, 0.9], speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
});
// 打包分析, 打包之后自动生成一个名叫report.html文件(可忽视)
if (IS_PROD) {
config.plugin("webpack-report").use(BundleAnalyzerPlugin, [
{
analyzerMode: "static"
}
]);
}
},
configureWebpack: config => {
// 开启 gzip 压缩
// 需要 npm i -D compression-webpack-plugin
const plugins = [];
if (IS_PROD) {
plugins.push(
new CompressionWebpackPlugin({
filename: "[path].gz[query]",
algorithm: "gzip",
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8
})
);
}
config.plugins = [...config.plugins, ...plugins];
},
css: {
extract: IS_PROD,
requireModuleExtension: false,// 去掉文件名中的 .module
loaderOptions: {
// 给 less-loader 传递 Less.js 相关选项
less: {
// `globalVars` 定义全局对象,可加入全局变量
globalVars: {
primary: '#333'
}
}
}
},
devServer: {
overlay: { // 让浏览器 overlay 同时显示警告和错误
warnings: true,
errors: true
},
host: "localhost",
port: 8080, // 端口号
https: false, // https:{type:Boolean}
open: false, //配置自动启动浏览器
hotOnly: true, // 热更新
// proxy: 'http://localhost:8080' // 配置跨域处理,只有一个代理
proxy: { //配置多个跨域
"/api": {
target: "http://192.168.56.2:8080",
changeOrigin: true,
// ws: true,//websocket支持
secure: false,
pathRewrite: {
"^/api": "/"
}
},
"/api2": {
target: "http://192.168.56.2:8080",
changeOrigin: true,
//ws: true,//websocket支持
secure: false,
pathRewrite: {
"^/api2": "/"
}
},
}
}
}
其他vue.config.js 配置使用说明
// vue.config.js
const path = require('path')
const defaultSettings = require('./src/settings.js')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = defaultSettings.title || 'saas' // page title
// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following method:
// port = 9527 npm run dev OR npm run dev --port = 9527
const port = process.env.port || process.env.npm_config_port || 9527 // dev port
//const CompressionWebpackPlugin = require("compression-webpack-plugin"); // 开启gzip压缩, 按需引用
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV);
// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
/**
* You will need to set publicPath if you plan to deploy your site under a sub path,
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
* then publicPath should be set to "/bar/".
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
* // process.env.NODE_ENV === 'development'
*/
publicPath: './',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: false, // 代码规范实时验证
// lintOnSave: process.env.NODE_ENV !== 'production',
productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建
devServer: {
open: true,
overlay: {
warnings: false,
errors: true
},
// proxy: {
// '/v1': {
// target: 'http://192.168.56.2:8080', // 要请求的地址
// ws: true,
// changeOrigin: true
// // pathRewrite: {
// // '^/v1': ''
// // }
// }
// },
before: require('./mock/mock-server.js')
},
//
configureWebpack:config=> {
config.name = name
//取消webpack警告的性能提示
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
config.performance = {
hints: 'warning',
//入口起点的最大体积 整数类型(以字节为单位)
maxEntrypointSize: 50000000,
//生成文件的最大体积 整数类型(以字节为单位 300k)
maxAssetSize: 30000000,
//只给出 js 文件的性能提示
assetFilter: function (assetFilename) {
return assetFilename.endsWith('.js');
}
}
config.resolve = {
alias: {
'@': resolve('src')
}
}
//
if(IS_PROD){
console.log("生产环境.....")
//开启gzip压缩: 需要安装依赖 npm install compression-webpack-plugin@5.0.0 -S -D
// config.plugins.push(new CompressionWebpackPlugin({
// algorithm: 'gzip',
// test: /\.js$|\.html$|\.json$|\.css/,
// threshold: 10240,
// minRatio: 0.8,
// }))
}
},
chainWebpack:config=>{
// it can improve the speed of the first screen, it is recommended to turn on preload
// it can improve the speed of the first screen, it is recommended to turn on preload
config.plugin('preload').tap(() => [
{
rel: 'preload',
// to ignore runtime.js
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
include: 'initial'
}
])
// when there are many pages, it will cause too many meaningless requests
config.plugins.delete('prefetch')
// set svg-sprite-loader
config.module.rule('svg').exclude.add(resolve('src/icons')).end()
config.module.rule('icons')
.test(/\.svg$/).include.add(resolve('src/icons')).end()
.use('svg-sprite-loader').loader('svg-sprite-loader')
.options({symbolId: 'icon-[name]'}).end()
// videoPlayer
config.module.rule('swf').test(/\.swf$/).use('url-loader').loader('url-loader').options({limit: 10000}).end()
//
config.when(process.env.NODE_ENV !== 'development', config => {
config.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}]).end()
console.log("chainWebpack... production")
//开启分离js
// https://webpack.js.org/configuration/optimization/#optimizationruntimechunk
config.optimization.runtimeChunk('single')
config.optimization.splitChunks({
chunks: 'all',
maxInitialRequests:Infinity,
minSize: 20000,
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
},
// vendor: {
// test: /[\\/]node_modules[\\/]/,
// name( module ) {
// // get the name. E.g. node_modules/packageName/not/this/part.js
// // or node_modules/packageName
// const packageName = module.context.match( /[\\/]node_modules[\\/](.*?)([\\/]|$)/ )[ 1 ]
// // npm package names are URL-safe, but some servers don't like @ symbols
// return `npm.${ packageName.replace( '@', '' ) }`
// },
// }
}
})
})
}
}
//去掉console.log、警告、注释、debugger
//线上去掉查看源码功能:sourceMap:false
//压缩代码
//config/index.js中build部分:
//productionGzip: true,
//productionGzipExtensions: ['js', 'css'],
new UglifyJsPlugin({
uglifyOptions: {
output:{
comments:false,
},
compress: {
warnings: false,
drop_console: true,
drop_debugger:true,
pure_funcs: ['console.log']
}
},
cache: true,
parallel: true,
sourceMap: false // set to true if you want JS source maps
}),
// 分包配置:
// splitChunks是用来设置代码如何打包和分割的,现就webpack官网提供的默认参数详细解释一下每个参数配置的含义以及使用场景。官网链接:https://www.webpackjs.com/plugins/split-chunks-plugin/
/**
* webpack中实现代码分割的两种方式:
* 1.同步代码:只需要在webpack配置文件总做optimization的配置即可
* 2.异步代码(import):异步代码,无需做任何配置,会自动进行代码分割,放置到新的文件中
*/
optimization: {
splitChunks: {
chunks: "all", //async异步代码分割 initial同步代码分割 all同步异步分割都开启
minSize: 30000, //字节 引入的文件大于30kb才进行分割
//maxSize: 50000, //50kb,尝试将大于50kb的文件拆分成n个50kb的文件
minChunks: 1, //模块至少使用次数
maxAsyncRequests: 5, //同时加载的模块数量最多是5个,只分割出同时引入的前5个文件
maxInitialRequests: 3, //首页加载的时候引入的文件最多3个
automaticNameDelimiter: '~', //缓存组和生成文件名称之间的连接符
name: true, //缓存组里面的filename生效,覆盖默认命名
cacheGroups: { //缓存组,将所有加载模块放在缓存里面一起分割打包
vendors: { //自定义打包模块
test: /[\\/]node_modules[\\/]/,
priority: -10, //优先级,先打包到哪个组里面,值越大,优先级越高
filename: 'vendors.js',
},
default: { //默认打包模块
priority: -20,
reuseExistingChunk: true, //模块嵌套引入时,判断是否复用已经被打包的模块
filename: 'common.js'
}
}
}
}
splitChunks基本配置
chunks:分割代码的模式
async 异步代码分割模式:只分割出异步引入的模块
异步代码指的是异步引入的代码模块单独打包成一个或多个文件,下面是异步引入的例子:
//异步加载模块
function getComponent () {
return import(/* webpackChunkName:"lodash" */ 'lodash').then(({ default: _ }) => {
var element = document.createElement('div')
element.innerHTML = _.join(['Dell', ' ', 'Lee', '-'])
return element
})
}
getComponent().then(el => {
document.body.appendChild(el)
})
initial 同步代码分割模式:只分割同步引入的模块
同步代码引入方式:
//同步加载模块
import _ from 'lodash' //第三方库
import test from './test.js' //业务代码
import jquery from 'jquery' //第三方库
console.log(test.name)
var element = document.createElement('div')
element.innerHTML = _.join(['Dell', ' ', 'Lee', '-'])
document.body.appendChild(element)
console.log(jquery('div'))
all 同步异步都分割模式:在所有配置条件都满足的情况下,无论如何引入模块都会进行分割
2.minSize和maxSize(单位:字节)
minSize指的是引入的模块的最小值
maxSize指的是引入的模块的最大值,当引入的模块大小大于最大值时,weback会尝试将这个模块以最大值为准分割成多个模块,前提是这个模块可以分割,比如lodash的提交大于50KB,那么设置maxSize:5000时,依然打包出一个文件来,故此属性一般不用
3.minChunks:模块至少使用次数
当值为2时,代表只引用了一次的模块不做分割打包处理
4.maxAsyncRequests:同时加载的模块数量最大值
当需要分割的模块同步引入个数超出限时时,webpack之后分割限制值的模块,其它的将不做处理
5.maxInitialRequests:首次加载引入模块可分割的最大值
6.automaticNameDelimiter:缓存组名称和生成文件名称之间的连接字符串
7.name: 设置为true时,缓存组里面的filename生效,覆盖默认命名方式
//
cacheGroups缓存组
cacheGroups: { //缓存组,将所有加载模块放在缓存里面一起分割打包
vendors: { //自定义打包模块
test: /[\\/]node_modules[\\/]/,
priority: -10, //优先级,先打包到哪个组里面,值越大,优先级越高
filename: 'vendors.js',
},
default: { //默认打包模块
priority: -20,
reuseExistingChunk: true, //模块嵌套引入时,判断是否复用已经被打包的模块
filename: 'common.js'
}
}
vendors为自定义打包模块,当vendors.test设置为/[\/]node_modules[\/]/,webpack将把使用npm命令安装的第三方库打包到vendors缓存组里面。
1.test:正则匹配打包分离的文件条件
2.priority:定义打包组的打包顺序优先级,值越大,优先级越高
3.filename:打包模块输出的文件名,默认为 缓存组名称(vendors) + 连接字符串(automaticNameDelimiter) + 模块入口文件(main.js) 例如:vendors~main.js
default为默认模块打包的缓存组,一般情况下打包业务模块编码。
reuseExistingChunk:模块嵌套引入时,判断是否复用已经被打包的模块