mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 23:57:22 +02:00
fix(content-blog): make footnote reference DOM ID unique on post listing page (#7212)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
parent
3b32a41f22
commit
71ba449a28
10 changed files with 197 additions and 1 deletions
|
@ -31,6 +31,7 @@
|
|||
"reading-time": "^1.5.0",
|
||||
"remark-admonitions": "^1.2.1",
|
||||
"tslib": "^2.3.1",
|
||||
"unist-util-visit": "^2.0.3",
|
||||
"utility-types": "^3.10.0",
|
||||
"webpack": "^5.72.0"
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import path from 'path';
|
||||
import admonitions from 'remark-admonitions';
|
||||
import footnoteIDFixer from './remark/footnoteIDFixer';
|
||||
import {
|
||||
normalizeUrl,
|
||||
docuHash,
|
||||
|
@ -435,7 +436,10 @@ export default async function pluginContentBlog(
|
|||
options: {
|
||||
remarkPlugins,
|
||||
rehypePlugins,
|
||||
beforeDefaultRemarkPlugins,
|
||||
beforeDefaultRemarkPlugins: [
|
||||
footnoteIDFixer,
|
||||
...beforeDefaultRemarkPlugins,
|
||||
],
|
||||
beforeDefaultRehypePlugins,
|
||||
staticDirs: siteConfig.staticDirectories.map((dir) =>
|
||||
path.resolve(siteDir, dir),
|
||||
|
|
9
packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md
generated
Normal file
9
packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post.md
generated
Normal file
|
@ -0,0 +1,9 @@
|
|||
foo[^1]
|
||||
|
||||
bar[^2]
|
||||
|
||||
baz[^3]
|
||||
|
||||
[^1]: foo
|
||||
[^2]: foo
|
||||
[^3]: foo
|
9
packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md
generated
Normal file
9
packages/docusaurus-plugin-content-blog/src/remark/__tests__/__fixtures__/post2.md
generated
Normal file
|
@ -0,0 +1,9 @@
|
|||
foo[^1]
|
||||
|
||||
bar[^2]
|
||||
|
||||
baz[^3]
|
||||
|
||||
[^1]: foo
|
||||
[^2]: foo
|
||||
[^3]: foo
|
|
@ -0,0 +1,66 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`footnoteIDFixer remark plugin appends a hash to each footnote def/ref 1`] = `
|
||||
"/* @jsxRuntime classic */
|
||||
/* @jsx mdx */
|
||||
|
||||
|
||||
|
||||
const layoutProps = {
|
||||
|
||||
};
|
||||
const MDXLayout = "wrapper"
|
||||
export default function MDXContent({
|
||||
components,
|
||||
...props
|
||||
}) {
|
||||
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
|
||||
<p>{\`foo\`}<sup parentName="p" {...{
|
||||
"id": "fnref-1-[HASH]"
|
||||
}}><a parentName="sup" {...{
|
||||
"href": "#fn-1-[HASH]",
|
||||
"className": "footnote-ref"
|
||||
}}>{\`1\`}</a></sup></p>
|
||||
<p>{\`bar\`}<sup parentName="p" {...{
|
||||
"id": "fnref-2-[HASH]"
|
||||
}}><a parentName="sup" {...{
|
||||
"href": "#fn-2-[HASH]",
|
||||
"className": "footnote-ref"
|
||||
}}>{\`2\`}</a></sup></p>
|
||||
<p>{\`baz\`}<sup parentName="p" {...{
|
||||
"id": "fnref-3-[HASH]"
|
||||
}}><a parentName="sup" {...{
|
||||
"href": "#fn-3-[HASH]",
|
||||
"className": "footnote-ref"
|
||||
}}>{\`3\`}</a></sup></p>
|
||||
<div {...{
|
||||
"className": "footnotes"
|
||||
}}>
|
||||
<hr parentName="div"></hr>
|
||||
<ol parentName="div">
|
||||
<li parentName="ol" {...{
|
||||
"id": "fn-1-[HASH]"
|
||||
}}>{\`foo\`}<a parentName="li" {...{
|
||||
"href": "#fnref-1-[HASH]",
|
||||
"className": "footnote-backref"
|
||||
}}>{\`↩\`}</a></li>
|
||||
<li parentName="ol" {...{
|
||||
"id": "fn-2-[HASH]"
|
||||
}}>{\`foo\`}<a parentName="li" {...{
|
||||
"href": "#fnref-2-[HASH]",
|
||||
"className": "footnote-backref"
|
||||
}}>{\`↩\`}</a></li>
|
||||
<li parentName="ol" {...{
|
||||
"id": "fn-3-[HASH]"
|
||||
}}>{\`foo\`}<a parentName="li" {...{
|
||||
"href": "#fnref-3-[HASH]",
|
||||
"className": "footnote-backref"
|
||||
}}>{\`↩\`}</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</MDXLayout>;
|
||||
}
|
||||
|
||||
;
|
||||
MDXContent.isMDXComponent = true;"
|
||||
`;
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import {simpleHash} from '@docusaurus/utils';
|
||||
import mdx from '@mdx-js/mdx';
|
||||
import footnoteIDFixer from '../footnoteIDFixer';
|
||||
|
||||
const processFixture = async (name: string) => {
|
||||
const filepath = path.join(__dirname, `__fixtures__/${name}.md`);
|
||||
const result = await mdx(await fs.readFile(filepath), {
|
||||
filepath,
|
||||
remarkPlugins: [footnoteIDFixer],
|
||||
});
|
||||
|
||||
return result.toString();
|
||||
};
|
||||
|
||||
describe('footnoteIDFixer remark plugin', () => {
|
||||
it('appends a hash to each footnote def/ref', async () => {
|
||||
const hash = simpleHash(path.join(__dirname, `__fixtures__/post.md`), 6);
|
||||
expect(
|
||||
(await processFixture('post')).replace(new RegExp(hash, 'g'), '[HASH]'),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('produces different hashes for different posts but same hash for the same path', async () => {
|
||||
const file1 = await processFixture('post');
|
||||
const file1again = await processFixture('post');
|
||||
const file2 = await processFixture('post2');
|
||||
expect(file1).toBe(file1again);
|
||||
expect(file1).not.toBe(file2);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import visit from 'unist-util-visit';
|
||||
import {simpleHash} from '@docusaurus/utils';
|
||||
import type {Transformer} from 'unified';
|
||||
import type {FootnoteReference, FootnoteDefinition} from 'mdast';
|
||||
|
||||
/**
|
||||
* In the blog list view, each post will be compiled separately. However, they
|
||||
* may use the same footnote IDs. This leads to duplicated DOM IDs and inability
|
||||
* to navigate to footnote references. This plugin fixes it by appending a
|
||||
* unique hash to each reference/definition.
|
||||
*/
|
||||
export default function plugin(): Transformer {
|
||||
return (root, vfile) => {
|
||||
const suffix = `-${simpleHash(vfile.path!, 6)}`;
|
||||
visit(root, 'footnoteReference', (node: FootnoteReference) => {
|
||||
node.identifier += suffix;
|
||||
});
|
||||
visit(root, 'footnoteDefinition', (node: FootnoteDefinition) => {
|
||||
node.identifier += suffix;
|
||||
});
|
||||
};
|
||||
}
|
13
website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md
Normal file
13
website/_dogfooding/_blog tests/2022-01-21-dup-footnote.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: Third post with footnote to test posts with same footnote reference.
|
||||
---
|
||||
|
||||
foo[^1]
|
||||
|
||||
bar[^2]
|
||||
|
||||
baz[^3]
|
||||
|
||||
[^1]: foo
|
||||
[^2]: bar
|
||||
[^3]: baz
|
13
website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md
Normal file
13
website/_dogfooding/_blog tests/2022-01-22-dup-footnote.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: Second post with footnote to test posts with same footnote reference.
|
||||
---
|
||||
|
||||
foo[^1]
|
||||
|
||||
bar[^2]
|
||||
|
||||
baz[^3]
|
||||
|
||||
[^1]: foo
|
||||
[^2]: bar
|
||||
[^3]: baz
|
13
website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md
Normal file
13
website/_dogfooding/_blog tests/2022-04-20-dup-footnote.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: First post with footnote to test posts with same footnote reference.
|
||||
---
|
||||
|
||||
foo[^1]
|
||||
|
||||
bar[^2]
|
||||
|
||||
baz[^3]
|
||||
|
||||
[^1]: foo
|
||||
[^2]: bar
|
||||
[^3]: baz
|
Loading…
Add table
Add a link
Reference in a new issue