webpack4 打包优化
1 参考文章
详解webpack4之splitchunksPlugin代码包分拆
开发工具心得:如何 10 倍提高你的 Webpack 构建效率
2: webpack4中的 optimization.runtimeChunk的作用是什么?
首先看参考文章:
优化持久化缓存的, runtime 指的是 webpack 的运行环境(具体作用就是模块解析, 加载) 和 模块信息清单,
模块信息清单在每次有模块变更(hash 变更)时都会变更, 所以我们想把这部分代码单独打包出来,
配合后端缓存策略, 这样就不会因为某个模块的变更导致包含模块信息的模块(通常会被包含在最后一个 bundle 中)缓存失效.
optimization.runtimeChunk 就是告诉 webpack 是否要把这部分单独打包出来.
假设一个使用动态导入的情况(使用import()),在app.js动态导入component.js
const app = () =>import('./component').then();
build之后,产生3个包。
0.01e47fe5.js
main.xxx.js
runtime.xxx.js
其中runtime,用于管理被分出来的包。下面就是一个runtimeChunk的截图,可以看到chunkId这些东西。
...
function jsonpScriptSrc(chunkId) {
/******/ return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"01e47fe5"}[chunkId] + ".bundle.js"
/******/ }
...
如果采用这种分包策略
当更改app的时候runtime与(被分出的动态加载的代码)0.01e47fe5.js的名称(hash)不会改变,main的名称(hash)会改变。
当更改component.js,main的名称(hash)不会改变,runtime与 (动态加载的代码) 0.01e47fe5.js的名称(hash)会改变。
总结一下:
runtime.js文件相当于动态文件的索引文件,相当于一个文件夹中的index索引文件,告诉main.js要引用的文件的名字
这样app.js 变化的时候 由于不影响 componment.js 所以生成的0.01.js 和runtime.js 不会发生变化;
当 componment.js 发生变化的时候,生成的0.01.js要发生变化,同时索引文件 runntime.js 也会发生变化。但是main.js引用的是runntime.js 则不会发生变化
---
3 使用 splitchunksPlugin 提取公共代码
optimization:{
splitChunks: {
chunks: 'all',//同步异步全都打包
minSize: 30000,//打包的库或者文件必须大于这个字节才会进行拆分
minChunks: 1,//规定当模块在生成的js文件(trunk)中被调用过多少次的时候再进行拆分
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',//如果不写filename 默认名字 组名~[name]
name: true,
cacheGroups: {//缓存组,因为需要打包完成之后,在把所有要拆分的代码合并拆分,所以先要缓存
vendors: {
test: /[\\/]node_modules[\\/]/, //如果上面chunks定为all,就是找到所有的import文件,看他是不是调用于 node_modules 文件夹 是的话就拆分
priority: -10,//优先级 比如同时符合vender 和 default 这个优先级高 所以存在这里
filename: 'vendors.js', //拆分后打包的文件名字
},
default: {//像文件中 import进来的文件 如果不在 node_modules文件夹中 则走默认组,打包出的文件名字是 common.js
priority: -20,
minChunks: 2,
reuseExistingChunk: true,//比如a.js 引用了 b.js;如果b.js在之前已经被拆分过,则这里不再对其进行拆分
filename: 'common.js'
}
}
}
}
为了支持异步js,
npm install --save-dev @babel/plugin-syntax-dynamic-import
记得修改 .babelrc
{
"presets":[
["@babel/preset-env",{
"useBuiltIns":"usage",
"corejs":2,
"targets":{
"browsers":[">1%","last 2 version","not ie <= 8"]
}
}]
],
"plugins": ["@babel/plugin-syntax-dynamic-import"]
}
注意:
4: 使用 DLLPlugin 提取第三方不变化的代码库:
DLLPlugin 它能把第三方库代码分离开,并且每次文件更改的时候,它只会打包该项目自身的代码。所以打包速度会更快。
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); module.exports = {
mode:'production',
// 入口文件
entry: {
// 项目中用到该两个依赖库文件
vue: ['vue']
},
// 输出文件
output: {
// 文件名称
filename: '[name].dll.js',
// 将输出的文件放到dist目录下
path: path.resolve(__dirname, '../static'), /*
存放相关的dll文件的全局变量名称,比如对于jquery来说的话就是 _dll_jquery, 在前面加 _dll
是为了防止全局变量冲突。
*/
library: '[name]_library'
},
plugins: [
new CleanWebpackPlugin(), //注意在webpack4 中 不需要定于删除哪个文件夹 默认会根据output中生成的path路径删掉
// 使用插件 DllPlugin
new DllPlugin({
/*
该插件的name属性值需要和 output.library保存一致,该字段值,也就是输出的 manifest.json文件中name字段的值。
比如在jquery.manifest文件中有 name: '_dll_jquery'
*/
name: '[name]_library',
context:__dirname, //context (可选): manifest文件中请求的上下文,默认为该webpack文件上下文
/* 生成manifest文件输出的位置和文件名称 */
path: path.join(__dirname, '../static/', '[name].manifest.json')
})
]
};
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const proConfig = {
plugins:[
new DllReferencePlugin({
context:__dirname,
manifest:require('../static/vue.manifest.json')
})
]
}
然后增加 package.json 文件:
"dll": "webpack --config ./build/webpack.dll.js --hide-modules --progress"
最后在模版文件中增加引用:
<script type="text/javascript" src="../static/vue.dll.js"></script>
所以先执行 npm run dll,在执行npm run build
但是这样修该模版文件不太好,所以引入插件:
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
plugins:[
new AddAssetHtmlPlugin({
filepath: require.resolve('../static/vue.dll.js'),//相当于path.join(__dirname, '../static/vendordev.dll.js')
includeSourcemap: false
})
]
注意:
1: html-webpack-include-assets-plugin 和 add-asset-html-webpack-plugin 的区别
两个插件都是把规定的文件插入到html中:
主要的不同是 html-webpack-include-assets-plugin 不会copy文件,而 add-asset-html-webpack-plugin 会copy文件,什么意思呢?
使用 add-asset-html-webpack-plugin 后,会把引入的 filepath: require.resolve('../static/vue.dll.js') 自动引入到 dist 文件夹中,而 html-webpack-include-assets-plugin 则不会;
所以在dev环境下,直接把vue.dll.js 引入dist目录下即可,所以使用 add-asset-html-webpack-plugin;而在production环境下,要把 vue.dll.js 放在dist/lib 文件夹下,所以使用CopyWebpackPlugin 复制vue.dll.js文件,配合 html-webpack-include-assets-plugin 插入html中;
所以分为dev和product环境:
const htmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin'); //dev环境中,该插件会把 vue.dll.js 文件复制到当前路径下
new AddAssetHtmlPlugin({
filepath: require.resolve('../static/vue.dll.js'),//相当于path.join(__dirname, '../static/vendordev.dll.js')
includeSourcemap: false,
}), //production 环境中
// 1 需要把 dll 文件复制到打包的 dist/lib 文件夹下 -- CopyWebpackPlugin
// 2 html中引入 dist/lib 下的dll 文件 -- htmlWebpackIncludeAssetsPlugin new htmlWebpackIncludeAssetsPlugin({ //这个插件是把vue.dll.js 插入到 html 中
assets:['./lib/vue.dll.js'],
append:false
}),
new CopyWebpackPlugin([ //文件复制到打包的 dist/lib 文件夹下
{ from: path.join(__dirname, "../static/vue.dll.js"), to: path.join(__dirname, "../dist/lib/vue.dll.js") }
]),
注意2:
这里引入 AddAssetHtmlPlugin 你会发现即使不使用:
new DllReferencePlugin({
context:__dirname,
manifest:require('../static/vue.manifest.json')
})
页面也可以使用vue。
那么 DllReferencePlugin 的作用是什么呢?
我们看打包生成的文件:
情况1: 不使用 DllReferencePlugin:
可以看出,index.js 文件中使用的vue居然还是来自 node_modules 说明并没有把vue第三方库剔除;
对比使用DllReferencePlugin :
发现index中已经没有 vue 第三方库,但是页面仍旧能打开,说明使用的是 dll 文件。
再来看 DllReferencePlugin 的作用:
有了映射文件,在webpack打包的时候就可以结合映射文件以及生成的全局变量,来对需要打包的源代码进行分析。
一旦发现你打包的源代码里面用到了映射文件中已有的文件,则直接使用vendors.dll.js 中的内容,而不会去node_modules里引入该模块
5. 引入的loader一定要加上 exclude和include 可以大幅降低打包的代码文件大小
6. 使用别名优化:
resolve:{
extensions:['.js','.vue','.json'],
alias:{
"@":path.resolve('src')
}
}
使用extensions省略后缀名字;使用alias给src加上别名,这样可以简化html中的路径,比如:
pages/index/index.vue 中要使用 assest/imgs/logo.png 的图片:
<img src="../../assest/imgs/logo.png" alt="" class="img-box">
可以简化成:
<img src="@/assest/imgs/logo.png" alt="" class="img-box">
类似的:
//简化前
import Chinese from '../../component/chinese.vue';
//简化后
import Chinese from '@/component/chinese.vue';
但是对于css注意,在引用路径的字符串前面加上 ~ 的符号,如:@import “~Css/…”。webpack 会以~符号作为前缀的路径视为依赖模块去解析
background: url('~@/assest/imgs/logo.png');
代码:
import VueRouter from 'vue-router'
import routers from './routers' Vue.use(VueRouter) const router = new VueRouter({
mode: 'history',
routers
})
原因:
routes:不是routers
解决办法:
routers改为routes即可。
8.解决webpack中css独立成文件后图片路径错误的问题
说明:此配置针对webpack4+
配置img图片路径问题:
output:{
filename:'js/[name].[chunkhash].js',
path:path.resolve(__dirname,'../dist'),
},
//module
{
test:/\.(png|gif|jpeg|jpg)$/,
use:[
{
loader:'url-loader?cacheDirectory=true',
options:{
name:'img/[name].[ext]',
limit:1024
}
}
]
},
//plugins
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : 'css/[name].[contenthash].css',
chunkFilename: devMode ? '[name].css' : 'css/[name].[contenthash].css',
})
生成的图片会在css文件中: css/img/logo.png 这样的话 找不到该图片,因为生成的图片路径应该是 img/logo.png
如果修改output的配置中加入一个 publicPath: '../' 配置,则所有的css文件和js的路径都会变化,所以应该只处理css文件,设置css文件中的公共路径:
output:{
filename:'js/[name].[chunkhash].js',
path:path.resolve(__dirname,'../dist'),
},
//module
{
test:/\.scss$/,
use:[
{
loader:MiniCssExtractPlugin.loader,
options:{
publicPath:'../'
}
},
{
loader:'css-loader',
options:{
importLoaders:2,
}
},
'postcss-loader',
'sass-loader'
]
},
{
test:/\.(png|gif|jpeg|jpg)$/,
use:[
{
loader:'url-loader?cacheDirectory=true',
options:{
name:'img/[name].[ext]',
limit:1024
}
}
]
},
//plugins
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : 'css/[name].[contenthash].css',
chunkFilename: devMode ? '[name].css' : 'css/[name].[contenthash].css',
})
9 为了避免不同路由页面间样式冲突,css样式要加 scoped
import Home from "./view/home";
const ProInsight = () => import(/* webpackPrefetch: true */ /* webpackChunkName: 'proInsight' */ "./view/proInsight");
const ProTarget = () => import(/* webpackPrefetch: true */ /* webpackChunkName: 'proTarget' */ "./view/proTarget"); Vue.use(VueRouter); const routes = [
{ path: "/", name: "home", component: Home },
{ path: "/proInsight", name: "proInsight", component: ProInsight },
{ path: "/proTarget", name: "proTarget", component: ProTarget }
];
中,首页入口 home文件没有使用异步加载,则该组件所有引用的公共代码,都会被打包到home中,而不会提取出来,
所以,home这个组件也要改成异步加载的形式。这样所有的公共代码才能被提取出来。


stats: {
warningsFilter: (warning) => /Conflicting order between/gm.test(warning),
children: false
}
webpack4 打包优化的更多相关文章
- vue cli3使用webpack4打包优化
去掉console.log,以及开启gzip const CompressionPlugin = require('compression-webpack-plugin');//引入gzip压缩插件 ...
- webpack4.0打包优化策略整理小结
本文转载于:https://www.jb51.net/article/137449.htm 介绍了webpack4.0打包优化策略整理小结,分享给大家,具体如下: webapck4 新特性介绍-参考资 ...
- webpack4打包nodejs项目进阶版——多页应用模板
前段时间我写了个打包nodejs项目的文章,点击前往 但是,问题很多.因为之前的项目是个历史遗留项目,重构起来可能会爆炸,当时又比较急所以就写个的适用范围很小的webpack的打包方法. 最近稍微得空 ...
- 多页应用 Webpack4 配置优化与踩坑记录
前言 最近新起了一个多页项目,之前都未使用 webpack4 ,于是准备上手实践一下.这篇文章主要就是一些配置介绍,对于正准备使用 webpack4 的同学,可以做一些参考. webpack4 相比之 ...
- webpack 打包优化的四种方法(多进程打包,多进程压缩,资源 CDN,动态 polyfill)
如今,webpack 毫无疑问是前端构建领域里最耀眼的一颗星,无论你前端走哪条路线,都需要有很强的webpack 知识.webpack 的基本用法这里就不展开讲了.主要探讨一下如何提高 webpack ...
- 小型Web页打包优化(下)
之前我们推送了一篇小型Web项目打包优化文章,(链接),我们使用了一段时间, 在这过程中我们也一直在思考, 怎么能把结构做的更好.于是我们改造了一版, 把可以改进的地方和可能会出现的问题, 在这一版中 ...
- 记一次webpack打包优化
未进行打包优化的痛点: 随着项目的不断扩大,引入的第三方库会越来越多,我们每次build的时候会对所有的文件进行打包,耗时必定很长,不利于日常开发. 解决思路: 第三方库我们只是引入到项目里来,一般不 ...
- webpack原理探究 && 打包优化
在做vue项目和react项目时,都用到了webpack.webpack帮助我们很好地提高了工作效率,但是一直以来没有对其原理进行探究,略有遗憾. 因为使用一个工具,能够深入了解其原理才能更好地使用. ...
- VUE_shop(第十天)项目的打包优化
项目的打包优化 1.添加页面的加载效果 1.首先安装运行依赖nprocess,在main.js文件中的axios拦截器拦截请求的时候调用Npeocees.start. 在拦截响应的时候调用nproce ...
随机推荐
- .net core中关于System.Text.Json的使用
在.Net Framework的时候序列化经常使用Newtonsoft.Json插件来使用,而在.Net Core中自带了System.Text.Json,号称性能更好,今天抽空就来捣鼓一下. 使用起 ...
- linux ubuntu 网卡配置---固定IP
需要修改/etc/network/interfaces和/etc/resolvconf/resolv.conf.d/base两个文件. 1) /etc/network/interfaces文件: 首先 ...
- [ES] - 图形化界面工具
推荐更新: Windows平台为 ElasticSearch 6.x 安装 Head 客户端插件 elasticsearch-head A web front end for an Elasticse ...
- Quartz.Net—JobBuilder
JobBuilder JobBuilder是一个建造者模式,链式建造.通过静态方法构建一个JobBuilder实例,然后再调用类方法Build()创建一个IJobDetail的实现. 1.静态方法 p ...
- django初识1
django django初识 django的本质就是基于socket通信 一.127.0.0.1 本地回环地址 后面:8001是端口号 /ppt是根目录下的ppt子网页 二./当前网站的客户端(根目 ...
- python学习-57 logging模块
logging 1.basicConfig方式 import logging # 以下是日志的级别 logging.debug('debug message') logging.info('info ...
- 网络地址转换(NAT)
NAT是解决ipv4地址短缺的方案之一 NAT是将位于子网中的主机与外网连通,子网中所有的主机都可以通过路由器的网络地址转换访问外网.对于外网来说该路由器相当于一台完整的主机,子网内所有主机对外网的访 ...
- hadoop mapper reducer
Local模式运行MR流程------------------------- 1.创建外部Job(mapreduce.Job),设置配置信息 2.通过jobsubmitter将job.xml + sp ...
- RMAN备份,catalog注册rman带库备份信息
客户需求:测试恢复的过程中,控制文件是全备时期的,recover database无法恢复到指定日期,控制文件中缺失后续新的归档备份信息. 方法:1.控制文件rman注册后续带库中的归档备份: 2.使 ...
- docker 启动 容器----bootstrap checks failed
错误信息: bootstrap checks failed 解决方法: 1.修改elasticsearch.yml配置文件,允许外网访问. vim config/elasticsearch.yml,增 ...