speed-measure-webpack-plugin是一款能检测Loader和Plugin耗时的插件,具体的用法就不再阐述了,可以去https://www.npmjs.com/package/speed-measure-webpack-plugin这看看
我们通常使用Loader去加载webpack不能识别的文件,例如.css .vue文件等,但是这个加载过程是一个挺耗时的过程。
因此,在loader的配置中我们可以通过设置:
{
test: /.js$/, //ES6的babel
include:path.resolve('src'), //只加载src下的.js文件
use: 'babel-loader',
},
{
test: /.js$/, //ES6的babel
include:path.resolve('src'), //只加载src下的.js文件
use: 'babel-loader',
exclude:/node_modules/ //解析时忽略node——modules
},
webpack的寻找模块的文件机制一般是由内置的JavaScript解析器决定的
import "D:\vueProject\webpack\commons"
import "./src/commons"
import "vue"
(具体的模块解析请看这里https://webpack.docschina.org/concepts/module-resolution)
你可以通过resolve去修改默认的查找规则,我们可以优化resolve的配置,达到减小webpack搜索文件范围的目的。
具体策略为:
resolve:{
//利用resolve模块减少文件查找
alias:{
'vue':path.resolve(__dirname,'./node_modules/vue/dist/vue.min.js'), //对于像常用的模块,我们可以定义在alias中,直接去该路径下查找该模块,减少查找模块的时间
},
}
resolve:{
//利用resolve模块减少文件查找
modules:["path.resolve(__dirname, 'src')","node_modules"]
}
使用本方法优化时,需要考虑到所有运行时依赖的第三方模块的入口文件的描述字段, 就算只有一个模块出错,也可能会造成构建出的代码无法正常运行。-----《深入浅出Webpack》
resolve:{
//利用resolve模块减少文件查找
mainFields:['main'] //查找package.json中的main字段 根据main字段就可以直接找到入口了,因为大多数第三方模块都是main为入口文件
}
resolve:{
//利用resolve模块减少文件查找
extensions:['.js','.json'], //先查找.js后缀的文件,再去查找.json后缀的文件
}
假设有一个模块 import “./data” —当我们设置了上面的extensions规则之后,先去对应文件夹查找data.js,找不到再去查找data.json。
假设我们已经直到data就是一个js文件,那么,我们该直接补全后缀。
import "./data.js"
module.noParse可以帮我忽略掉那些没有采用模块化的模块,因为像一些工具库,Jquery等没有采用模块化,让webpack去解析这个模块,很是浪费时间
module:{
noParse:[/jquery\.min\.js$/], //不去解析jquery 没用且浪费时间
}
在webpack系列项目中,如果开启了缓存,那么就会在node_modules下生成一个.cache文件夹
babel-loader常用于解析.js文件,将高版本的JS语法,例如ES6转换成低版本的语法。我们可以针对babel-loader去进行缓存的操作,使得打包速度加快
{
//之前提到的针对Loader的匹配规则去优化打包速度
test: /.js$/, //ES6的babel
include:path.resolve('src'), //只加载src下的.js文件
use: [{
loader:'babel-loader',
options:{
cacheDirectory:true //开启缓存,将在node_modules/.cache生成对应的缓存文件
}
}],
exclude:/node_modules/ //解析时忽略node——modules
},
webpack4中推荐使用ter-webpack-plugin进行缓存,在webpack4中有一个配置optimization,它会根据mode不同去进行一个代码的压缩优化,我们可以通过传入一个new TerSerPlugin(…)去覆盖webpack默认的压缩工具
optimization: {
minimizer: [
new TerserPlugin({
cache:true, //开启缓存
}),
],
cached-loader可以帮助性能开销较大的Loader,将结果缓存到磁盘中,请将cache-loader,放在别的Loader之后执行
但是如果是性能开销小的Loader去使用的话,那么就会变得更慢了
请注意,保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用此 loader。–webpack官网
{
test: /.js$/, //ES6的babel
include:path.resolve('src'), //只加载src下的.js文件
//loader执行顺序从右到左
use: ['cache-loader','babel-loader']
}],
exclude:/node_modules/ //解析时忽略node——modules
},
这是一个经常用到的缓存策略,单独配置一个webpack配置,将公共资源打包出来,等我们正式打包发布的时候,直接引用就好了,如此一来经过我们预编译打包的模块就不需要经过webpack打包
const path=require('path');
const webpack=require('webpack')
module.exports={
entry:{
library:[ //要分离的包
'vue' //这里我只打包了vue 其实也可以将我们业务中常用到的工具包打包
]
},
output:{
filename:'[name]_[hash:6].dll.js', //文件指纹 方便检测文件有没有被修改过
path:path.join(__dirname,"commons/library"), //生成的文件路径
library:'[name]' //分离包暴露模块的名字
},
plugins:[
new webpack.DllPlugin({
//分包
name:'[name]', //文件名
path:path.join(__dirname,"commons/library/[name].json"), //生成的json 供DllReferencePlugin使用
})
]
}
经过上面的打包,在comms/library/下生成一个library_[hash:6].dll.js和library.json文件
下一步我们将根据这个library.json文件,直接找到我们预编译好的包
module.exports={
plugins:[
new webpack.DllReferencePlugin({
manifest:require('./commons/library/library_[has:6].json') //引入经由DLLPlugin生成的json文件 同样的带上了文件指纹
}),
]
}
webpack时运行在Node环境中的,JS是单线程的,任务是一个接着一个的处理,有什么办法能让webpack在同个时间段,执行多个任务呢?答案就是使用HappyPack。
modules.rules={
test: /.js$/,
include:path.resolve('src'), //只加载src下的.js文件
use:[’happypack/loader?id=babel ’],
exclude:/node_modules/ //解析时忽略node——modules
},
plugins:[
new HappyPack ( {
//用唯一的标识符 id,来代表当前的 HappyPack 是用来处理一类特定的文件的
id: ’ babel ’, // 如何处理. j s 文件,用法和 Loader 配置中的一样
loaders: [ ’ babel-loader?cacheDirectory’] , //. .. 其他配置项 }) ,
]
原理:因为loader是对文件的读写操作,特别耗时,HappyPack的原理就是将这些操作分解到多个进程去并行处理,缩短总的构建时间
打包体积关系到我们一个项目性能的好坏,首屏优化,资源压缩等。
常用的打包体积分析插件就是:webpack-bundle-analyzer,具体用法就不说了,可以去这看:https://www.npmjs.com/package/webpack-bundle-analyzer
将代码压缩,资源压缩,项目的体积更小,速度更快。
我们都知道,在webpack中,使用Loader去解析除了 .js 和 .json 之外的文件,其实这些文件也提供了很多的压缩选项,也有很多的plugin能帮我们压缩各种资源。
使用optimize-css-assets-webpack-plugin结合cssnano压缩css代码
plugins:[
new OptimizeCSSAssetsPlugin({
assetNameRegExp:/\.css$/g, //要解析的css文件匹配规则,尽可能的精准 避免webpack不必要的工作
cssProcessor:require('cssnano') //使用cssnano工具进行css压缩
}),
]
加粗样式
如果是webpack4.x以上的版本的话,那么mode="production"是会自动开启uglifyPlugin的
使用uglifyPlugin进行JS文件的压缩,
图像压缩的plugin和loader很多,这里只提一个常用的url-loader:https://www.webpackjs.com/loaders/url-loader
{
test:/\.(png|jpg|jpeg)$/,
use:[
{
loader: 'url-loader',
options:{
name:'[name]_[hash:6].[ext]',
limit:10*1024, //小于10*1024字节即10kb时,就将图片转换成base64嵌入html中
},
},
}
mode="production"时,默认关闭source-map
有这么一个需求,当A页面引用了C模块,B页面也引用了C模块,那么对于这个C模块,我们就可以叫做公共模块,webpack会重复打包C模块,那么我们就可以使用SplitChunksPlugin去将C模块打包出来,避免重复打包的情况
相关配置:https://webpack.docschina.org/plugins/split-chunks-plugin/#src/components/Sidebar/Sidebar.jsx
splitChunks: {
chunks:"all", //打包模块的类型:同步模块(initial),异步模块(async) all为所有模块
//同步模块---一般就是直接执行文件,例如入口文件等
//异步模块---import("vue")等
minSize: 0, //引用的块的大小,直接大于这个就直接打包,设置为0为怎么样都打包
cacheGroups: {
//打包的模块
commons: {
//打包的commons模块
name: 'commons', //commons模块的name
minChunks: 2 //引用次数为2 采取实现打包 例如A模块引用C模块,B模块也引用C模块,那么对于C模块来说就是引用了两次
}
}
},
要注意,如果是webpack4.0以下的版本,提取公共代码用CommonsChunkPlugin
在打包生产环境时,我们可以将一些比较大的模块,例如Vue、React等采取CDN引入的方式,如此一来就能缩小我们的项目大小了。
html-webpack-externals-plugins—将某个模块,替换成CDN资源:https://www.npmjs.com/package/html-webpack-externals-plugin
webpack.pro.js
new HtmlWebpackExternalsPlugin({
externals:[
{
module:'Vue', //打包模块名称
entry:'//cdn.bootcss.com/vue/2.6.11/vue.common.dev.js', //输出CDN资源
global:'Vue' //全局名称
}
]
})
index.html-----使用EJS语法引入
<!DOCTYPE html>
<html lang="en">
<head>
<title>webpack</title>
<script type="text/script" src='https//cdn.bootcss.com/vue/2.6.11/vue.common.dev.js'></script>
</head>
<body>
<div id='search'>
<p>search页</p>
</div>
</body>
</html>
比如我们正在写一个多页面应用,此时我们index.html页面需要一大串的meta,search.html也需要同样的meta,那么我们就可以使用html-webpack-plugin中的EJS语法+raw-loader,直接引入一个meta.html。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<%= require('raw-loader!./meat.html') %>
<title>webpack</title>
</head>
<body>
<div id='search'>
<p>search页</p>
</div>
</body>
</html>
meta.html
<meta charset="UTF-8">
<meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="keywords" content="now,now直播,直播,腾讯直播,QQ直播,美女直播,附近直播,才艺直播,小视频,个人直播,美女视频,在线直播,手机直播">
<meta name="name" itemprop="name" content="NOW直播—腾讯旗下全民视频社交直播平台">
<meta name="description" itemprop="description"
content="NOW直播,腾讯旗下全民高清视频直播平台,汇集中外大咖,最in网红,草根偶像,明星艺人,校花,小鲜肉,逗逼段子手,各类美食、音乐、旅游、时尚、健身达人与你24小时不间断互动直播,各种奇葩刺激的直播玩法,让你跃跃欲试,你会发现,原来人人都可以当主播赚钱!">
<meta name="image" itemprop="image"
content="https://pub.idqqimg.com/pc/misc/files/20170831/60b60446e34b40b98fa26afcc62a5f74.jpg">
<meta name="baidu-site-verification" content="G4ovcyX25V">
<meta name="apple-mobile-web-app-capable" content="no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
将用到的方法,模块打包,不用到的方法或者模块就不打包
根据DCE的规则去执行,当满足DCE的代码或者模块就不去打包。
在ES6的模块机制下才有效,因为ES6的模块机制是静态的不是动态的,DCE匹配的代码会在uglify阶段被擦除,不会被打包。
DCE规则
4. 代码不被执行,不会被到达的
5. 代码执行结果不会被用到的
6. 代码只写不读的
在webpack4.x以上的版本中,当mode==“pdoduction”,默认开启,即生产模式自动开启,若想在开发环境开启,那么就需要.babelrc里设置modules:false即可
webpack打包会生成各种闭包,导致内存泄漏,运行开销增大,体积增大,所以我们要使用scope hoisting 来重新构建webpack。
将模块代码按照引用顺序放在一个函数作用域中,然后适当命名解决冲突
module.exports = {
resolve: {
//针对 Npm 中的第二方模块优先采用 j snext :main 中指向的 ES6 模块化语法的文件
mainFields: [’ j snext :main ’,’browser’,’main ’]
plugins: [
new ModuleConcatenationPlugin( ), ]//开启 Scope Hoisting
}
大型网站,不单单只是单页面,其实每一个页面都是一个单页面,如果这些单页面之间采用了相同的技术栈和相同的代码,相同的样式,那么代码重复率就特别高,这会产生以下问题
相同代码重复被执行,影响效率,浪费用户流量和服务器成本
页面加载资源大,首屏时间慢
那么将页面之间共有的代码抽离成公共代码就尤为重要,这么做的好处有:
加快访问时间,例如当刚进入页面就开始加载公共代码,设置缓存,那么再去访问网站的另一个页面,就不需要再去请求公共代码,直接从缓存中获取
减少服务器压力,减少用户流量和带宽,因为第一次进入时,已经缓存了公共代码,那么,访问该网站别的页面时,就不需要去请求公共代码
当确定一个网站需要的技术栈之后,我们可以将公共代码分成:
这个库是存放一些业务模块的代码,例如utils模块的代码等,这个库主要的特点是,内容经常更新,commos.js
这个库是存放一些项目必须的依赖模块,例如:当一个网站是以vue框架开发的,一个大型网站不单单只是一个单页面应用,很可能有多个入口,但是这些应用的特点就是,共同使用vue开发,那么vue就是这个项目的基础库,这个库的特点就是内容不经常更新,是多页页面共同用到的模块。base.js
为每一个经由webpack打包生成的文件的文件名,添加一个hash值,标识当前唯一的文件,一般而言是:[name]_[hash:8].js
结合我们需要提取公共代码,其实就是为了让我们知道,该文件是否被更新过,如果被更新过,那么我们就需要去替换掉缓存中的公共代码,若没有,那么我们就不需要去更新缓存中的公共代码。
https://webpack.docschina.org/plugins/split-chunks-plugin/#src/components/Sidebar/Sidebar.jsx具体的配置参照官网,这里只介绍一下基本的参数:
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
base: {
//打包基础库base.js
name: "base",
test: /[\\/]node_modules[\\/]/, //打包node_modules下的模块
chunks: "all",
},
common: {
//打包公共模块
name: "common",
test: /[\\/]src[\\/]/,
minSize: 1024,
chunks: "all",
}
}
}
},
};