在之前一个商场项目里实现过一个关于资源预加载的优化,使用的是webpack5的插件来实现的。今天分享一下:
场景需求
将具体资源目录下的图片资源实现预加载,减少图片loading时间
插件功能
- 支持根据资源路径,在打包时动态插入资源路径
- 资源加载方式可配置,支持preload和prefetch模式
实现原理
- 使用link标签,动态插入到html的head里
- 利用webpack的html-webpack-plugin插件,在构建过程中修改html文件
示例
head里的link标签
network会提前请求资源
页面使用资源时直接取缓存
代码
- 插件实现
const HtmlWebpackPlugin = require('html-webpack-plugin');
class PreloadImagesPlugin {
constructor(options) {
this.assetDir = options.assetDir;
this.strategy = options.strategy || 'preload';
}
apply(compiler) {
// console.log('compiler===',compiler.outputPath)
compiler.hooks.compilation.tap('PreloadImagesPlugin', (compilation) => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tap(
'PreloadImagesPlugin',
(data, cb) => {
const imagePaths = this.getImages(compilation.assets);
console.log('imagePaths===',imagePaths)
for (const imagePath of imagePaths) {
const newTag = {
tagName: 'link',
voidTag: true,
attributes: {
rel: this.strategy,
href: imagePath,
as: 'image',
},
};
data.assetTags.styles.push(newTag);
}
}
);
});
}
// 获取所有图片路径
getImages(assets) {
let images = [];
for (const assetPath in assets) {
if (assetPath.includes(this.assetDir)) {
images.push(assetPath);
}
}
return images;
}
}
module.exports = PreloadImagesPlugin;
- 引入插件
// 使用的是CRA起的项目
//在config-overrides.js里引用PreloadImagesPlugin插件
const CRA = require('customize-cra');
const { override, addWebpackAlias, addWebpackPlugin, addWebpackModuleRule } = CRA
const PreloadImagesPlugin = require('./plugins/preloadImage');
//srcPath 是打包时的图片资源输出路劲,cra默认是static/media
//可以自己配置自己改写配置的输出目录,也可以根据load改写资源输出目录
//需要
const srcPath = 'static/assets'
const path = require('path');
module.exports = override(
// 添加路径别名
addWebpackAlias({
'@': path.resolve(__dirname, 'src'),
}),
addWebpackPlugin(new PreloadImagesPlugin({ assetDir: srcPath, strategy: 'prefetch' })),
// addWebpackModuleRule({
// test: /\.(png|jpe?g|gif|svg)$/i,
// use: [
// {
// loader: 'file-loader',
// options: {
// name: `${srcPath}/[name].[hash].[ext]`,
// },
// },
// ],
// include: path.resolve(__dirname,'src/assets'),
// }),
(config) => {
// config.output.publicPath = '/';
// config.output.filename ='static/js/[name].[contenthash:8].js';
// config.output.chunkFilename ='static/js/[name].[contenthash:8].chunk.js';
// config.output.path = path.resolve(__dirname, 'dist');
config.output.assetModuleFilename = `${srcPath}/[name].[hash][ext]`;
return config;
},
);
webpack来实现preloadimg比较简单,因为预览插件不需要区分本地和生产环境,webpack打包的路劲都是一样的。
PS:后续可以根据资源优先级自行修改插件配置,根据不同的目录选择加载的方式prefetch or preload
本文暂时没有评论,来添加一个吧(●'◡'●)