Add support for versioned sidebars which are `.js` not `.json`
Have you read the Contributing Guidelines on issues?
- [X] I have read the Contributing Guidelines on issues.
Prerequisites
- [X] I'm using the latest version of Docusaurus.
- [X] I have tried the
npm run clearoryarn clearcommand. - [X] I have tried
rm -rf node_modules yarn.lock package-lock.jsonand re-installing packages. - [X] I have tried creating a repro with https://new.docusaurus.io.
- [X] I have read the console error message carefully (if applicable).
Description
Version sidebars are hard coded to be .json . files.
It doesn't mention this in the documentation on versioning - it just kind of implies it.
Maybe there should be an alert warning people about it? or there could be some kind of fix that would make it possible to use either.
Here's my proposed fix:
Make the getVersionSidebarsPath function read the user's source code to see if it's .js or .json before it returns. I'm sure a more elegant way exists but this seems fine, unless I'm missing something.
Reproducible demo
https://codesandbox.io/p/devbox/priceless-goldwasser-qdeo7?file=%2FREADME.md&privacy=public
Steps to reproduce
-
Make a new version `npm run docusaurus docs:version 1.1.0
-
Replace the
version-1.1.0-sidebar.jsonwith an equivalent.jsfile like:
const sidebar = {
tutorialSidebar: [
{
type: "autogenerated",
dirName: ".",
},
],
};
module.exports = sidebar;
- Observe a crash
Expected behavior
Versioned sidebars should behave like normal ones, allowing js (or even ts)
Actual behavior
It crashes, it can't find the sidebar
Your environment
- Public source code:
- Public site URL:
- Docusaurus version used:
- Environment name and version (e.g. Chrome 89, Node.js 16.4):
- Operating system and version (e.g. Ubuntu 20.04.2 LTS):
Self-service
- [X] I'd be willing to fix this bug myself.
@robert-j-webb I agree that we could support reading from both .json and .js for versioned sidebars.
Just wanted to explain the reason why we historically only support .json so far.
When creating versions with the CLI, we kind-of have to run the sidebar code and transform it from JS to JSON. If we don't do this, if your sidebar code has dynamic logic like reading file-system paths or using relative imports, we would have to emit a versioned sidebar .js with all the paths "fixed" so that it works in another dir.
I don't think it's possible to solve all the possible edge cases here, this is why when versioning docs you get a .json sidebar and not a .js sidebar, even if the unversioned sidebars.js is not initially a .json file.
Does it make sense?
Now if you don't care about the ability of the CLI to emit versioned .js sidebars, and if you are fine renaming from .json to .js yourself, I think it's reasonable to support that use-case.
When creating versions with the CLI, we kind-of have to run the sidebar code and transform it from JS to JSON. If we don't do this, if your sidebar code has dynamic logic like reading file-system paths or using relative imports, we would have to emit a versioned sidebar .js with all the paths "fixed" so that it works in another dir.
I don't think it's possible to solve all the possible edge cases here, this is why when versioning docs you get a .json sidebar and not a .js sidebar, even if the unversioned sidebars.js is not initially a .json file.
Does it make sense?
Interesting, that does make sense. I think it's basically impossible to write something that would rewrite code to be aware in that way.
Now if you don't care about the ability of the CLI to emit versioned .js sidebars, and if you are fine renaming from .json to .js yourself, I think it's reasonable to support that use-case.
I'm really glad you mentioned that, I think it's a reasonable use case too.
Should I write something up to support .js or .json ?
I'm not quite sure the best way to do this or how to test it, something like this:
/** `[siteDir]/community_versioned_sidebars/version-1.0.0-sidebars.json` */
export function getVersionSidebarsPath(
siteDir: string,
pluginId: string,
versionName: string,
): string {
const isJs = (fs.existsSync(ath.join(
siteDir,
addPluginIdPrefix(VERSIONED_SIDEBARS_DIR, pluginId),
`version-${versionName}-sidebars.js`,
))
return path.join(
siteDir,
addPluginIdPrefix(VERSIONED_SIDEBARS_DIR, pluginId),
`version-${versionName}-sidebars.${isJs ? 'js' : 'json}`,
);
}
May work, but not for .ts ? Is there a better way to do that?
I think it's preferable if I implement this myself because I'm not sure how it should be done. In any case, we'd want to avoid sync IOs like this.
We also need to take into consideration future goals because I'd like to get rid of the versioned_sidebars folder and instead co-locate sidebars files next to the versioned docs.