【性能优化】DNS解析优化

前言

  • DNS解析过程消耗时间
  • DNS有本地缓存

比如首次访问某站点,会耗费很多时间进行DNS解析,但解析结束后会将ip地址存入本地设备,后续再访问此域名时就会直接从缓存中取。

首次访问页面时,本页面的DNS解析是无法优化的,但是页面中可能用到其他域名下的资源,如css、图片、js等,可以通知浏览器提前对这些资源进行异步DNS解析。

实现

以下代码引入了其他域名下的资源,需要在head中添加link进行dns预解析,格式如下:

html 复制代码
<link rel="dns-prefetch" href="https://www.xxx.com">
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <link rel="dns-prefetch" href="https://www.abc.com">
  <link rel="dns-prefetch" href="https://www.aaa.com">
  <link rel="dns-prefetch" href="https://www.tes.com">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .container {
      background: url('https://www.abc.com/imgs/main-bg');
    }
  </style>
</head>

<body>
  <div class="container">
    <img src="https://www.aaa.com/img/32fd.jpg" alt="">
  </div>
  <script src="https://www.tes.com/sss.js"></script>
</body>

</html>

框架内实现

但是合作开发模式下,站外资源的引用会分散到很多组件中,难以集中控制且由于是手动写死的地址,也会提高维护成本

本文提供两种方式,分别为手写js实现以及vite插件,如果想将js插件发布到npm可以看另一篇文章:如何将自己的插件发布到npm上

方式一:手写js实现

标准的做法应该是根据构建工具写一个插件,如vite用的rollup,就要写一个rollup插件,但是本文通过node实现

首先需要实现分析打包结果中的js,取出站外资源对应域名,并动态添加link标签到html的head中。

新建js用于动态插入link

确保项目中有如下插件

html 复制代码
npm install node-html-parser
npm install glob
npm install url-regex

dns-prefetch.cjs代码内容如下:

javascript 复制代码
// 该node文件:识别打包结果中的站外资源地址并动态插入index.html中link实现dns-prefetch,提高渲染速度
// 调用方式:node ./scripts/dns-prefetch.js

const fs = require("fs")
const path = require("path")
const { parse } = require("node-html-parser") // 可以脱离浏览器环境将html字符串解析成HTML节点
const { glob } = require("glob")
const urlRegex = require("url-regex") // 可以分析文件中所包含的url
const { strict } = require("assert")

const urlPattern = /(https?:\/\/[^/]*)/i // 获取外部链接
const urls = new Set() // url集合

// 遍历dist目录中的所有 HTML 文件
async function searchDomain() {
  const files = await glob("dist/**/*.{html,css,js}")
  for (const file of files) {
    const source = fs.readFileSync(file, "utf-8")
    const matches = source.match(urlRegex({ strict: true }))
    if (matches) {
      matches.forEach((url) => {
        const match = url.match(urlPattern)
        if (match && match[1]) {
          urls.add(match[1]) // 将域名加到Set中
        }
      })
    }
  }
}

// 将遍历好的所有域名生成link预解析标签并插入到index.html中
async function insertLinks() {
  const files = await glob("dist/**/*.html")
  const links = [...urls]
    .map((url) => `<link rel="dns-prefetch" href="${url}">`)
    .join("\n")

  for (const file of files) {
    const html = fs.readFileSync(file, "utf-8")
    const root = parse(html)
    const head = root.querySelector("head")
    head.insertAdjacentHTML("afterbegin", links)
    fs.writeFileSync(file, root.toString(), "utf-8")
  }
}

async function main() {
  await searchDomain()
  await insertLinks()
}

main()

package.json中在打包处理后执行该js

javascript 复制代码
"scripts": {
  "dev": "vite",
  "build": "vite build && node ./scripts/dns-prefetch.cjs",
  "preview": "vite preview"
},

&&的意义 :如 vite+ts 项目默认打包为:"build": "tsc && vite build",意为先进行ts语法检查,再打包,如果语法检查错误则立即停止。所以此处将自定义js放到打包后执行。

查看dist中index.html,发现link已经插入。

方式二:vite-plugin-prefetch-dns插件

复制代码
npm install vite-plugin-prefetch-dns
javascript 复制代码
import { defineConfig } from 'vite';
import prefetchDns from 'vite-plugin-prefetch-dns';

export default defineConfig({
  plugins: [
    ...其他插件
    prefetchDns()
  ]
});

执行npm run build,打包完毕后看到正确插入link标签。

相关推荐
刘发财3 小时前
弃用html2pdf.js,这个html转pdf方案能力是它的几十倍
前端·javascript·github
牛奶5 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶5 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
冰_河6 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
Kagol8 小时前
🎉OpenTiny NEXT-SDK 重磅发布:四步把你的前端应用变成智能应用!
前端·开源·agent
GIS之路9 小时前
ArcGIS Pro 中的 notebook 初识
前端
JavaGuide9 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
ssshooter9 小时前
看完就懂 useSyncExternalStore
前端·javascript·react.js
格砸10 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端
Live0000011 小时前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native