-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(v2): linking to asset or external html page -> don't use history.…
…push() (#3347) * Rework markdown links to asset require processing + add test page * implement pathname:// protocol / escape hatch at the Link level * linking to assets: fix tests + avoid creating an useless nested paragraph * fix assets linking doc * attempt to fix windows e2e test * try to fix windows errors
- Loading branch information
Showing
21 changed files
with
267 additions
and
227 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 0 additions & 33 deletions
33
...cusaurus-mdx-loader/src/remark/transformAssets/__tests__/__snapshots__/index.test.js.snap
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
...ges/docusaurus-mdx-loader/src/remark/transformAssets/__tests__/fixtures/fail.md
This file was deleted.
Oops, something went wrong.
91 changes: 0 additions & 91 deletions
91
packages/docusaurus-mdx-loader/src/remark/transformAssets/index.js
This file was deleted.
Oops, something went wrong.
35 changes: 35 additions & 0 deletions
35
...ocusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`transformAsset plugin fail if asset url is absent 1`] = `"Markdown link url is mandatory. filePath=packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/fixtures/noUrl.md, title=null"`; | ||
|
||
exports[`transformAsset plugin pathname protocol 1`] = ` | ||
"[asset](pathname:///asset/unchecked.pdf) | ||
" | ||
`; | ||
|
||
exports[`transformAsset plugin transform md links to <a /> 1`] = ` | ||
"[asset](https://example.com/asset.pdf) | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} ></a> | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} >asset</a> | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} title={Title} >asset</a> ![seet](asset) | ||
## Heading | ||
\`\`\`md | ||
[asset](./asset.pdf) | ||
\`\`\` | ||
[assets](!file-loader!./asset.pdf) | ||
[assets](/github/!file-loader!/assets.pdf) | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} >asset</a> | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default} >staticAsset.pdf</a> | ||
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default} >@site/static/staticAsset.pdf</a> | ||
" | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/** | ||
* 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. | ||
*/ | ||
|
||
const {posixPath} = require('@docusaurus/utils'); | ||
|
||
const visit = require('unist-util-visit'); | ||
const path = require('path'); | ||
const url = require('url'); | ||
const fs = require('fs-extra'); | ||
const {getFileLoaderUtils} = require('@docusaurus/core/lib/webpack/utils'); | ||
|
||
const { | ||
loaders: {inlineMarkdownLinkFileLoader}, | ||
} = getFileLoaderUtils(); | ||
|
||
// Needed to throw errors with computer-agnostic path messages | ||
// Absolute paths are too dependant of user FS | ||
function toRelativePath(filePath) { | ||
return path.relative(process.cwd(), filePath); | ||
} | ||
|
||
async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) { | ||
const assetExists = await fs.exists(fileSystemAssetPath); | ||
if (!assetExists) { | ||
throw new Error( | ||
`Asset ${toRelativePath(fileSystemAssetPath)} used in ${toRelativePath( | ||
sourceFilePath, | ||
)} not found.`, | ||
); | ||
} | ||
} | ||
|
||
// transform the link node to a jsx link with a require() call | ||
function toAssetRequireNode({node, index, parent, filePath, requireAssetPath}) { | ||
let relativeRequireAssetPath = posixPath( | ||
path.relative(path.dirname(filePath), requireAssetPath), | ||
); | ||
|
||
// nodejs does not like require("assets/file.pdf") | ||
relativeRequireAssetPath = relativeRequireAssetPath.startsWith('.') | ||
? relativeRequireAssetPath | ||
: `./${relativeRequireAssetPath}`; | ||
|
||
const hrefProp = `require('${inlineMarkdownLinkFileLoader}${relativeRequireAssetPath}').default`; | ||
|
||
node.type = 'jsx'; | ||
|
||
node.value = `<a target="_blank" href={${hrefProp}} ${ | ||
node.title ? `title={${node.title}}` : '' | ||
} >`; | ||
|
||
const linkText = (node.children[0] && node.children[0].value) || ''; | ||
delete node.children; | ||
|
||
parent.children.splice(index + 1, 0, { | ||
type: 'text', | ||
value: linkText, | ||
}); | ||
|
||
parent.children.splice(index + 2, 0, {type: 'jsx', value: '</a>'}); | ||
} | ||
|
||
// If the link looks like an asset link, we'll link to the asset, | ||
// and use a require("assetUrl") (using webpack url-loader/file-loader) | ||
// instead of navigating to such link | ||
async function convertToAssetLinkIfNeeded({ | ||
node, | ||
index, | ||
parent, | ||
staticDir, | ||
filePath, | ||
}) { | ||
const assetPath = node.url; | ||
|
||
const hasSiteAlias = assetPath.startsWith('@site/'); | ||
const hasAssetLikeExtension = | ||
path.extname(assetPath) && !assetPath.match(/#|.md|.mdx|.html/); | ||
|
||
const looksLikeAssetLink = hasSiteAlias || hasAssetLikeExtension; | ||
|
||
if (!looksLikeAssetLink) { | ||
return; | ||
} | ||
|
||
function toAssetLinkNode(requireAssetPath) { | ||
toAssetRequireNode({ | ||
node, | ||
index, | ||
parent, | ||
filePath, | ||
requireAssetPath, | ||
}); | ||
} | ||
|
||
if (assetPath.startsWith('@site/')) { | ||
const siteDir = path.join(staticDir, '..'); | ||
const fileSystemAssetPath = path.join( | ||
siteDir, | ||
assetPath.replace('@site/', ''), | ||
); | ||
await ensureAssetFileExist(fileSystemAssetPath, filePath); | ||
toAssetLinkNode(fileSystemAssetPath); | ||
} else if (path.isAbsolute(assetPath)) { | ||
const fileSystemAssetPath = path.join(staticDir, assetPath); | ||
if (await fs.exists(fileSystemAssetPath)) { | ||
toAssetLinkNode(fileSystemAssetPath); | ||
} | ||
} else { | ||
const fileSystemAssetPath = path.join(path.dirname(filePath), assetPath); | ||
if (await fs.exists(fileSystemAssetPath)) { | ||
toAssetLinkNode(fileSystemAssetPath); | ||
} | ||
} | ||
} | ||
|
||
async function processLinkNode({node, index, parent, filePath, staticDir}) { | ||
if (!node.url) { | ||
throw new Error( | ||
`Markdown link url is mandatory. filePath=${toRelativePath( | ||
filePath, | ||
)}, title=${node.title}`, | ||
); | ||
} | ||
|
||
const parsedUrl = url.parse(node.url); | ||
if (parsedUrl.protocol) { | ||
return; | ||
} | ||
|
||
await convertToAssetLinkIfNeeded({ | ||
node, | ||
index, | ||
parent, | ||
staticDir, | ||
filePath, | ||
}); | ||
} | ||
|
||
const plugin = (options) => { | ||
const transformer = async (root) => { | ||
const promises = []; | ||
visit(root, 'link', (node, index, parent) => { | ||
promises.push(processLinkNode({node, index, parent, ...options})); | ||
}); | ||
await Promise.all(promises); | ||
}; | ||
return transformer; | ||
}; | ||
|
||
module.exports = plugin; |
Oops, something went wrong.