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()
  ]
})
相关推荐
Jmyd01234 小时前
Web端3D营销展厅技术实现路径:从素材上云到线索回流的数据链路
前端·3d·性能优化·三维数字化
CCblandy6 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
NetX行者10 小时前
用 Vite + Vue3 + UnoCSS 搭建企业级项目模板(一):基础骨架
vue·vite·unocss
a59865211 小时前
Docker云手机端口不通,无法访问|六边云手机教你故障排查完整流程
docker·容器·性能优化·云手机
oradh13 小时前
Oracle SQL性能优化案例----数据入库和更新任务
sql·oracle·性能优化
打工仔折腾 AI14 小时前
CentOS 7 单机部署 Elasticsearch 7.17.29:启动报错排查与 CRUD 验证
人工智能·后端·python·elasticsearch·性能优化·centos·jenkins
HEJOO915 小时前
iOS 性能优化全面详解
ios·性能优化·cocoa
yunwei3717 小时前
eBPF 实例教程:BPF Arena 零拷贝共享内存
linux·后端·性能优化
对象存储与RustFS18 小时前
用 warp 压测 S3 兼容存储,十分钟跑出一份可复现的基准报告
后端·云原生·性能优化
martindelophy1 天前
浏览器视频导出太慢怎么优化?一次 WebCodecs 实践:8 分钟视频耗时降低 31%
性能优化·音视频·优化