【JS 图片预加载】图片预加载之Vite插件

之前分享了webpack版本的图片预加载插件,今天分享一下Vite的图片预加载插件,功能和配置与webpack一样。

场景需求

根据目标资源优先级来生成不同的预加载标签,【preload】和【prefetch】

插件功能

  • 根据不同加载策略生成不同的Link标签
  • 支持preload和prefetch配置可选
  • 默认支持preload加载

插件实现步骤

  1. 插件入参需支持对象和数组传入
  2. 入参进行参数归一化处理
  3. 在vite插件提供的的两个钩子函数里处理构建的资源
  4. generateBundle钩子函数里获取需要预加载的资源文件
  5. transformIndexHtml函数里插入预加载标签

插件效果示例

preload


prefetch



preload & prefetch



插件配置

// 支持单一对象配置
  VitePreloadImagesPlugin({
      strategy: 'preload',
      assetDir:'src/assets/preload',
  })
// 支持数组多策略配置
   VitePreloadImagesPlugin([
      {
        strategy: 'preload',
        assetDir: 'src/assets/preload',
      },
      {
        strategy: 'prefetch',
        assetDir:'src/assets/prefetch',
      },
  ])

代码实现

import fs from 'fs';
import path from 'path';

//入参进行参数归一化处理
function getOptions(options) {
  if (!options) {
    throw new Error('options is required! options is array or object');
  }
  if (Array.isArray(options)) {
    return options;
  }
  if (typeof options === 'object') {
    const { strategy = 'preload', assetDir } = options;
    if (!assetDir) {
      throw new Error('options is  object,the assetDir is required');
    }

    return [{ strategy, assetDir, }]
  }

}

function VitePreloadImagesPlugin(options) {
  const strategies = getOptions(options) || [];

  let assets: any[] = [];
  let config;

  return {
    name: 'vite-plugin-preload-images',
    configResolved(conf) {
      // 获取解析后的配置中的 base 选项
      config = conf;
    },
    transformIndexHtml(html) {
      // console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>transformIndexHtml');
      let links: string[] = []
      strategies.forEach((item) => {
        const { strategy, assetDir } = item;

        let imageFiles: string[] = [];
        
        if (config.mode === 'production') { // 生产环境
          imageFiles = assets.filter((f) => f.originalFileName.startsWith(assetDir))
            .map(file => (config.base + file.fileName));
        } else {
          const assetPath = path.join(process.cwd(), assetDir);
          const files = fs.readdirSync(assetPath);

          imageFiles = files.filter(file => /\.(png|jpe?g|gif|svg)$/i.test(file))
            .map(file => (path.join(config.base, assetDir, file)));

        }
        imageFiles.map(file_path => {
          links.push(` \n`)
        });


      })

      return html.replace('', `${links.join('')}`);
    },
    generateBundle(_options, bundle) {
      // console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>generateBundle', );
      // 遍历 bundle 对象,找到所有的图片文件
      assets = Object.keys(bundle)
        .filter(key => /^assets(.)*\.(png|jpe?g|gif|svg)$/i.test(key))
        .map((key) => bundle[key])
    },
  };
}

export default VitePreloadImagesPlugin;

vite在dev环境时是直接使用esbuild来加载文件,因此不要特殊处理文件资源,但生产环境时,因为是使用rollup来打包构建的,因此需要对打包资源特殊处理。


目前图片预加载插件的webpack和vite版都已实现了,并发布了npm包。有兴趣的童鞋可以在npm

下载试试

npm install images-preload-plugins --save-dev
// webpack.config.js

import WebpackPreloadImagesPlugin from 'images-preload-plugins/webpack';

// vite.config.js

import VitePreloadImagesPlugin from 'images-preload-plugins/vite';