docusaurus: Markdown content with custom `slug` fails to resolve relative links ("error Docusaurus found broken links!")
Have you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
Prerequisites
- I’m using the latest version of Docusaurus.
- I have tried the
npm run clearoryarn clearcommand. - I have tried
rm -rf node_modules yarn.lock package-lock.jsonand re-installing packages. - I have tried creating a repro with https://new.docusaurus.io.
- I have read the console error message carefully (if applicable).
Description
yarn build fails with error Docusaurus found broken links! if a markdown docs page with custom slug has a relative link in it.
Steps to reproduce
- Add
classicpreset withdocsenabled, like so:docs: { routeBasePath: '/', path: 'content' } - Add two
docs:content/01-ch1/01-sec1.mdx:--- slug: '/' --- hi - this is the landing page! More good stuff in [sec2](./sec2).content/01-ch1/02-sec2.mdx:This is chapter1 -> section2.
Expected behavior
Relative paths should not error out, even in case of custom slug.
Actual behavior
- Run
yarn build:error Docusaurus found broken links! Please check the pages of your site in the list below, and make sure you don't reference any path that does not exist. Note: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass. Exhaustive list of all broken links found: - On source page path = /ch1: -> linking to ./sec2 (resolved as: /sec2)
NOTE1: This does not seem to be a problem with a slug referring to a different path. It still errors out if slug: /ch1/
NOTE2: It stops complaining, if I use the absolute path /ch1/sec2.
Your environment
- Public source code: https://github.com/Domiii/dbux/blob/docs/docs/content/04-tools-and-configuration/00-architecture-overview.mdx
- Public site URL: (not deployed yet)
- Docusaurus version used:
2.0.0-beta.13 - Environment name and version (e.g. Chrome 89, Node.js 16.4): Node@16+
- Operating system and version (e.g. Ubuntu 20.04.2 LTS): Windows 10
Reproducible demo
No response
Self-service
- I’d be willing to fix this bug myself.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 16
I hope you understand what I had been emphasizing above.
b/c/dis not a file path, it’s a URL path and it’s up to the browser to decide what it resolves to. You should expect it to behave differently whenslugis set because the routing has been changed.URL links, relative or absolute, can still be useful in many cases because file links currently only work when you link files within one plugin. This might be fixed in the future.
Mmm, we can. I’ve actually explained to multiple people about how routing works. I kind of added some details here: https://docusaurus.io/docs/next/docs-introduction#docs-only-mode but ultimately I think it would be useful to have a centralized place where we talk about all things related to routing:
routeBasePath, conflicting routes, slugs, file path => URL path, relative / absolute URLs… If you want to take the first step, PR welcomeSorry, was having dinner, didn’t explain it clear enough.
In Docusaurus, there are two types of paths: file paths and URL paths. File paths are what exist on your system; URL paths are what your site’s visitors see in their browser.
Without extra configuration, they usually map very intuitively:
docs/ch1/sec1.md=>/docs/ch1/sec1docs/ch1/sec2.md=>/docs/ch1/sec2What
slugdoes is that it manually sets the URL.docs/ch1/sec1.md(slug: /) =>/docsdocs/ch1/sec2.md=>/docs/ch1/sec2A key observation is that these two path systems are isomorphic:
..goes one level above,.stays on the current level,./sluggoes to aslugsubpath. If you are given a path, you have no way to tell if it’s a file path or URL path.So, how should you link pages? As implied in my previous response in #6208, Docusaurus wants to prioritize using file paths over URLs in general, because editors can help you update file references during refactoring, but URLs are a downstream feature. Therefore, in
ch1/01-sec1.md, if you write[link](./02-sec2.md), Docusaurus understands that this is a file path, and automatically converts that to a URL path for you. It can do that because the docs plugin keeps track of the file path => URL mapping, and it knows that02-sec2.mdfile eventually becomes the/ch1/sec2URL.However, if you write
[link](./sec2), does Docusaurus know that this is a file path? No, because<a href="./sec2">link</a>is, in fact, a common pattern to link to another page, compared to<a href="./02-sec2.md">link</a>which is very unlikely to happen (.mdfiles aren’t present in the build output; they are converted to.htmlfiles). Therefore, Docusaurus sees this as a URL and leaves it as-is.So, what page does
<a href="./sec2">link</a>link to? We go back to your page’s URL. Because you have setslug: /,docs/ch1/sec1.mdis now mapped tohttp://example.com/docs. By the argument that URL and file paths are isomorphic in behavior,./sec2will be resolved ashttp://example.com/sec2by the browser (remember: all this happens on the client side!), which is, well, a non-existent path.How should you solve it? If you want to use file paths, explicitly tell Docusaurus that it’s a file path by adding the extension:
[link](./02-sec2.md). If you want to use URL paths, make sure it resolves correctly:[link](/docs/ch1/sec2).Does that clear up some doubts?
This is not a guess, it is actually a documented recommendation, see above. Is there a better place where we should recommend this? I feel it’s in the right place, and you just didn’t read the whole doc. It’s hard to make everything intuitive and in the end you have to read the doc 🤪
We have a system to detect broken links preventing you to deploy a broken site, isn’t it covering this use-case?
Agree that users generally struggle with our routing system. The docs-only mode also makes it even more confusing as you have to combine routeBasePath + slug to set a doc as your homepage. I’ve seen recently a live stream where a user struggled, also encountered the “onBrokenLinks” error after changing a slug, and wasn’t sure how to fix it.
In this case, however, we didn’t invent anything, and relative links are relative to the current page they appear in, it’s just how the web works. Just write 2 HTML files locally in different folders and test for yourself.
That’s also why we tend to recommend using relative file paths:
https://docusaurus.io/docs/next/docs-markdown-features
URLs will never be relative to the file. When your file has been turned to HTML pages, how does the browser know what the original path is like? You are missing the key part here: file path is server-side, URL path is client-side. The server knows about the client because it builds the client, but the client is ignorant about the server. That’s what I mean by saying that “URL is downstream”.
Also remember that FS structure tells you nothing about the URL structure. Files that happen to be in the same folder can end up with drastically different URL. Can you even provide a well-defined heuristic of what “URL relative to the file” is like? If you can (in the form of pseudocode or some test cases) from there we can make another feature request.
And that’s exactly the reason why I said you should use MD links instead of URL links. Changing the routes can lead to unexpected broken links.