webpack优化首屏加载时间及流畅度的思路
Webpack是一个非常强大的模块打包器。它的主要功能是将多个模块按照依赖关系进行合并打包,并生成最终的静态资源。但是,在打包过程中,我们也需要考虑一些优化策略以提高页面的首屏加载时间和流畅度。
一、减少打包体积
1.只打包需要的模块
Webpack通过使用require()函数来引入模块,但是它会将所有的模块都打包进入bundle.js文件中。这样就会导致bundle.js文件过大,从而影响页面的首屏加载时间。为了减少打包体积,我们可以使用Webpack提供的Tree Shaking来实现只打包需要的模块。
Tree Shaking是Webpack 2.0以上版本新增的优化功能。它能够根据代码的引用关系,删除无用的代码,从而减少打包后的文件大小。在Webpack中使用Tree Shaking非常简单,只需在配置文件中设置mode为production即可。
module.exports = {
mode: "production",
...
}
2.压缩代码
除了只打包需要的模块外,我们还可以使用Webpack提供的UglifyJS插件来压缩JS代码。通过压缩代码,可以去掉不必要的空格、注释、换行符等,从而减小打包后的文件大小。
在Webpack中使用UglifyJS插件非常简单,只需在配置文件中添加如下代码:
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
...
plugins: [
new UglifyJSPlugin()
]
}
二、使用缓存
1.使用缓存提高打包速度
每次修改代码后都要重新构建和打包,这样会耗费大量时间。为了提高打包速度和效率,我们可以使用Webpack的缓存功能。
通过使用cache-loader或hard-source-webpack-plugin插件,可以将每次打包生成的结果缓存起来,这样下次打包时就可以直接使用缓存结果,从而提高打包效率。
2.使用浏览器缓存加快页面加载速度
浏览器缓存可以避免重复访问服务器,从而提高页面的加载速度。我们可以通过在Webpack中设置output.chunkFilename和output.filename来控制静态资源的命名规则,并设置max-age等缓存策略。
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js',
chunkFilename: '[name].[hash:8].js'
},
...
}
三、优化图片加载
1.使用webpack的file-loader和url-loader进行图片处理
Webpack提供的file-loader和url-loader可以帮助我们对图片进行处理,将图片转化成base64编码并嵌入到html中,从而减少http请求次数,提高页面加载速度。
file-loader会将图片打包后生成一个url,url-loader会根据图片大小来决定是否将图片转为base64编码。
2.使用图片压缩工具对图片进行压缩
图片压缩工具可以帮助我们对图片进行压缩,从而减小图片的大小,提高页面加载速度。
四、优化代码分割
Webpack的Code Splitting功能可以将代码拆分成不同的块,从而减少每个页面需要加载的资源数量和文件大小。通过将公共代码提取出来,可以避免重复加载和下载。
1.使用SplitChunksPlugin插件进行代码分割
Webpack提供了一个SplitChunksPlugin插件来帮助我们进行代码分割。可以将公共的依赖模块抽取成chunk,并且将多个chunk之间的重复依赖提取成单独的chunk。
module.exports = {
optimization: {
splitChunks: {
chunks: "all"
}
},
...
}
2.按需加载
按需加载可以实现资源动态加载,从而提高页面加载速度。通过使用React.lazy()函数或者import()语法,可以实现组件的按需加载。
五、使用CDN加速
使用CDN可以将静态资源部署到全球各地的节点上,从而实现跨域访问和加速静态资源请求的速度。 优化用户体验不光要压缩代码文件,还要提高网络的传输速度,通过 CDN 可以实现。
CDN:内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
CDN 其实是通过优化物理链路层传输过程中的网速有限、丢包等问题来提升网速的,其大致原理可以如下: 因为 CDN 都有缓存,所以为了避免 CDN 缓存导致用户加载到老版本的问题,需要遵循以下规则:
- 针对 HTML 文件:不开启任何缓存,不放入 CDN
- 针对静态 JS 、CSS 、图片等文件:开启 CDN 和缓存,放入 CDN 服务器,并且给每一个文件名带入 Hash 值,避免文件重名导致访问到同名缓存废弃文件的问题
- 介于浏览器对同一时刻、同一域名的请求个数有限制的状况,请求资源过多的话,可能导致加载文件被阻塞。所以,当同一时间加载资源过多时,我们可以针对不同的文件类型放入不同的 CDN 上
在Webpack中使用CDN非常简单,只需在配置文件中设置output.publicPath的值为CDN地址即可。
module.exports = {
...
output: {
publicPath: 'http://cdn.com/static/'
},
...
}
Webpack 可以很方便地配置 CDN 来加速静态资源请求的速度。下面是一份详细的配置步骤:
- 在 output 中设置 publicPath
在 Webpack 配置文件中的 output 配置项中,设置 publicPath 的值为 CDN 地址。例如:
module.exports = {
output: {
publicPath: 'https://cdn.example.com/'
}
}
- 配置 externals
可以通过配置 externals,将一些第三方库从打包文件中抽离出来,以便于在 HTML 文件中引入 CDN 资源。当使用 externals 时,需要在页面中手动引入对应的 CDN 资源。
module.exports = {
externals: {
jquery: 'https://cdn.example.com/jquery.min.js'
}
}
- 使用插件 html-webpack-plugin
使用 html-webpack-plugin 插件,可以在打包后的 HTML 文件中自动插入对应的 CDN 资源链接。可以使用该插件的 publicPath 配置项来设置 CDN 地址。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
minify: true,
publicPath: 'https://cdn.example.com/'
})
]
}
- 使用 copy-webpack-plugin
若存在一些与打包无关的静态资源,可以通过 copy-webpack-plugin 插件将其从源码目录复制到打包后的目录中,同时修改 HTML 文件中的引用路径为 CDN 地址。
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'src/assets',
to: 'assets',
transformPath(targetPath) {
return `${PUBLIC_PATH}${targetPath}`;
}
}
]
})
]
}
- 设置 Cache-Control 和 Expires 响应头
在 CDN 配置中设置 Cache-Control 或 Expires 响应头,可以让浏览器在第一次请求时缓存资源,并在过期前使用本地缓存,从而减少重复请求数据。
例如,可以在 Nginx 中增加如下配置:
location /static/ {
expires 1d;
add_header Cache-Control "public";
alias /www/static/;
}
以上是在 Webpack 中配置 CDN 加速的详细步骤。需要注意的是,在使用 CDN 时还需要考虑到资源版本控制、跨域访问等问题。
六、优化打包速度
1.使用HappyPack多线程打包
Webpack是单线程的,打包速度比较慢,通过使用HappyPack插件可以将Webpack的loader部分进行多线程并行处理,从而提高打包速度。
2.使用DLLPlugin进行预编译
DLLPlugin可以将第三方库先进行打包,然后在开发时直接使用已经打包好的dll文件,从而减少重复打包的时间。
Webpack 作为一个强大的模块打包器,打包速度一直是开发者关注的热点问题。下面是一些优化打包速度的详细配置:
- 使用 HappyPack
HappyPack 可以将 Webpack 的 loader 进行多线程并行处理,从而加快打包速度。可以使用 happypack 插件来配置多线程处理的 loader。
const HappyPack = require('happypack');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=js',
exclude: /node_modules/
}
],
},
plugins: [
new HappyPack({
id: 'js',
threads: 4,
loaders: ['babel-loader']
})
]
}
其中,id 表示 HappyPack 实例的唯一标识符,threads 表示启动的线程数,loaders 表示要处理的 loader。
- 使用 DLLPlugin 进行预编译
DLLPlugin 可以将第三方库先进行打包,然后在开发时直接使用已经打包好的 dll 文件,从而减少重复打包的时间。需要注意的是,在修改了第三方库版本或新增第三方库时,需要重新生成 dll 文件。
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
vendors: ['react', 'react-dom', 'lodash']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, 'dist'),
library: '[name]_lib'
},
plugins: [
new webpack.DllPlugin({
name: '[name]_lib',
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
]
}
- 使用 IgnorePlugin 忽略部分模块
可以使用 IgnorePlugin 忽略掉不需要的模块,在打包时跳过它们,从而提升打包速度。
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
}
- 设置 resolve.alias 配置
resolve.alias 可以将一些常用的模块路径映射为绝对路径,从而缩短 Webpack 查找模块的时间。
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'react': path.resolve(__dirname, 'node_modules/react/cjs/react.production.min.js'),
'react-dom': path.resolve(__dirname, 'node_modules/react-dom/cjs/react-dom.production.min.js')
}
}
}
以上是优化 Webpack 打包速度的一些常用配置。当然,在实际项目中,还可以结合其他插件和工具,如 MiniCssExtractPlugin、Webpack Shell Plugin、Autoprefixer 等来进一步优化打包速度。
总之,Webpack如何优化首屏加载时间及流畅度的深度分析,可以针对不同的项目需求进行调整和优化,今后会多多学习,提供经验与感悟与大家一起分享。
转载自:https://juejin.cn/post/7221413753731350587