专业的编程技术博客社区

网站首页 > 博客文章 正文

【JS 图片预加载插件】实现一个webpack图片预加载插件

baijin 2025-02-17 11:08:08 博客文章 10 ℃ 0 评论

在之前一个商场项目里实现过一个关于资源预加载的优化,使用的是webpack5的插件来实现的。今天分享一下:

场景需求

将具体资源目录下的图片资源实现预加载,减少图片loading时间

插件功能

  1. 支持根据资源路径,在打包时动态插入资源路径
  2. 资源加载方式可配置,支持preload和prefetch模式

实现原理

  • 使用link标签,动态插入到html的head里
  • 利用webpack的html-webpack-plugin插件,在构建过程中修改html文件

示例

head里的link标签


network会提前请求资源

页面使用资源时直接取缓存



代码

  1. 插件实现
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;
  1. 引入插件
// 使用的是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

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表