Skip to content

Instantly share code, notes, and snippets.

@shunnNet
Last active January 1, 2024 23:19
Show Gist options
  • Save shunnNet/5ab22ab86dd805b9573061b377d71719 to your computer and use it in GitHub Desktop.
Save shunnNet/5ab22ab86dd805b9573061b377d71719 to your computer and use it in GitHub Desktop.
How to scrap all `.vue` template info at build time ?

前言

我有一個專案叫 browser-ai,在裡面有個功能是可以使用 Vue 的 directive 為 DOM 綁上標籤

<template>
  <h1 v-ai="{ id: 'title', description: 'Search Product In this page' }">...</h1>
</template>

<!-- 上述內容會轉換成 -->
<h1 data-ai-id="title" data-ai-description="Search Product In this page">...</h1>

若沒有設定 description,則該 DOM 節點的 textContent 會成為 description

<template>
  <h1 v-ai="{ id: 'title'}"> Search Product In this page</h1>
</template>

<!-- 上述內容會轉換成 -->
<h1 data-ai-id="title" data-ai-description="Search Product In this page">Search Product In this page</h1>

id, description 是用來作為 LLM 的 prompt 資訊,並且透過 Vue 的能力,我也可以記錄加上這些標籤的 DOM 節點,在之後進行操作。

我的需求

接著我需要做到的是「在 build time 蒐集所有的這些節點,最好還可以標註他在哪一個路由上(SPA),可以不需要 DOM 物件」。理想中的實作結果如下(假設使用 rollup 或是 vite 打包):

// virtual:vai-elements
export const elementList = [
  { id: "product-title", description: "Search Product In this page", data: {route: "/product"}  },
  { id: "book-title", description: "Search Book In this page", data: {route: "/book"}  },
]
import { elementList } from "virtual:vai-elements"

// do something with elementList

有這個需求的原因有二:

  1. 若一開始我就知道,在全站之中,某一個 element 有我要的資訊,也知道他在哪一個頁面,那我就可以一口氣導航過去
    1. 打包階段沒有真的 DOM 物件不是問題,這可以想辦法在 runtime 解決
  2. 若一開始我就有所有站內的文本資訊,AI 就可以有更完整的資訊進行回答

此外,我希望將這個功能製作成 unplugin,讓這一切變得方便一點。在原本的構想中,他要可以相容於 Vite+Vue 以及 Nuxt3。

幾個思路

我嘗試想出了幾個解決方向:

  1. 使用 Vue SSR 功能,在打包的階段接收 router 以及元件樹,實際渲染每個路由後,解析 SSR render 出來的 DOM。這個作法是我認為比較確實的,但是在做成 plugin 的時候有一些問題:
    1. 由於是在 build time 運行,且要直接渲染使用者的 APP,因此我實際上需要做一個跟使用者的打包設定幾乎相同的打包。這會導致打包時間變成至少 2 倍,萬一想不開想支援 hot-reload,那效能肯定不會太好。
  2. 使用 ast:
    1. 我認為不是很可行,因為框架有自己渲染模板、解析變數的機制,如果 id 或 description 的值是一個變數的話,就只有框架有辦法判斷那個值是多少了。
  3. 使用 tailwind 跟 unocss 的靜態解析
    1. 這個做法概念是像這兩個工具一樣,看到特定的 class name,就把對應的內容加到模組之中。
    2. 但是這個做法會限制使用者不可以連接字串,該字串必須是靜態,並且為了判斷要抽取哪些內容,可能要規定使用者使用特定語法。
    3. 還有個問題是,這種作法沒有考慮 route 跟元件樹,因此 route 需要使用者手動加入
    4. 無法支援 textContent 作為 description

簡單來說,第一個作法是最完善的,可是效能很差; 第二個不可行; 第三個效能應該會不錯,但是會對使用者有一些限制。

問題

我想請教的是,是否還有其他的可能的作法?或是上述做法之中還有什麼改進的可能?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment