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()
  ]
})
相关推荐
LuckyRich13 小时前
【仿Mudou库one thread per loop式并发服务器实现】HTTP协议模块实现
服务器·c++·http·性能优化
MrWho不迷糊4 小时前
秒杀怎么优化
后端·性能优化
API_technology8 小时前
高并发场景下的淘宝 API 开发实践:商品数据实时采集与性能优化
大数据·数据库·性能优化·数据挖掘
墨顿20 小时前
模型推理的性能优化
人工智能·深度学习·性能优化·模型推理
涵信20 小时前
第二十节:项目经验-描述一个React性能优化案例
前端·react.js·性能优化
向哆哆21 小时前
Java 性能优化:JVM 调优的实战技巧与案例分析
java·jvm·性能优化
异常君1 天前
当巨型 HashMap 触发扩容:1G HashMap 的扩容风险与性能优化实战
java·后端·性能优化
wordbaby1 天前
加速 Web 应用:资源压缩详解与 Vite + Nginx 实践指南
前端·nginx·vite
huali1 天前
unplugin-https-reverse-proxy 2.0 发布:革新移动端调试体验
前端·开源·vite