Skip to content

Commit

Permalink
fix: use jsdom replace htmlparser2+dom-serializer to fix Hydration mi…
Browse files Browse the repository at this point in the history
…smatches
  • Loading branch information
lisonge committed Jul 14, 2024
1 parent 1354dd8 commit e6d448f
Show file tree
Hide file tree
Showing 4 changed files with 353 additions and 78 deletions.
35 changes: 13 additions & 22 deletions docs/.vitepress/plugins/mirror.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import fs from 'node:fs/promises';
import type { Plugin } from 'vite';
import type selfPkgT from '../../package.json';
import * as walk from 'acorn-walk';
import jsdom from 'jsdom';
import MagicString from 'magic-string';
import { DomUtils, parseDocument } from 'htmlparser2';
import render from 'dom-serializer';
import fs from 'node:fs/promises';
import process from 'node:process';
import type { Plugin } from 'vite';
import type selfPkgT from '../../package.json';

const selfPkg: typeof selfPkgT = JSON.parse(
await fs.readFile(process.cwd() + '/package.json', 'utf-8'),
Expand Down Expand Up @@ -70,25 +69,17 @@ export const mirror = (): Plugin | undefined => {
};
};

const Parser = globalThis.DOMParser || new jsdom.JSDOM().window.DOMParser;
export const transformHtml = (code: string) => {
if (!useMirror) return;
const doc = parseDocument(code);
const scripts = DomUtils.findAll((e) => {
return (
e.name === 'script' &&
!!e.attribs.src &&
e.attribs.src.startsWith('/assets/')
);
}, doc.children);
scripts.forEach((e) => {
e.attribs.src = mirrorBaseUrl + e.attribs.src;
if (!code.includes('/assets/')) return;
// 注意: 如果使用 htmlparser2+dom-serializer, 当 md 文件包含 `<<n` 将出现 Hydration mismatches 错误
const doc = new Parser().parseFromString(code, 'text/html');
doc.querySelectorAll('link[href^="/assets/"]').forEach((e) => {
e.setAttribute('href', mirrorBaseUrl + e.getAttribute('href'));
});
const links = DomUtils.findAll((e) => {
const href = e.attribs.href;
return e.name === 'link' && !!href && href.startsWith('/assets/');
}, doc.children);
links.forEach((e) => {
e.attribs.href = mirrorBaseUrl + e.attribs.href;
doc.querySelectorAll('script[src^="/assets/"]').forEach((e) => {
e.setAttribute('href', mirrorBaseUrl + e.getAttribute('src'));
});
return render(doc, { encodeEntities: false });
return doc.documentElement.outerHTML;
};
20 changes: 10 additions & 10 deletions docs/selector/optimize.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

因此上面的 `深度先序顺序遍历子孙节点` 将省略, 只进行一次判断, 不需要判断 n 次

但是如果你在子查询里使用 `<<(n)`, 例如 `TextView <<(n) [parent=null]`
但是如果你在子查询里使用 `<<n`, 例如 `TextView <<n [parent=null]`

根据上面说明的优化, 虽然也只有一次判断, 但是由于 `<<(n)` 导致内部的子判断也是 n 次, 实际上没有优化判断次数
根据上面说明的优化, 虽然也只有一次判断, 但是由于 `<<n` 导致内部的子判断也是 n 次, 实际上没有优化判断次数

实际上, 在初始匹配节点是 根节点 的情况下, `TextView``@TextView <<(n) [parent=null]` 完全等价
实际上, 在初始匹配节点是 根节点 的情况下, `TextView``@TextView <<n [parent=null]` 完全等价

### 祖先节点 {#ancestor}

Expand Down Expand Up @@ -78,25 +78,25 @@

这样一个选择器只能在右侧使用快速查询, 为了在中间的子选择器也能使用

额外规定如果属性选择器如果符合上面格式并且右侧是 `<<(n)`, 也能在局部使用快速查找
额外规定如果属性选择器如果符合上面格式并且右侧是 `<<n`, 也能在局部使用快速查找

示例 `A > B + C[id='x'][childCount=2] <<(n) D` 中的 `C[id='x'][childCount=2] <<(n)` 可以使用局部快速查找
示例 `A > B + C[id='x'][childCount=2] <<n D` 中的 `C[id='x'][childCount=2] <<n` 可以使用局部快速查找

> [!TIP] 提示
> 实际上从根节点开始匹配的选择器如 `A > B` 都可等价为 `A > @B <<(n) [parent=null]`
> 实际上从根节点开始匹配的选择器如 `A > B` 都可等价为 `A > @B <<n [parent=null]`
下面给出满足局部查询优化的示例: ✅ 表示符合格式, ❎ 表示不符合格式

- `A > B + C[id='x'][childCount=2] <<(n) D`
- `A > B + C[childCount=2][id='x'] <<(n) D`
- `A > B + C[id='x'][childCount=2] <<n D`
- `A > B + C[childCount=2][id='x'] <<n D`

上面介绍的是只有一个局部选择器的情况, 下面给出多个局部快速查找的的示例

`A > C[id='x'] <<(n) D[id='y'] <<(n) E`, 其中的 `C[id='x'] <<(n)``D[id='y'] <<(n)` 都可以使用局部快速查找
`A > C[id='x'] <<n D[id='y'] <<n E`, 其中的 `C[id='x'] <<n``D[id='y'] <<n` 都可以使用局部快速查找

---

[`[vid="image"] <<(n) [vid="recyclerView"] <<(n) [vid="content_layout"]`](https://i.gkd.li/i/16201605?gkd=W3ZpZD0iaW1hZ2UiXSA8PG4gW3ZpZD0icmVjeWNsZXJWaWV3Il0gPDxuIFt2aWQ9ImNvbnRlbnRfbGF5b3V0Il0) 为例
[`[vid="image"] <<n [vid="recyclerView"] <<n [vid="content_layout"]`](https://i.gkd.li/i/16201605?gkd=W3ZpZD0iaW1hZ2UiXSA8PG4gW3ZpZD0icmVjeWNsZXJWaWV3Il0gPDxuIFt2aWQ9ImNvbnRlbnRfbGF5b3V0Il0) 为例

上面的选择器存在 3 个快速查找优化

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
"dependencies": {
"@gkd-kit/selector": "0.3.3",
"@types/file-saver": "2.0.7",
"@types/jsdom": "21.1.7",
"@types/node": "20.14.10",
"acorn-walk": "8.3.3",
"cross-env": "7.0.3",
"dom-serializer": "2.0.0",
"file-saver": "2.0.5",
"htmlparser2": "9.1.0",
"jsdom": "24.1.0",
"magic-string": "0.30.10",
"markdown-it-mathjax3": "4.3.2",
"naive-ui": "2.38.2",
Expand Down
Loading

0 comments on commit e6d448f

Please sign in to comment.