vite插件:提取项目中第三方域进行dns-prefetch预连接

项目中如果有大量第三方域的静态资源,采用<link rel="dns-prefetch" href="xxx">的方法进行DNS预解析可以提高网站加载速度。

但是现实是网站往往采用Vue,React等框架开发,团队协作,手动添加可能无法全面覆盖,代码插入是更好的选择;本文基于vite插件开发,自动化完成提取和插入。

一. 使用到的Vite/Rollup钩子

  1. configResolved:解析完配置后,可以获取配置对象,排除网站本身域名base。
  2. generateBundle:构建bundle完成时触发,可以获取到构建完后的JS,CSS代码
  3. transformIndexHtml:转换入口HTML用到的钩子,可以获取到HTML字符串,插入Tag

二. 获取源码

Vite构建完成后的代码可能加载第三方域的代码无非就是分布在JS,CSS,HTML文件中。

其中构建完成后的JS,CSS代码可以在generateBundle中获取,generateBundle提供一个bundle对象,包含每个文件的文件名和源码字符串;遍历对象获取元素file,文件名可以通过file.fileName获取。

文件源码存储的位置可能因为输出的类型不同而不同,可以通过file.type判断,chunk类型存储在file.code中,source类型在file.source

js 复制代码
if (/\.(js|css|html)$/.test(file.fileName)) {
  const content =
    file.type === 'chunk' ? file.code : file.source?.toString()
  getDomains(content) // 获取域名
}

HTML字符串可以直接通过transformIndexHtml获取

三. 获取bundle中的域名

可以采用正则匹配的方法获取域名,获取到的域名存储在Set中保证唯一性。获取完成后注意要排除网站域名和一些框架,w3c相关的域名如react.dev,www.w3c.org

js 复制代码
// 匹配域名的正则
const DOMAIN_REGEX = /https?:\/\/([^/\s"'`]+)/gi
// 排除的域名
const EXCLUDED_DOMAINS = ['react.dev', 'www.w3.org']
while ((match = DOMAIN_REGEX.exec(content))) {
    const domain = match[1] // match[0]是以http(s)开头
    if (
      domain &&
      !domain.includes(config.base) &&
      !EXCLUDED_DOMAINS.includes(domain) &&
      !domain.startsWith('localhost')
    ) {
      domains.add(domain)
    }
}

四. 插入到HTML入口文件

transformIndexHtml支持返回{ html. tags },首先从Set集合中取出域名字符串生成HtmlTagDescriptor对象,我们要插入的<link rel="dns-prefetch" href="xxx">放在tags中就行。

记得在HTML中也要提取域名

js 复制代码
transformIndexHtml(html) {
  getDomains(html)
  const prefetchLinks: HtmlTagDescriptor[] = Array.from(domains).map(
    (domain) => ({
      tag: 'link',
      attrs: {
        rel: 'dns-prefetch',
        href: `//${domain}`
      },
      injectTo: 'head'
    })
  )
  return {
    html,
    tags: prefetchLinks
  }
}

完整实现

如果有特殊需求可以添加options,增加插件灵活性

js 复制代码
// vite-plugin-dns-prefetch.ts
import type { Plugin, ResolvedConfig, HtmlTagDescriptor } from 'vite'

const DOMAIN_REGEX = /https?:\/\/([^/\s"'`]+)/gi

const EXCLUDED_DOMAINS = ['react.dev', 'www.w3.org']

export default function viteDnsPrefetchPlugin(): Plugin {
  let config: ResolvedConfig
  const domains = new Set<string>()

  return {
    name: 'vite:dns-prefetch',
    apply: 'build',

    configResolved(resolved) {
      config = resolved
    },

    generateBundle(_, bundle) {
      console.log('bundle', bundle)
      for (const file of Object.values(bundle)) {
        if (/\.(js|css|html)$/.test(file.fileName)) {
          const content =
            file.type === 'chunk' ? file.code : file.source?.toString()
          getDomains(content)
        }
      }
    },

    transformIndexHtml(html) {
      getDomains(html)
      const prefetchLinks: HtmlTagDescriptor[] = Array.from(domains).map(
        (domain) => ({
          tag: 'link',
          attrs: {
            rel: 'dns-prefetch',
            href: `//${domain}`
          },
          injectTo: 'head'
        })
      )
      return {
        html,
        tags: prefetchLinks
      }
    }
  }

  function getDomains(content: string) {
    if (content) {
      let match
      while ((match = DOMAIN_REGEX.exec(content))) {
        const domain = match[1]
        if (
          domain &&
          !domain.includes(config.base) &&
          !EXCLUDED_DOMAINS.includes(domain) &&
          !domain.startsWith('localhost')
        ) {
          domains.add(domain)
        }
      }
    }
  }
}

// vite中使用
import { defineConfig } from 'vite'
import prefetchDnsPlugin from './vite-plugin-prefetch-dns'

export default defineConfig({
  plugins: [
    prefetchDnsPlugin()
  ]
})
相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
liangshanbo12152 天前
React 性能优化实战
性能优化·react
mmsx2 天前
Android GIS系列 内存加锁、SQLite 开事务:矢量数据集双层并发设计
android·性能优化·app
Pioneer000013 天前
我用 Redis + 网关做多模型 API 路由:缓存命中率 95%+ 的工程实践
人工智能·redis·后端·缓存·性能优化·架构
ZFJ_张福杰3 天前
【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化
flutter·性能优化·卡顿·isolate
政企项目老覃3 天前
金融转账“幽灵失败“排查实录:从本地消息表到 Seata TCC 的选型与权衡
数据库·程序人生·性能优化·数据分析·系统架构
爱喝水的鱼丶3 天前
SAP-ABAP:MM 模块供应商主数据开发:字段扩展、分级管控与同步接口开发
开发语言·性能优化·接口·sap·abap·增强·经验交流
贾伟康3 天前
【HarmonyOS 7新能力|050】Core File Kit mmap工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·文件系统·mmap
贾伟康3 天前
【HarmonyOS 7新能力|045】LazyLayoutAlgorithm工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·arkui·懒加载
打工仔折腾 AI3 天前
数据库上 K8s 之后谁来管?拆解金仓 KES-Operator 的声明式运维方案
人工智能·后端·python·性能优化·ai agent 实战