mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
beta.16
This commit is contained in:
parent
17b8eded79
commit
d337d0b268
253
CHANGELOG.md
253
CHANGELOG.md
|
|
@ -1,5 +1,258 @@
|
|||
# Docusaurus 2 Changelog
|
||||
|
||||
## 2.0.0-beta.16 (2022-02-25)
|
||||
|
||||
#### :rocket: New Feature
|
||||
|
||||
- `docusaurus-logger`, `docusaurus-module-type-aliases`, `docusaurus-plugin-debug`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus`
|
||||
- [#6243](https://github.com/facebook/docusaurus/pull/6243) feat(core): brand new swizzle CLI experience ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`
|
||||
- [#6750](https://github.com/facebook/docusaurus/pull/6750) feat(create): new --package-manager option; interactive package manager selection ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6610](https://github.com/facebook/docusaurus/pull/6610) feat(create): allow specifying a git clone strategy ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6723](https://github.com/facebook/docusaurus/pull/6723) feat: sync color mode between browser tabs ([@lex111](https://github.com/lex111))
|
||||
- `docusaurus-theme-search-algolia`
|
||||
- [#6692](https://github.com/facebook/docusaurus/pull/6692) feat(search-algolia): allow disabling search page and configuring path ([@lex111](https://github.com/lex111))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6517](https://github.com/facebook/docusaurus/pull/6517) feat(docs,theme-classic): docs breadcrumbs ([@jodyheavener](https://github.com/jodyheavener))
|
||||
- [#6519](https://github.com/facebook/docusaurus/pull/6519) feat(content-docs): sidebar item type "html" for rendering pure markup ([@jodyheavener](https://github.com/jodyheavener))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-utils`
|
||||
- [#6593](https://github.com/facebook/docusaurus/pull/6593) feat(content-blog): infer blog post date from git history ([@felipecrs](https://github.com/felipecrs))
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6619](https://github.com/facebook/docusaurus/pull/6619) feat(content-docs): add custom props front matter ([@TheCatLady](https://github.com/TheCatLady))
|
||||
- [#6452](https://github.com/facebook/docusaurus/pull/6452) feat(content-docs): allow explicitly disabling index page for generated category ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`
|
||||
- [#6603](https://github.com/facebook/docusaurus/pull/6603) feat(content-blog): allow customizing blog archive component through option ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-theme-classic`
|
||||
- [#6221](https://github.com/facebook/docusaurus/pull/6221) feat(content-blog): Allow pagination for BlogTagsPostsPage ([@redhoyasa](https://github.com/redhoyasa))
|
||||
|
||||
#### :boom: Breaking Change
|
||||
|
||||
- `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright`
|
||||
- [#6752](https://github.com/facebook/docusaurus/pull/6752) chore: upgrade docsearch-react to v3 stable, bump dependencies ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-types`
|
||||
- [#6729](https://github.com/facebook/docusaurus/pull/6729) refactor: make MDX export a flat TOC list instead of tree ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus`
|
||||
- [#6740](https://github.com/facebook/docusaurus/pull/6740) refactor: remove deprecated Webpack utils & validation escape hatch ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-search-algolia`
|
||||
- [#6707](https://github.com/facebook/docusaurus/pull/6707) refactor(theme-classic): bias again search metadata toward Algolia DocSearch ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-common`, `docusaurus`
|
||||
- [#6651](https://github.com/facebook/docusaurus/pull/6651) refactor: reduce exported members of docusaurus router ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
|
||||
#### :bug: Bug Fix
|
||||
|
||||
- `docusaurus-theme-common`
|
||||
- [#6758](https://github.com/facebook/docusaurus/pull/6758) fix(theme-common): isSamePath should be case-insensitive ([@slorber](https://github.com/slorber))
|
||||
- [#6748](https://github.com/facebook/docusaurus/pull/6748) fix(theme-classic): temporarily disable toc heading autoscrolling ([@slorber](https://github.com/slorber))
|
||||
- [#6696](https://github.com/facebook/docusaurus/pull/6696) fix(theme-common): do not run useLocationChange when hot reloading ([@lex111](https://github.com/lex111))
|
||||
- [#6490](https://github.com/facebook/docusaurus/pull/6490) fix(theme-classic): do not switch color modes when printing ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6749](https://github.com/facebook/docusaurus/pull/6749) fix(theme-classic): fix breadcrumb home link bug with new useHomePageRoute() hook ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6720](https://github.com/facebook/docusaurus/pull/6720) fix(content-docs): create assets for frontmatter images ([@lebalz](https://github.com/lebalz))
|
||||
- [#6592](https://github.com/facebook/docusaurus/pull/6592) fix(content-docs): read last update from inner git repositories ([@felipecrs](https://github.com/felipecrs))
|
||||
- [#6477](https://github.com/facebook/docusaurus/pull/6477) fix(content-docs): export versioning utils ([@milesj](https://github.com/milesj))
|
||||
- `docusaurus-mdx-loader`
|
||||
- [#6712](https://github.com/facebook/docusaurus/pull/6712) fix(mdx-loader): make headings containing links properly formatted in ToC ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus`
|
||||
- [#6701](https://github.com/facebook/docusaurus/pull/6701) fix(cli): disable directory listing in serve ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6607](https://github.com/facebook/docusaurus/pull/6607) fix(cli): log error itself on unhandled rejection ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6500](https://github.com/facebook/docusaurus/pull/6500) fix(cli): allow passing a list of file names to write-heading-ids ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6496](https://github.com/facebook/docusaurus/pull/6496) fix(core): configValidation should allow inline theme functions ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6652](https://github.com/facebook/docusaurus/pull/6652) fix(theme-classic): minor BTT button fixes ([@lex111](https://github.com/lex111))
|
||||
- [#6612](https://github.com/facebook/docusaurus/pull/6612) fix(theme-classic): make Prism additional languages properly server-side rendered ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6599](https://github.com/facebook/docusaurus/pull/6599) fix(theme-classic): add docSidebar as allowed item in dropdown ([@homotechsual](https://github.com/homotechsual))
|
||||
- [#6531](https://github.com/facebook/docusaurus/pull/6531) fix(theme-classic): highlight active collapsible doc category properly ([@lex111](https://github.com/lex111))
|
||||
- [#6515](https://github.com/facebook/docusaurus/pull/6515) fix(theme-classic): add key prop for SimpleLinks map ([@kgajera](https://github.com/kgajera))
|
||||
- [#6508](https://github.com/facebook/docusaurus/pull/6508) fix(theme-classic): apply width/height for footer logos without href ([@kgajera](https://github.com/kgajera))
|
||||
- `docusaurus-utils`
|
||||
- [#6617](https://github.com/facebook/docusaurus/pull/6617) fix(utils): convert Markdown links in reference-style links with multiple spaces ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6489](https://github.com/facebook/docusaurus/pull/6489) fix(utils): do not resolve Markdown paths with @site prefix ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6478](https://github.com/facebook/docusaurus/pull/6478) fix(utils): Markdown linkification match local paths beginning with http ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`
|
||||
- [#6495](https://github.com/facebook/docusaurus/pull/6495) fix(content-docs): render category with no subitems as a normal link ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
|
||||
#### :nail_care: Polish
|
||||
|
||||
- `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6755](https://github.com/facebook/docusaurus/pull/6755) refactor: unify error handling behavior ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`
|
||||
- [#6679](https://github.com/facebook/docusaurus/pull/6679) feat(create): better detection of package manager preference ([@lex111](https://github.com/lex111))
|
||||
- [#6481](https://github.com/facebook/docusaurus/pull/6481) refactor(init): promote good practices; use site alias ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6745](https://github.com/facebook/docusaurus/pull/6745) fix(content-docs): improve sidebar shorthand normalization error message ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6602](https://github.com/facebook/docusaurus/pull/6602) feat(content-docs): allow omitting enclosing array consistently for category shorthand ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6596](https://github.com/facebook/docusaurus/pull/6596) refactor(content-docs): clean up sidebars logic; validate generator returns ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6586](https://github.com/facebook/docusaurus/pull/6586) refactor(content-docs): read category metadata files before autogenerating ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus`
|
||||
- [#6730](https://github.com/facebook/docusaurus/pull/6730) refactor: declare all props as interfaces ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-translations`
|
||||
- [#6711](https://github.com/facebook/docusaurus/pull/6711) chore(theme-translations): complete Korean translations ([@revi](https://github.com/revi))
|
||||
- [#6686](https://github.com/facebook/docusaurus/pull/6686) fix(theme-translations): improve Korean translations ([@winterlood](https://github.com/winterlood))
|
||||
- [#6635](https://github.com/facebook/docusaurus/pull/6635) refactor(theme-translation): improve Traditional Chinese translation quality ([@toto6038](https://github.com/toto6038))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-translations`
|
||||
- [#6674](https://github.com/facebook/docusaurus/pull/6674) fix(theme-classic): improve aria label of color mode toggle ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-theme-classic`
|
||||
- [#6668](https://github.com/facebook/docusaurus/pull/6668) refactor: recommend using data-theme without html element selector ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6622](https://github.com/facebook/docusaurus/pull/6622) refactor(theme-classic): clean up CSS of doc sidebar item ([@lex111](https://github.com/lex111))
|
||||
- `docusaurus`
|
||||
- [#6644](https://github.com/facebook/docusaurus/pull/6644) fix(core): forward ref to Link's anchor element ([@koistya](https://github.com/koistya))
|
||||
- [#6646](https://github.com/facebook/docusaurus/pull/6646) fix(cli): make docusaurus clear also remove .yarn/.cache folder ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6306](https://github.com/facebook/docusaurus/pull/6306) feat(core): use react-helmet-async ([@seyoon20087](https://github.com/seyoon20087))
|
||||
- `docusaurus-utils-validation`
|
||||
- [#6656](https://github.com/facebook/docusaurus/pull/6656) feat: allow numbers in plugin ID ([@cdemonchy-pro](https://github.com/cdemonchy-pro))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-utils`, `lqip-loader`
|
||||
- [#6650](https://github.com/facebook/docusaurus/pull/6650) refactor(utils): replace hash with contenthash for file loader ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-preset-classic`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils-validation`, `docusaurus-utils`
|
||||
- [#6615](https://github.com/facebook/docusaurus/pull/6615) fix: remove more peer dependency warnings ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`
|
||||
- [#6598](https://github.com/facebook/docusaurus/pull/6598) feat: make Markdown images lazy loaded ([@johnnyreilly](https://github.com/johnnyreilly))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6505](https://github.com/facebook/docusaurus/pull/6505) fix(theme-classic): make focused link outlined with JS disabled ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6507](https://github.com/facebook/docusaurus/pull/6507) refactor: improve internal typing ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-sitemap`, `docusaurus-preset-classic`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils-validation`, `docusaurus-utils`
|
||||
- [#6498](https://github.com/facebook/docusaurus/pull/6498) fix: updating peerDependency fields for yarn berry ([@vidarc](https://github.com/vidarc))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`
|
||||
- [#6482](https://github.com/facebook/docusaurus/pull/6482) feat: mark some text labels as translatable ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
|
||||
#### :memo: Documentation
|
||||
|
||||
- Other
|
||||
- [#6727](https://github.com/facebook/docusaurus/pull/6727) docs: add Blog Matheus Brunelli site to showcase ([@mrbrunelli](https://github.com/mrbrunelli))
|
||||
- [#6721](https://github.com/facebook/docusaurus/pull/6721) docs: add Butterfly Documentation to showcase ([@CodeDoctorDE](https://github.com/CodeDoctorDE))
|
||||
- [#6710](https://github.com/facebook/docusaurus/pull/6710) docs(website): Add techharvesting to showcase ([@NaseelNiyas](https://github.com/NaseelNiyas))
|
||||
- [#6708](https://github.com/facebook/docusaurus/pull/6708) docs: add doc for generated-index keyword/image metadata ([@slorber](https://github.com/slorber))
|
||||
- [#6709](https://github.com/facebook/docusaurus/pull/6709) docs(website): fix video responsiveness ([@lex111](https://github.com/lex111))
|
||||
- [#6687](https://github.com/facebook/docusaurus/pull/6687) docs: add deep dive video for Docusaurus ([@dmitryvinn](https://github.com/dmitryvinn))
|
||||
- [#6704](https://github.com/facebook/docusaurus/pull/6704) docs(website): search doc typo searchParameters ([@slorber](https://github.com/slorber))
|
||||
- [#6682](https://github.com/facebook/docusaurus/pull/6682) docs: add redux-cool site to showcase ([@Ruben-Arushanyan](https://github.com/Ruben-Arushanyan))
|
||||
- [#6677](https://github.com/facebook/docusaurus/pull/6677) docs: add Rivalis to showcase ([@kalevski](https://github.com/kalevski))
|
||||
- [#6676](https://github.com/facebook/docusaurus/pull/6676) docs: add SmartCookieWeb site to showcase ([@CookieJarApps](https://github.com/CookieJarApps))
|
||||
- [#6675](https://github.com/facebook/docusaurus/pull/6675) docs: mention that all official themes are TypeScript-covered ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6673](https://github.com/facebook/docusaurus/pull/6673) docs: mention about blog date in front matter ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6672](https://github.com/facebook/docusaurus/pull/6672) refactor(website): extract homepage data from UI; feature text updates ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6670](https://github.com/facebook/docusaurus/pull/6670) docs: add CyberDrain Improved Partner Portal (CIPP) to showcase ([@homotechsual](https://github.com/homotechsual))
|
||||
- [#6667](https://github.com/facebook/docusaurus/pull/6667) fix(website): make YT iframe responsive ([@lex111](https://github.com/lex111))
|
||||
- [#6659](https://github.com/facebook/docusaurus/pull/6659) docs: add eli5 video to home page ([@dmitryvinn-fb](https://github.com/dmitryvinn-fb))
|
||||
- [#6633](https://github.com/facebook/docusaurus/pull/6633) docs: improve wording of using Markdown file paths ([@BigDataWriter](https://github.com/BigDataWriter))
|
||||
- [#6624](https://github.com/facebook/docusaurus/pull/6624) docs: add Resoto & Some Engineering Inc. to showcase ([@TheCatLady](https://github.com/TheCatLady))
|
||||
- [#6611](https://github.com/facebook/docusaurus/pull/6611) docs: fix bad anchor link syntax ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6591](https://github.com/facebook/docusaurus/pull/6591) docs: improve Github Actions example jobs ([@ebarojas](https://github.com/ebarojas))
|
||||
- [#6426](https://github.com/facebook/docusaurus/pull/6426) feat(website): add Tweets section ([@yangshun](https://github.com/yangshun))
|
||||
- [#6532](https://github.com/facebook/docusaurus/pull/6532) docs: add SAP Cloud SDK to showcase ([@artemkovalyov](https://github.com/artemkovalyov))
|
||||
- [#6513](https://github.com/facebook/docusaurus/pull/6513) docs: clean up CONTRIBUTING ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6501](https://github.com/facebook/docusaurus/pull/6501) docs: add Cloudflare pages deployment guide ([@apidev234](https://github.com/apidev234))
|
||||
- [#6499](https://github.com/facebook/docusaurus/pull/6499) docs: mention how env vars can be read ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6492](https://github.com/facebook/docusaurus/pull/6492) docs: mention where to find the sitemap ([@tamalweb](https://github.com/tamalweb))
|
||||
- [#6491](https://github.com/facebook/docusaurus/pull/6491) docs: add developers.verida to showcase ([@nick-verida](https://github.com/nick-verida))
|
||||
- [#6414](https://github.com/facebook/docusaurus/pull/6414) feat(website): new plugin to load CHANGELOG and render as blog ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6404](https://github.com/facebook/docusaurus/pull/6404) docs: elaborate on Markdown asset linking; document pathname:// protocol ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6484](https://github.com/facebook/docusaurus/pull/6484) docs: remove mention that CDN resources are cached cross-domain ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6429](https://github.com/facebook/docusaurus/pull/6429) refactor: self-host KaTeX assets ([@pranabdas](https://github.com/pranabdas))
|
||||
- [#6483](https://github.com/facebook/docusaurus/pull/6483) docs: mark a lot of website texts as translatable ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-preset-classic`
|
||||
- [#6627](https://github.com/facebook/docusaurus/pull/6627) docs: fix presets documentation link ([@thedanielhanke](https://github.com/thedanielhanke))
|
||||
|
||||
#### :house: Internal
|
||||
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6759](https://github.com/facebook/docusaurus/pull/6759) refactor(theme-classic): merge CSS files for Heading ([@slorber](https://github.com/slorber))
|
||||
- [#6584](https://github.com/facebook/docusaurus/pull/6584) misc: enable jsx-key eslint rule ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`
|
||||
- [#6756](https://github.com/facebook/docusaurus/pull/6756) test: sort migration test FS mock calls ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6609](https://github.com/facebook/docusaurus/pull/6609) refactor(migrate): change internal methods' parameter style ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6476](https://github.com/facebook/docusaurus/pull/6476) chore: fix Stylelint globs for editor support ([@nschonni](https://github.com/nschonni))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`
|
||||
- [#6744](https://github.com/facebook/docusaurus/pull/6744) fix(content-docs): properly display collocated social card image ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-types`, `docusaurus`
|
||||
- [#6742](https://github.com/facebook/docusaurus/pull/6742) refactor: improve client modules types ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`
|
||||
- [#6741](https://github.com/facebook/docusaurus/pull/6741) chore(module-type-aliases): add react as peer dependency ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6658](https://github.com/facebook/docusaurus/pull/6658) refactor(module-aliases): remove react-helmet dependency ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- Other
|
||||
- [#6726](https://github.com/facebook/docusaurus/pull/6726) misc: improve bug report template ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6512](https://github.com/facebook/docusaurus/pull/6512) misc: configure linguist behavior to show better language stats ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6487](https://github.com/facebook/docusaurus/pull/6487) chore: fix codesandbox example link + mention npm publish recovery ([@slorber](https://github.com/slorber))
|
||||
- [#6486](https://github.com/facebook/docusaurus/pull/6486) chore: update examples for beta.15 ([@slorber](https://github.com/slorber))
|
||||
- [#6485](https://github.com/facebook/docusaurus/pull/6485) fix(website): bad translate tags without default translation ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6716](https://github.com/facebook/docusaurus/pull/6716) refactor: ensure lodash is default-imported ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-logger`, `docusaurus-migrate`, `docusaurus`
|
||||
- [#6661](https://github.com/facebook/docusaurus/pull/6661) refactor: convert CLI entry points to ESM; migrate create-docusaurus to ESM ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-common`, `docusaurus`
|
||||
- [#6651](https://github.com/facebook/docusaurus/pull/6651) refactor: reduce exported members of docusaurus router ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`
|
||||
- [#6629](https://github.com/facebook/docusaurus/pull/6629) refactor: move module declarations for non-route components to theme-classic ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-pwa`, `docusaurus-theme-classic`
|
||||
- [#6614](https://github.com/facebook/docusaurus/pull/6614) refactor: remove Babel plugins that are included in preset-env ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-translations`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6605](https://github.com/facebook/docusaurus/pull/6605) chore: fix ESLint warnings, restrict export all syntax ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`
|
||||
- [#6583](https://github.com/facebook/docusaurus/pull/6583) refactor(live-codeblock): migrate theme to TS ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-common`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6524](https://github.com/facebook/docusaurus/pull/6524) refactor: enforce named capture groups; clean up regexes ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-plugin-content-docs`, `docusaurus`
|
||||
- [#6521](https://github.com/facebook/docusaurus/pull/6521) refactor: mark all functions that import external modules as async ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright`
|
||||
- [#6514](https://github.com/facebook/docusaurus/pull/6514) chore: clean up ESLint config, enable a few rules ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-types`, `docusaurus`
|
||||
- [#6511](https://github.com/facebook/docusaurus/pull/6511) refactor(core): convert theme-fallback to TS ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-utils`
|
||||
- [#6506](https://github.com/facebook/docusaurus/pull/6506) test: add test for readOutputHTMLFile ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-theme-common`
|
||||
- [#6502](https://github.com/facebook/docusaurus/pull/6502) refactor: fix all eslint warnings ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus`
|
||||
- [#6474](https://github.com/facebook/docusaurus/pull/6474) test: rename 'fixtures' to '**fixtures**' ([@nschonni](https://github.com/nschonni))
|
||||
|
||||
#### :running_woman: Performance
|
||||
|
||||
- `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6725](https://github.com/facebook/docusaurus/pull/6725) refactor: convert all fs methods to async ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
|
||||
#### Committers: 38
|
||||
|
||||
- Alexey Pyltsyn ([@lex111](https://github.com/lex111))
|
||||
- Artem Kovalov ([@artemkovalyov](https://github.com/artemkovalyov))
|
||||
- Balthasar Hofer ([@lebalz](https://github.com/lebalz))
|
||||
- Clement Demonchy ([@cdemonchy-pro](https://github.com/cdemonchy-pro))
|
||||
- CodeDoctor ([@CodeDoctorDE](https://github.com/CodeDoctorDE))
|
||||
- Daniel Hanke ([@thedanielhanke](https://github.com/thedanielhanke))
|
||||
- Daniel Kalevski ([@kalevski](https://github.com/kalevski))
|
||||
- Dmitry Vinnik ([@dmitryvinn](https://github.com/dmitryvinn))
|
||||
- Dmitry Vinnik | Meta ([@dmitryvinn-fb](https://github.com/dmitryvinn-fb))
|
||||
- Erick Zhao ([@erickzhao](https://github.com/erickzhao))
|
||||
- Everardo J. Barojas M. ([@ebarojas](https://github.com/ebarojas))
|
||||
- Felipe Santos ([@felipecrs](https://github.com/felipecrs))
|
||||
- Gaurish ([@apidev234](https://github.com/apidev234))
|
||||
- Hong Yongmin ([@revi](https://github.com/revi))
|
||||
- Jody Heavener ([@jodyheavener](https://github.com/jodyheavener))
|
||||
- John Reilly ([@johnnyreilly](https://github.com/johnnyreilly))
|
||||
- Joshua Chen ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- Kishan Gajera ([@kgajera](https://github.com/kgajera))
|
||||
- Konstantin Tarkus ([@koistya](https://github.com/koistya))
|
||||
- Matheus Ricardo Brunelli ([@mrbrunelli](https://github.com/mrbrunelli))
|
||||
- Matthew Ailes ([@vidarc](https://github.com/vidarc))
|
||||
- Mikey O'Toole ([@homotechsual](https://github.com/homotechsual))
|
||||
- Miles Johnson ([@milesj](https://github.com/milesj))
|
||||
- Muhammad Redho Ayassa ([@redhoyasa](https://github.com/redhoyasa))
|
||||
- Naseel Niyas ([@NaseelNiyas](https://github.com/NaseelNiyas))
|
||||
- Nick Schonning ([@nschonni](https://github.com/nschonni))
|
||||
- Pranab Das ([@pranabdas](https://github.com/pranabdas))
|
||||
- Ruben Arushanyan ([@Ruben-Arushanyan](https://github.com/Ruben-Arushanyan))
|
||||
- Sébastien Lorber ([@slorber](https://github.com/slorber))
|
||||
- Tamal Web ([@tamalweb](https://github.com/tamalweb))
|
||||
- Yangshun Tay ([@yangshun](https://github.com/yangshun))
|
||||
- [@BigDataWriter](https://github.com/BigDataWriter)
|
||||
- [@CookieJarApps](https://github.com/CookieJarApps)
|
||||
- [@TheCatLady](https://github.com/TheCatLady)
|
||||
- [@nick-verida](https://github.com/nick-verida)
|
||||
- [@seyoon20087](https://github.com/seyoon20087)
|
||||
- [@toto6038](https://github.com/toto6038)
|
||||
- 이정환 ([@winterlood](https://github.com/winterlood))
|
||||
|
||||
## 2.0.0-beta.15 (2022-01-26)
|
||||
|
||||
#### :rocket: New Feature
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
:::caution
|
||||
|
||||
We discourage swizzling of components during the Docusaurus 2 beta phase. The theme components APIs are likely to evolve and have breaking changes. If possible, stick with the default appearance for now.
|
||||
|
||||
:::
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Routing
|
||||
|
||||
This page is only accessible through version-switching. It shows how a versioned doc file becomes a webpage.
|
||||
|
||||
```mdx-code-block
|
||||
import {useLatestVersion, useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
|
||||
import {useLocation} from '@docusaurus/router';
|
||||
|
||||
export const URLPath = () => <code>{useLocation().pathname}</code>;
|
||||
|
||||
export const FilePath = () => {
|
||||
const currentVersion = useActiveDocContext('default').activeVersion.name;
|
||||
return <code>{currentVersion === 'current' ? './docs/' : `./versioned_docs/version-${currentVersion}/`}advanced/routing.md</code>;
|
||||
}
|
||||
```
|
||||
|
||||
This page, <URLPath />, is generated from the file at <FilePath />. The component used is `@theme/DocItem`.
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
---
|
||||
sidebar_position: 4
|
||||
id: plugin-client-redirects
|
||||
title: '📦 plugin-client-redirects'
|
||||
slug: '/api/plugins/@docusaurus/plugin-client-redirects'
|
||||
---
|
||||
|
||||
Docusaurus Plugin to generate **client-side redirects**.
|
||||
|
||||
This plugin will write additional HTML pages to your static site, that redirects the user to your existing Docusaurus pages with JavaScript.
|
||||
|
||||
:::note
|
||||
|
||||
This plugin only create redirects for the production build.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
It is better to use server-side redirects whenever possible.
|
||||
|
||||
Before using this plugin, you should look if your hosting provider doesn't offer this feature.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-client-redirects
|
||||
```
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Main usecase: you have `/myDocusaurusPage`, and you want to redirect to this page from `/myDocusaurusPage.html`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
{
|
||||
fromExtensions: ['html'],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Second usecase: you have `/myDocusaurusPage.html`, and you want to redirect to this page from `/myDocusaurusPage`.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
{
|
||||
toExtensions: ['html'],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
For custom redirect logic, provide your own `createRedirects` function.
|
||||
|
||||
Let's imagine you change the url of an existing page, you might want to make sure the old url still works:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
{
|
||||
redirects: [
|
||||
{
|
||||
to: '/docs/newDocPath', // string
|
||||
from: ['/docs/oldDocPathFrom2019', '/docs/legacyDocPathFrom2016'], // string | string[]
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
It's possible to use a function to create the redirects for each existing path:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
{
|
||||
createRedirects: function (existingPath) {
|
||||
if (existingPath === '/docs/newDocPath') {
|
||||
return ['/docs/oldDocPathFrom2019', '/docs/legacyDocPathFrom2016']; // string | string[]
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Finally, it's possible to use all options at the same time:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
{
|
||||
fromExtensions: ['html', 'htm'],
|
||||
toExtensions: ['exe', 'zip'],
|
||||
redirects: [
|
||||
{
|
||||
to: '/docs/newDocPath',
|
||||
from: '/docs/oldDocPath',
|
||||
},
|
||||
],
|
||||
createRedirects: function (existingPath) {
|
||||
if (existingPath === '/docs/newDocPath2') {
|
||||
return ['/docs/oldDocPath2'];
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
---
|
||||
sidebar_position: 5
|
||||
id: plugin-debug
|
||||
title: '📦 plugin-debug'
|
||||
slug: '/api/plugins/@docusaurus/plugin-debug'
|
||||
---
|
||||
|
||||
The debug plugin will display useful debug information at [http://localhost:3000/\_\_docusaurus/debug](http://localhost:3000/__docusaurus/debug).
|
||||
|
||||
It is mostly useful for plugin authors, that will be able to inspect more easily the content of the `.docusaurus` folder (like the creates routes), but also be able to inspect data structures that are never written to disk, like the plugin data loaded through the `contentLoaded` lifecycle.
|
||||
|
||||
:::note
|
||||
|
||||
If you report a bug, we will probably ask you to have this plugin turned on in the production, so that we can inspect your deployment config more easily.
|
||||
|
||||
If you don't have any sensitive information, you can keep it on in production [like we do](http://docusaurus.io/__docusaurus/debug).
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-debug
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you have installed `@docusaurus/preset-classic`, you don't need to install it as a dependency. You can also configure it through the [classic preset options](presets.md#docusauruspreset-classic) instead of doing it like below.
|
||||
|
||||
By default, it's enabled in dev, and disabled in prod, to avoid exposing potentially sensitive information.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: ['@docusaurus/plugin-debug'],
|
||||
};
|
||||
```
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
---
|
||||
sidebar_position: 6
|
||||
id: plugin-google-analytics
|
||||
title: '📦 plugin-google-analytics'
|
||||
slug: '/api/plugins/@docusaurus/plugin-google-analytics'
|
||||
---
|
||||
|
||||
The default [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/) plugin. It is a JavaScript library for measuring how users interact with your website **in the production build**. If you are using Google Analytics 4 you might need to consider using [plugin-google-gtag](./plugin-google-gtag.md) instead.
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-google-analytics
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you have installed `@docusaurus/preset-classic`, you don't need to install it as a dependency.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<small>
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `trackingID` | `string` | **Required** | The tracking ID of your analytics service. |
|
||||
| `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
|
||||
|
||||
</small>
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration object.
|
||||
|
||||
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
const config = {
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
};
|
||||
```
|
||||
|
||||
### Preset options {#ex-config-preset}
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-start
|
||||
googleAnalytics: {
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin options {#ex-config-plugin}
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-google-analytics',
|
||||
// highlight-start
|
||||
{
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
---
|
||||
sidebar_position: 7
|
||||
id: plugin-google-gtag
|
||||
title: '📦 plugin-google-gtag'
|
||||
slug: '/api/plugins/@docusaurus/plugin-google-gtag'
|
||||
---
|
||||
|
||||
The default [Global Site Tag (gtag.js)](https://developers.google.com/analytics/devguides/collection/gtagjs/) plugin. It is a JavaScript tagging framework and API that allows you to send event data to Google Analytics, Google Ads, and Google Marketing Platform, **in the production build**. This section describes how to configure a Docusaurus site to enable global site tag for Google Analytics.
|
||||
|
||||
:::tip
|
||||
|
||||
You can use [Google's Tag Assistant](https://tagassistant.google.com/) tool to check if your gtag is set up correctly!
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-google-gtag
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you have installed `@docusaurus/preset-classic`, you don't need to install it as a dependency.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<small>
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `trackingID` | `string` | **Required** | The tracking ID of your gtag service. |
|
||||
| `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
|
||||
|
||||
</small>
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration object.
|
||||
|
||||
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
const config = {
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
};
|
||||
```
|
||||
|
||||
### Preset options {#ex-config-preset}
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-start
|
||||
gtag: {
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin options {#ex-config-plugin}
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-google-gtag',
|
||||
// highlight-start
|
||||
{
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
---
|
||||
sidebar_position: 8
|
||||
id: plugin-ideal-image
|
||||
title: '📦 plugin-ideal-image'
|
||||
slug: '/api/plugins/@docusaurus/plugin-ideal-image'
|
||||
---
|
||||
|
||||
Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder) **in the production builds**.
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-ideal-image
|
||||
```
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Modify your `docusaurus.config.js`
|
||||
|
||||
```js {3}
|
||||
module.exports = {
|
||||
...
|
||||
plugins: ['@docusaurus/plugin-ideal-image'],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
This plugin supports the PNG and JPG formats only.
|
||||
|
||||
```jsx
|
||||
import Image from '@theme/IdealImage';
|
||||
import thumbnail from './path/to/img.png';
|
||||
|
||||
// your React code
|
||||
<Image img={thumbnail} />
|
||||
|
||||
// or
|
||||
<Image img={require('./path/to/img.png')} />
|
||||
```
|
||||
|
||||
## Options {#options}
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | `string` | `ideal-img/[name].[hash:hex:7].[width].[ext]` | Filename template for output files. |
|
||||
| `sizes` | `array` | _original size_ | Specify all widths you want to use. If a specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up). |
|
||||
| `size` | `integer` | _original size_ | Specify one width you want to use; if the specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up) |
|
||||
| `min` | `integer` | | As an alternative to manually specifying `sizes`, you can specify `min`, `max` and `steps`, and the sizes will be generated for you. |
|
||||
| `max` | `integer` | | See `min` above |
|
||||
| `steps` | `integer` | `4` | Configure the number of images generated between `min` and `max` (inclusive) |
|
||||
| `quality` | `integer` | `85` | JPEG compression quality |
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
sidebar_position: 10
|
||||
id: plugin-sitemap
|
||||
title: '📦 plugin-sitemap'
|
||||
slug: '/api/plugins/@docusaurus/plugin-sitemap'
|
||||
---
|
||||
|
||||
This plugin creates sitemap for your site so that search engine crawlers can crawl your site more accurately.
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-sitemap
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you have installed `@docusaurus/preset-classic`, you don't need to install it as a dependency. You can also configure it through the [classic preset options](presets.md#docusauruspreset-classic) instead of doing it like below.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-sitemap',
|
||||
{
|
||||
changefreq: 'weekly',
|
||||
priority: 0.5,
|
||||
trailingSlash: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,216 +0,0 @@
|
|||
---
|
||||
id: versioning
|
||||
title: Versioning
|
||||
slug: /versioning
|
||||
---
|
||||
|
||||
You can use the version script to create a new documentation version based on the latest content in the `docs` directory. That specific set of documentation will then be preserved and accessible even as the documentation in the `docs` directory changes moving forward.
|
||||
|
||||
:::caution
|
||||
|
||||
Think about it before starting to version your documentation - it can become difficult for contributors to help improve it!
|
||||
|
||||
:::
|
||||
|
||||
Most of the time, you don't need versioning as it will just increase your build time, and introduce complexity to your codebase. Versioning is **best suited for websites with high-traffic and rapid changes to documentation between versions**. If your documentation rarely changes, don't add versioning to your documentation.
|
||||
|
||||
To better understand how versioning works and see if it suits your needs, you can read on below.
|
||||
|
||||
## Directory structure {#directory-structure}
|
||||
|
||||
```shell
|
||||
website
|
||||
├── sidebars.json # sidebar for the current docs version
|
||||
├── docs # docs directory for the current docs version
|
||||
│ ├── foo
|
||||
│ │ └── bar.md # https://mysite.com/docs/next/foo/bar
|
||||
│ └── hello.md # https://mysite.com/docs/next/hello
|
||||
├── versions.json # file to indicate what versions are available
|
||||
├── versioned_docs
|
||||
│ ├── version-1.1.0
|
||||
│ │ ├── foo
|
||||
│ │ │ └── bar.md # https://mysite.com/docs/foo/bar
|
||||
│ │ └── hello.md
|
||||
│ └── version-1.0.0
|
||||
│ ├── foo
|
||||
│ │ └── bar.md # https://mysite.com/docs/1.0.0/foo/bar
|
||||
│ └── hello.md
|
||||
├── versioned_sidebars
|
||||
│ ├── version-1.1.0-sidebars.json
|
||||
│ └── version-1.0.0-sidebars.json
|
||||
├── docusaurus.config.js
|
||||
└── package.json
|
||||
```
|
||||
|
||||
The table below explains how a versioned file maps to its version and the generated URL.
|
||||
|
||||
| Path | Version | URL |
|
||||
| --------------------------------------- | -------------- | ----------------- |
|
||||
| `versioned_docs/version-1.0.0/hello.md` | 1.0.0 | /docs/1.0.0/hello |
|
||||
| `versioned_docs/version-1.1.0/hello.md` | 1.1.0 (latest) | /docs/hello |
|
||||
| `docs/hello.md` | current | /docs/next/hello |
|
||||
|
||||
:::tip
|
||||
|
||||
The files in the `docs` directory belong to the `current` docs version.
|
||||
|
||||
By default, the `current` docs version is labelled as `Next` and hosted under `/docs/next/*`, but is entirely configurable to fit your project's release lifecycle.
|
||||
|
||||
:::
|
||||
|
||||
### Tagging a new version {#tagging-a-new-version}
|
||||
|
||||
1. First, make sure the current docs version (the `docs` directory) is ready to be frozen.
|
||||
1. Enter a new version number.
|
||||
|
||||
```bash npm2yarn
|
||||
npm run docusaurus docs:version 1.1.0
|
||||
```
|
||||
|
||||
When tagging a new version, the document versioning mechanism will:
|
||||
|
||||
- Copy the full `docs/` folder contents into a new `versioned_docs/version-[versionName]/` folder.
|
||||
- Create a versioned sidebars file based from your current [sidebar](docs-introduction.md#sidebar) configuration (if it exists) - saved as `versioned_sidebars/version-[versionName]-sidebars.json`.
|
||||
- Append the new version number to `versions.json`.
|
||||
|
||||
## Docs {#docs}
|
||||
|
||||
### Creating new docs {#creating-new-docs}
|
||||
|
||||
1. Place the new file into the corresponding version folder.
|
||||
1. Include the reference for the new file into the corresponding sidebar file, according to version number.
|
||||
|
||||
**Current version docs**
|
||||
|
||||
```shell
|
||||
# The new file.
|
||||
docs/new.md
|
||||
|
||||
# Edit the corresponding sidebar file.
|
||||
sidebar.js
|
||||
```
|
||||
|
||||
**Older version docs**
|
||||
|
||||
```shell
|
||||
# The new file.
|
||||
versioned_docs/version-1.0.0/new.md
|
||||
|
||||
# Edit the corresponding sidebar file.
|
||||
versioned_sidebars/version-1.0.0-sidebars.json
|
||||
```
|
||||
|
||||
### Linking docs {#linking-docs}
|
||||
|
||||
- Remember to include the `.md` extension.
|
||||
- Files will be linked to correct corresponding version.
|
||||
- Relative paths work as well.
|
||||
|
||||
```md
|
||||
The [@hello](hello.md#paginate) document is great!
|
||||
|
||||
See the [Tutorial](../getting-started/tutorial.md) for more info.
|
||||
```
|
||||
|
||||
## Versions {#versions}
|
||||
|
||||
Each directory in `versioned_docs/` will represent a documentation version.
|
||||
|
||||
### Updating an existing version {#updating-an-existing-version}
|
||||
|
||||
You can update multiple docs versions at the same time because each directory in `versioned_docs/` represents specific routes when published.
|
||||
|
||||
1. Edit any file.
|
||||
1. Commit and push changes.
|
||||
1. It will be published to the version.
|
||||
|
||||
Example: When you change any file in `versioned_docs/version-2.6/`, it will only affect the docs for version `2.6`.
|
||||
|
||||
### Deleting an existing version {#deleting-an-existing-version}
|
||||
|
||||
You can delete/remove versions as well.
|
||||
|
||||
1. Remove the version from `versions.json`.
|
||||
|
||||
Example:
|
||||
|
||||
```diff {4}
|
||||
[
|
||||
"2.0.0",
|
||||
"1.9.0",
|
||||
- "1.8.0"
|
||||
]
|
||||
```
|
||||
|
||||
2. Delete the versioned docs directory. Example: `versioned_docs/version-1.8.0`.
|
||||
3. Delete the versioned sidebars file. Example: `versioned_sidebars/version-1.8.0-sidebars.json`.
|
||||
|
||||
## Recommended practices {#recommended-practices}
|
||||
|
||||
### Figure out the behavior for the "current" version {#figure-out-the-behavior-for-the-current-version}
|
||||
|
||||
The "current" version is the version name for the `./docs` folder.
|
||||
|
||||
There are different ways to manage versioning, but two very common patterns are:
|
||||
|
||||
- You release v1, and start immediately working on v2 (including its docs)
|
||||
- You release v1, and will maintain it for some time before thinking about v2.
|
||||
|
||||
Docusaurus defaults work great for the first usecase.
|
||||
|
||||
**For the 2nd usecase**: if you release v1 and don't plan to work on v2 anytime soon, instead of versioning v1 and having to maintain the docs in 2 folders (`./docs` + `./versioned_docs/version-1.0.0`), you may consider using the following configuration instead:
|
||||
|
||||
```json
|
||||
{
|
||||
"lastVersion": "current",
|
||||
"versions": {
|
||||
"current": {
|
||||
"label": "1.0.0",
|
||||
"path": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The docs in `./docs` will be served at `/docs/1.0.0` instead of `/docs/next`, and `1.0.0` will become the default version we link to in the navbar dropdown, and you will only need to maintain a single `./docs` folder.
|
||||
|
||||
See [docs plugin configuration](../../api/plugins/plugin-content-docs.md) for more details.
|
||||
|
||||
### Version your documentation only when needed {#version-your-documentation-only-when-needed}
|
||||
|
||||
For example, you are building a documentation for your npm package `foo` and you are currently in version 1.0.0. You then release a patch version for a minor bug fix and it's now 1.0.1.
|
||||
|
||||
Should you cut a new documentation version 1.0.1? **You probably shouldn't**. 1.0.1 and 1.0.0 docs shouldn't differ according to semver because there are no new features!. Cutting a new version for it will only just create unnecessary duplicated files.
|
||||
|
||||
### Keep the number of versions small {#keep-the-number-of-versions-small}
|
||||
|
||||
As a good rule of thumb, try to keep the number of your versions below 10. **It is very likely** that you will have a lot of obsolete versioned documentation that nobody even reads anymore. For example, [Jest](https://jestjs.io/versions) is currently in version `24.9`, and only maintains several latest documentation versions with the lowest being `22.X`. Keep it small 😊
|
||||
|
||||
### Use absolute import within the docs {#use-absolute-import-within-the-docs}
|
||||
|
||||
Don't use relative paths import within the docs. Because when we cut a version the paths no longer work (the nesting level is different, among other reasons). You can utilize the `@site` alias provided by Docusaurus, that points to the `website` directory. Example:
|
||||
|
||||
```diff
|
||||
- import Foo from '../src/components/Foo';
|
||||
+ import Foo from '@site/src/components/Foo';
|
||||
```
|
||||
|
||||
### Global or versioned collocated assets {#global-or-versioned-collocated-assets}
|
||||
|
||||
You should decide if assets like images and files are per version or shared between versions
|
||||
|
||||
If your assets should be versioned, put them in the docs version, and use relative paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[download this file](./file.pdf)
|
||||
```
|
||||
|
||||
If your assets are global, put them in `/static` and use absolute paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[download this file](/file.pdf)
|
||||
```
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
---
|
||||
id: math-equations
|
||||
title: Math Equations
|
||||
description: Writing LaTeX Math Equations
|
||||
slug: /markdown-features/math-equations
|
||||
---
|
||||
|
||||
Mathematical equations can be rendered using [KaTeX](https://katex.org).
|
||||
|
||||
## Usage
|
||||
|
||||
Please read [KaTeX](https://katex.org) documentation for more details.
|
||||
|
||||
### Inline
|
||||
|
||||
Write inline math equations by wrapping LaTeX equations between `$`:
|
||||
|
||||
```mdx
|
||||
Let $f:[a,b] \to \R$ be Riemann integrable. Let $F:[a,b]\to\R$ be $F(x)=
|
||||
\int_{a}^{x}f(t)dt$. Then $$F$$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
```
|
||||
|
||||
Let $f:[a,b] \to \R$ be Riemann integrable. Let $F:[a,b]\to\R$ be $F(x)=
|
||||
\int_{a}^{x}f(t)dt$. Then $F$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
|
||||
### Blocks
|
||||
|
||||
For equation block or display mode, use line breaks and `$$`:
|
||||
|
||||
```mdx
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x) dx
|
||||
$$
|
||||
```
|
||||
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x) dx
|
||||
$$
|
||||
|
||||
## Configuration
|
||||
|
||||
To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save remark-math@3 rehype-katex@4 hast-util-is-element@1.1.0
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
Use the exact same versions. The latest versions are incompatible with Docusaurus 2.
|
||||
|
||||
:::
|
||||
|
||||
Import the plugins in `docusaurus.config.js`:
|
||||
|
||||
```js
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
```
|
||||
|
||||
Add them to your content plugin or preset options (usually `@docusaurus/preset-classic` docs options):
|
||||
|
||||
```js
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
```
|
||||
|
||||
Include the KaTeX CSS in your config under `stylesheets`:
|
||||
|
||||
```js
|
||||
stylesheets: [
|
||||
{
|
||||
href: "https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css",
|
||||
integrity: "sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc",
|
||||
crossorigin: "anonymous",
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Overall the changes look like:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-start
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
// highlight-end
|
||||
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// highlight-start
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css',
|
||||
integrity:
|
||||
'sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
---
|
||||
id: react
|
||||
title: MDX and React
|
||||
description: Using the power of React in Docusaurus Markdown documents, thanks to MDX
|
||||
slug: /markdown-features/react
|
||||
---
|
||||
|
||||
# MDX and React
|
||||
|
||||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
```
|
||||
|
||||
## Using JSX in Markdown {#using-jsx-in-markdown}
|
||||
|
||||
Docusaurus has built-in support for [MDX v1](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components.
|
||||
|
||||
:::note
|
||||
|
||||
While both `.md` and `.mdx` files are parsed using MDX, some of the syntax are treated slightly differently. For the most accurate parsing and better editor support, we recommend using the `.mdx` extension for files containing MDX syntax.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
MDX is not [100% compatible with CommonMark](https://github.com/facebook/docusaurus/issues/3018).
|
||||
|
||||
Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.
|
||||
|
||||
:::
|
||||
|
||||
Try this block here:
|
||||
|
||||
```jsx
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
```
|
||||
|
||||
Notice how it renders both the markup from your React component and the Markdown syntax:
|
||||
|
||||
```mdx-code-block
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<BrowserWindow minHeight={240} url="http://localhost:3000">
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight>
|
||||
{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
You can also import your own components defined in other files or third-party components installed via npm! Check out the [MDX docs](https://mdxjs.com/) to see what other fancy stuff you can do with MDX.
|
||||
|
||||
:::caution
|
||||
|
||||
Since all doc files are parsed using MDX, any HTML is treated as JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects. This behavior is different from Docusaurus 1. See also [Migrating from v1 to v2](../../migration/migration-manual.md#convert-style-attributes-to-style-objects-in-mdx).
|
||||
|
||||
:::
|
||||
|
||||
## Importing code snippets {#importing-code-snippets}
|
||||
|
||||
You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/). In order to use `raw-loader`, first you need to install it in your project:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save raw-loader
|
||||
```
|
||||
|
||||
Now you can import code snippets from another file as it is:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!./myComponent';
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```mdx-code-block
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponent';
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
<br />
|
||||
```
|
||||
|
||||
You can also pass `title` prop to `CodeBlock` component in order to appear it as header above your codeblock:
|
||||
|
||||
```jsx
|
||||
<CodeBlock className="language-jsx" title="/src/myComponent">
|
||||
{MyComponentSource}
|
||||
</CodeBlock>
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want JSX to insert the imported text here.
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
This feature is experimental and might be subject to API breaking changes in the future.
|
||||
|
||||
:::
|
||||
|
||||
## Importing Markdown {#importing-markdown}
|
||||
|
||||
You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages.
|
||||
|
||||
By convention, using the **`_` filename prefix** will not create any doc page and means the markdown file is a **"partial"**, to be imported by other files.
|
||||
|
||||
```md title="_markdown-partial-example.mdx"
|
||||
<span>Hello {props.name}</span>
|
||||
|
||||
This is text some content from `_markdown-partial-example.mdx`.
|
||||
```
|
||||
|
||||
```jsx title="someOtherDoc.mdx"
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<PartialExample name="Sebastien" />;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
<PartialExample name="Sebastien" />
|
||||
</BrowserWindow>
|
||||
|
||||
<br />
|
||||
```
|
||||
|
||||
This way, you can reuse contents among multiple pages and avoid duplicating materials.
|
||||
|
||||
:::caution
|
||||
|
||||
The table-of-contents does not currently contain the imported Markdown headings. This is a technical limitation that we are trying to solve ([issue](https://github.com/facebook/docusaurus/issues/3915)).
|
||||
|
||||
:::
|
||||
|
||||
## Available exports
|
||||
|
||||
Within the MDX page, the following variables are available as globals:
|
||||
|
||||
- `frontMatter`: the front matter as a record of string keys and values;
|
||||
- `toc`: the table of contents, as a tree of headings. See also [Inline TOC](./markdown-features-inline-toc.mdx) for a more concrete use-case.
|
||||
- `contentTitle`: the Markdown title, which is the first `h1` heading in the Markdown text. It's `undefined` if there isn't one (e.g. title specified in the front matter).
|
||||
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
|
@ -1,336 +0,0 @@
|
|||
---
|
||||
id: tutorial
|
||||
title: i18n - Tutorial
|
||||
slug: /i18n/tutorial
|
||||
---
|
||||
|
||||
This tutorial will walk you through the basis of the **Docusaurus i18n system**.
|
||||
|
||||
We will add **French** translations to a **newly initialized English Docusaurus website**.
|
||||
|
||||
Initialize a new site with `npx create-docusaurus@latest website classic` (like [this one](https://github.com/facebook/docusaurus/tree/main/examples/classic)).
|
||||
|
||||
## Configure your site {#configure-your-site}
|
||||
|
||||
Modify `docusaurus.config.js` to add the i18n support for the French language.
|
||||
|
||||
### Site configuration {#site-configuration}
|
||||
|
||||
Use the [site i18n configuration](./../api/docusaurus.config.js.md#i18n) to declare the i18n locales:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'fr'],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Theme configuration {#theme-configuration}
|
||||
|
||||
Add a **navbar item** of type `localeDropdown` so that users can select the locale they want:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'localeDropdown',
|
||||
position: 'left',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Start your site {#start-your-site}
|
||||
|
||||
Start your localized site in dev mode, using the locale of your choice:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run start -- --locale fr
|
||||
```
|
||||
|
||||
Your site is accessible at **`http://localhost:3000/fr/`**.
|
||||
|
||||
We haven't provided any translation, and the site is **mostly untranslated**.
|
||||
|
||||
:::tip
|
||||
|
||||
Docusaurus provides **default translations** for generic theme labels, such as "Next" and "Previous" for the pagination.
|
||||
|
||||
Please help us complete those **[default translations](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-translations/locales)**.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Each locale is a **distinct standalone single-page-application**: it is not possible to start the Docusaurus sites in all locales at the same time.
|
||||
|
||||
:::
|
||||
|
||||
## Translate your site {#translate-your-site}
|
||||
|
||||
The French translations will be added in `website/i18n/fr`.
|
||||
|
||||
Docusaurus is modular, and each content plugin has its own subfolder.
|
||||
|
||||
:::note
|
||||
|
||||
After copying files around, restart your site with `npm run start -- --locale fr`.
|
||||
|
||||
Hot-reload will work better when editing existing files.
|
||||
|
||||
:::
|
||||
|
||||
### Use the translation APIs {#use-the-translation-apis}
|
||||
|
||||
Open the homepage, and use the [translation APIs](../docusaurus-core.md#translate):
|
||||
|
||||
```jsx title="src/pages/index.js"
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
// highlight-start
|
||||
import Translate, {translate} from '@docusaurus/Translate';
|
||||
// highlight-end
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>
|
||||
{/* highlight-start */}
|
||||
<Translate>Welcome to my website</Translate>
|
||||
{/* highlight-end */}
|
||||
</h1>
|
||||
<main>
|
||||
{/* highlight-start */}
|
||||
<Translate
|
||||
id="homepage.visitMyBlog"
|
||||
description="The homepage message to ask the user to visit my blog"
|
||||
values={{blog: <Link to="https://docusaurus.io/blog">blog</Link>}}>
|
||||
{'You can also visit my {blog}'}
|
||||
</Translate>
|
||||
{/* highlight-end */}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder={
|
||||
// highlight-start
|
||||
translate({
|
||||
message: 'Hello',
|
||||
description: 'The homepage input placeholder',
|
||||
})
|
||||
// highlight-end
|
||||
}
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
Docusaurus provides a **very small and lightweight translation runtime** on purpose, and only supports basic [placeholders interpolation](../docusaurus-core.md#interpolate), using a subset of the [ICU Message Format](https://formatjs.io/docs/core-concepts/icu-syntax/).
|
||||
|
||||
Most documentation websites are generally **static** and don't need advanced i18n features (**plurals**, **genders**, etc.). Use a library like [react-intl](https://www.npmjs.com/package/react-intl) for more advanced use-cases.
|
||||
|
||||
:::
|
||||
|
||||
### Translate JSON files {#translate-json-files}
|
||||
|
||||
JSON translation files are used for everything that is not contained in a Markdown document:
|
||||
|
||||
- React/JSX code
|
||||
- Layout navbar and footer labels
|
||||
- Docs sidebar category labels
|
||||
- ...
|
||||
|
||||
Run the [write-translations](../cli.md#docusaurus-write-translations-sitedir) command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run write-translations -- --locale fr
|
||||
```
|
||||
|
||||
It will extract and initialize the JSON translation files that you need to translate.
|
||||
|
||||
The homepage translations are statically extracted from React source code:
|
||||
|
||||
```json title="i18n/fr/code.json"
|
||||
{
|
||||
"Welcome to my website": {
|
||||
"message": "Welcome to my website",
|
||||
"description": "The homepage welcome message"
|
||||
},
|
||||
"Hello": {
|
||||
"message": "Hello",
|
||||
"description": "The homepage input placeholder"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Plugins and themes will also write their own **JSON translation files**, such as:
|
||||
|
||||
```json title="i18n/fr/docusaurus-theme-classic/navbar.json"
|
||||
{
|
||||
"title": {
|
||||
"message": "My Site",
|
||||
"description": "The title in the navbar"
|
||||
},
|
||||
"item.label.Docs": {
|
||||
"message": "Docs",
|
||||
"description": "Navbar item with label Docs"
|
||||
},
|
||||
"item.label.Blog": {
|
||||
"message": "Blog",
|
||||
"description": "Navbar item with label Blog"
|
||||
},
|
||||
"item.label.GitHub": {
|
||||
"message": "GitHub",
|
||||
"description": "Navbar item with label GitHub"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Translate the `message` attribute in the JSON files of `i18n/fr`, and your site layout and homepage should now be translated.
|
||||
|
||||
### Translate Markdown files {#translate-markdown-files}
|
||||
|
||||
Official Docusaurus content plugins extensively use Markdown/MDX files, and allow you to translate them.
|
||||
|
||||
#### Translate the docs {#translate-the-docs}
|
||||
|
||||
Copy your docs Markdown files to `i18n/fr/docusaurus-plugin-content-docs/current`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current
|
||||
cp -r docs/** i18n/fr/docusaurus-plugin-content-docs/current
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
`current` is needed for the docs versioning feature: each docs version has its own subfolder.
|
||||
|
||||
:::
|
||||
|
||||
#### Translate the blog {#translate-the-blog}
|
||||
|
||||
Copy your blog Markdown files to `i18n/fr/docusaurus-plugin-content-blog`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-blog
|
||||
cp -r blog/** i18n/fr/docusaurus-plugin-content-blog
|
||||
```
|
||||
|
||||
#### Translate the pages {#translate-the-pages}
|
||||
|
||||
Copy your pages Markdown files to `i18n/fr/docusaurus-plugin-content-pages`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-pages
|
||||
cp -r src/pages/**.md i18n/fr/docusaurus-plugin-content-pages
|
||||
cp -r src/pages/**.mdx i18n/fr/docusaurus-plugin-content-pages
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
We only copy `.md` and `.mdx` files, as pages React components are translated through JSON translation files already.
|
||||
|
||||
:::
|
||||
|
||||
### Use explicit heading ids {#use-explicit-heading-ids}
|
||||
|
||||
By default, a Markdown heading `### Hello World` will have a generated id `hello-world`.
|
||||
|
||||
Other documents can target it with `[link](#hello-world)`.
|
||||
|
||||
The translated heading becomes `### Bonjour le Monde`, with id `bonjour-le-monde`.
|
||||
|
||||
Generated ids are not always a good fit for localized sites, as it requires you to localize all the anchor links:
|
||||
|
||||
```diff
|
||||
- [link](#hello-world).
|
||||
+ [link](#bonjour-le-monde)
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
For localized sites, it is recommended to use **[explicit heading ids](../guides/markdown-features/markdown-features-headings.mdx#explicit-ids)**.
|
||||
|
||||
:::
|
||||
|
||||
## Deploy your site {#deploy-your-site}
|
||||
|
||||
You can choose to deploy your site under a **single domain**, or use **multiple (sub)domains**.
|
||||
|
||||
### Single-domain deployment {#single-domain-deployment}
|
||||
|
||||
Run the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
```
|
||||
|
||||
Docusaurus will build **one single-page application per locale**:
|
||||
|
||||
- `website/build`: for the default, English language
|
||||
- `website/build/fr`: for the French language
|
||||
|
||||
You can now [deploy](../deployment.mdx) the `build` folder to the static hosting solution of your choice.
|
||||
|
||||
:::note
|
||||
|
||||
The Docusaurus v2 website use this strategy:
|
||||
|
||||
- [https://docusaurus.io](https://docusaurus.io)
|
||||
- [https://docusaurus.io/fr](https://docusaurus.io/fr)
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Static hosting providers generally redirect `/unknown/urls` to `/404.html` by convention, always showing an **English 404 page**.
|
||||
|
||||
**Localize your 404 pages** by configuring your host to redirect `/fr/*` to `/fr/404.html`.
|
||||
|
||||
This is not always possible, and depends on your host: GitHub Pages can't do this, [Netlify](https://docs.netlify.com/routing/redirects/redirect-options/#custom-404-page-handling) can.
|
||||
|
||||
:::
|
||||
|
||||
### Multi-domain deployment {#multi-domain-deployment}
|
||||
|
||||
You can also build your site for a single locale:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build -- --locale fr
|
||||
```
|
||||
|
||||
Docusaurus will not add the `/fr/` URL prefix.
|
||||
|
||||
On your [static hosting provider](../deployment.mdx):
|
||||
|
||||
- create one deployment per locale
|
||||
- configure the appropriate build command, using the `--locale` option
|
||||
- configure the (sub)domain of your choice for each deployment
|
||||
|
||||
:::caution
|
||||
|
||||
This strategy is **not possible** with Github Pages, as it is only possible to **have a single deployment**.
|
||||
|
||||
:::
|
||||
|
||||
### Hybrid {#hybrid}
|
||||
|
||||
It is possible to have some locales using sub-paths, and others using subdomains.
|
||||
|
||||
It is also possible to deploy each locale as a separate subdomain, assemble the subdomains in a single unified domain at the CDN level:
|
||||
|
||||
- Deploy your site as `fr.docusaurus.io`
|
||||
- Configure a CDN to serve it from `docusaurus.io/fr`
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
---
|
||||
id: presets
|
||||
title: Presets
|
||||
---
|
||||
|
||||
Presets are collections of plugins and themes.
|
||||
|
||||
## Using presets {#using-presets}
|
||||
|
||||
A preset is usually a npm package, so you install them like other npm packages using npm.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/preset-classic
|
||||
```
|
||||
|
||||
Then, add it in your site's `docusaurus.config.js`'s `presets` option:
|
||||
|
||||
```jsx {3} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: ['@docusaurus/preset-classic'],
|
||||
};
|
||||
```
|
||||
|
||||
To load presets from your local directory, specify how to resolve them:
|
||||
|
||||
```jsx {5} title="docusaurus.config.js"
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [path.resolve(__dirname, '/path/to/docusaurus-local-presets')],
|
||||
};
|
||||
```
|
||||
|
||||
## Presets -> themes and plugins {#presets---themes-and-plugins}
|
||||
|
||||
Presets are a shorthand function to add plugins and themes to your Docusaurus config. For example, you can specify a preset that includes the following themes and plugins,
|
||||
|
||||
```js
|
||||
module.exports = function preset(context, opts = {}) {
|
||||
return {
|
||||
themes: ['@docusaurus/theme-cool', opts.cool],
|
||||
plugins: ['@docusaurus/plugin-blog', opts.blog],
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
then in your Docusaurus config, you may configure the preset instead:
|
||||
|
||||
```jsx {3} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@docusaurus/preset-my-own',
|
||||
{cool: {hello: 'world'}, blog: {path: '/blog'}},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
This is equivalent of doing:
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themes: ['@docusaurus/themes-cool', {hello: 'world'}],
|
||||
plugins: ['@docusaurus/plugin-blog', {path: '/blog'}],
|
||||
};
|
||||
```
|
||||
|
||||
This is especially useful when some plugins and themes are intended to be used together.
|
||||
|
||||
## Official presets {#official-presets}
|
||||
|
||||
### `@docusaurus/preset-classic` {#docusauruspreset-classic}
|
||||
|
||||
The classic preset that is usually shipped by default to new Docusaurus website. It is a set of plugins and themes.
|
||||
|
||||
| Themes | Plugins |
|
||||
| --- | --- |
|
||||
| [`@docusaurus/theme-classic`](./api/themes/theme-configuration.md) | [`@docusaurus/plugin-content-docs`](./api/plugins/plugin-content-docs.md) |
|
||||
| [`@docusaurus/theme-search-algolia`](./api/themes/theme-search-algolia.md) | [`@docusaurus/plugin-content-blog`](./api/plugins/plugin-content-blog.md) |
|
||||
| | [`@docusaurus/plugin-content-pages`](./api/plugins/plugin-content-pages.md) |
|
||||
| | [`@docusaurus/plugin-debug`](./api/plugins/plugin-debug.md) |
|
||||
| | [`@docusaurus/plugin-google-analytics`](./api/plugins/plugin-google-analytics.md) |
|
||||
| | [`@docusaurus/plugin-google-gtag`](./api/plugins/plugin-google-gtag.md) |
|
||||
| | [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) |
|
||||
|
||||
To specify plugin options individually, you can provide the necessary fields to certain plugins, i.e. `customCss` for `@docusaurus/theme-classic`, pass them in the preset field, like this:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// Debug defaults to true in dev, false in prod
|
||||
debug: undefined,
|
||||
// Will be passed to @docusaurus/theme-classic.
|
||||
theme: {
|
||||
customCss: [require.resolve('./src/css/custom.css')],
|
||||
},
|
||||
// Will be passed to @docusaurus/plugin-content-docs (false to disable)
|
||||
docs: {},
|
||||
// Will be passed to @docusaurus/plugin-content-blog (false to disable)
|
||||
blog: {},
|
||||
// Will be passed to @docusaurus/plugin-content-pages (false to disable)
|
||||
pages: {},
|
||||
// Will be passed to @docusaurus/plugin-content-sitemap (false to disable)
|
||||
sitemap: {},
|
||||
// Will be passed to @docusaurus/plugin-google-gtag (only enabled when explicitly specified)
|
||||
gtag: {},
|
||||
// Will be passed to @docusaurus/plugin-google-analytics (only enabled when explicitly specified)
|
||||
googleAnalytics: {},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
In addition to these plugins and themes, `@docusaurus/theme-classic` adds [`remark-admonitions`](https://github.com/elviswolcott/remark-admonitions) as a remark plugin to `@docusaurus/plugin-content-blog` and `@docusaurus/plugin-content-docs`.
|
||||
|
||||
The `admonitions` key will be passed as the [options](https://github.com/elviswolcott/remark-admonitions#options) to `remark-admonitions`. Passing `false` will prevent the plugin from being added to MDX.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// options for remark-admonitions
|
||||
admonitions: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
---
|
||||
id: static-assets
|
||||
title: Static Assets
|
||||
---
|
||||
|
||||
Every website needs assets: images, stylesheets, favicons etc. By default, you are suggested to put these assets in the `static` folder.
|
||||
|
||||
Every file you put into **that directory will be copied** into the root of the generated `build` folder with the directory hierarchy preserved. E.g. if you add a file named `sun.jpg` to the static folder, it will be copied to `build/sun.jpg`.
|
||||
|
||||
This means that:
|
||||
|
||||
- for site `baseUrl: '/'`, the image `/static/img/docusaurus.png` will be served at `/img/docusaurus.png`.
|
||||
- for site `baseUrl: '/subpath/'`, the image `/static/img/docusaurus.png` will be served at `/subpath/img/docusaurus.png`.
|
||||
|
||||
You can customize the static directory sources in `docusaurus.config.js`. For example, we can add `public` as another possible path:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
title: 'My site',
|
||||
staticDirectories: ['public', 'static'],
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Now, all files in `public` as well as `static` will be copied to the build output.
|
||||
|
||||
## Referencing your static asset {#referencing-your-static-asset}
|
||||
|
||||
In JSX, you can reference assets from the `static` folder in your code using absolute paths, but this is not ideal because changing the site `baseUrl` will **break those links**. For the image `<img src="/img/docusaurus.png" />` served at `https://example.com/test`, the browser will try to resolve it from the URL root, i.e. as `https://example.com/img/docusaurus.png`, which will fail because it's actually served at `https://example.com/test/img/docusaurus.png`.
|
||||
|
||||
You can `import` / `require()` the static asset (recommended), or use the `useBaseUrl` utility function: both prepend the `baseUrl` to paths for you.
|
||||
|
||||
:::info
|
||||
|
||||
In Markdown, things are different: you can stick to use absolute paths because Docusaurus actually handles them as `require` calls instead of URLs when parsing the Markdown. See [Markdown static assets](./guides/markdown-features/markdown-features-assets.mdx).
|
||||
|
||||
:::
|
||||
|
||||
### Examples {#examples}
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import DocusaurusImageUrl from '@site/static/img/docusaurus.png';
|
||||
|
||||
<img src={DocusaurusImageUrl} />;
|
||||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
<img src={require('@site/static/img/docusaurus.png').default} />
|
||||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<img src={useBaseUrl('/img/docusaurus.png')} />;
|
||||
```
|
||||
|
||||
You can also import SVG files: they will be transformed into React components.
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import DocusaurusLogoWithKeytar from '@site/static/img/docusaurus_keytar.svg';
|
||||
|
||||
<DocusaurusLogoWithKeytar title="Docusaurus Logo" className="logo" />;
|
||||
```
|
||||
|
||||
### Caveats {#caveats}
|
||||
|
||||
Keep in mind that:
|
||||
|
||||
- By default, none of the files in `static` folder will be post-processed, hashed or minified.
|
||||
- Missing files referenced via hardcoded absolute paths will not be detected at compilation time, and will result in a 404 error.
|
||||
- By default, GitHub Pages runs published files through [Jekyll](https://jekyllrb.com/). Since Jekyll will discard any files that begin with `_`, it is recommended that you disable Jekyll by adding an empty file named `.nojekyll` file to your `static` directory if you are using GitHub pages for hosting.
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
---
|
||||
id: using-plugins
|
||||
title: Plugins
|
||||
---
|
||||
|
||||
Plugins are the building blocks of features in a Docusaurus 2 site. Each plugin handles its own individual feature. Plugins may work and be distributed as part of bundle via [presets](presets.md).
|
||||
|
||||
## Available plugins {#available-plugins}
|
||||
|
||||
We maintain a [list of official plugins](./api/plugins/overview.md), but the community has also created some [unofficial plugins](/community/resources#community-plugins).
|
||||
|
||||
## Installing a plugin {#installing-a-plugin}
|
||||
|
||||
A plugin is usually a npm package, so you install them like other npm packages using npm.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save docusaurus-plugin-name
|
||||
```
|
||||
|
||||
Then you add it in your site's `docusaurus.config.js`'s `plugins` option:
|
||||
|
||||
```jsx {3} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: ['@docusaurus/plugin-content-pages'],
|
||||
};
|
||||
```
|
||||
|
||||
Docusaurus can also load plugins from your local directory, you can do something like the following:
|
||||
|
||||
```jsx {5} title="docusaurus.config.js"
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [path.resolve(__dirname, '/path/to/docusaurus-local-plugin')],
|
||||
};
|
||||
```
|
||||
|
||||
## Configuring plugins {#configuring-plugins}
|
||||
|
||||
For the most basic usage of plugins, you can provide just the plugin name or the absolute path to the plugin.
|
||||
|
||||
However, plugins can have options specified by wrapping the name and an options object in an array inside your config. This style is usually called `Babel Style`.
|
||||
|
||||
```js {4-9} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-xxx',
|
||||
{
|
||||
/* options */
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// Basic usage.
|
||||
'@docusaurus/plugin-google-analytics',
|
||||
|
||||
// With options object (babel style)
|
||||
[
|
||||
'@docusaurus/plugin-sitemap',
|
||||
{
|
||||
changefreq: 'weekly',
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Multi-instance plugins and plugin ids {#multi-instance-plugins-and-plugin-ids}
|
||||
|
||||
All Docusaurus content plugins can support multiple plugin instances.
|
||||
|
||||
The Docs plugin has [additional multi-instance documentation](./guides/docs/docs-multi-instance.mdx)
|
||||
|
||||
It is required to assign a unique id to each plugin instance.
|
||||
|
||||
By default, the plugin id is `default`.
|
||||
|
||||
```js {6,13} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-xxx',
|
||||
{
|
||||
id: 'plugin-xxx-1',
|
||||
// other options
|
||||
},
|
||||
],
|
||||
[
|
||||
'@docusaurus/plugin-xxx',
|
||||
{
|
||||
id: 'plugin-xxx-2',
|
||||
// other options
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
At most one plugin instance can be the "default plugin instance", by omitting the `id` attribute, or using `id: 'default'`.
|
||||
|
||||
:::
|
||||
|
||||
## Plugins design {#plugins-design}
|
||||
|
||||
Docusaurus' implementation of the plugins system provides us with a convenient way to hook into the website's lifecycle to modify what goes on during development/build, which involves (but not limited to) extending the webpack config, modifying the data being loaded and creating new components to be used in a page.
|
||||
|
||||
## Creating plugins {#creating-plugins}
|
||||
|
||||
A plugin is a function that takes two parameters: `context` and `options`. It returns a plugin instance object. You can create plugins as functions or modules. For more information, refer to the [plugin method references section](./api/plugin-methods/README.md).
|
||||
|
||||
### Functional definition {#functional-definition}
|
||||
|
||||
You can use a plugin as a function directly included in the Docusaurus config file:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
// highlight-start
|
||||
function myPlugin(context, options) {
|
||||
// ...
|
||||
return {
|
||||
name: 'my-plugin',
|
||||
async loadContent() {
|
||||
// ...
|
||||
},
|
||||
async contentLoaded({content, actions}) {
|
||||
// ...
|
||||
},
|
||||
/* other lifecycle API */
|
||||
};
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Module definition {#module-definition}
|
||||
|
||||
You can use a plugin as a module path referencing a separate file or NPM package:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
// without options:
|
||||
'./my-plugin',
|
||||
// or with options:
|
||||
['./my-plugin', options],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Then in the folder `my-plugin` you can create an index.js such as this:
|
||||
|
||||
```js title="my-plugin.js"
|
||||
module.exports = function myPlugin(context, options) {
|
||||
// ...
|
||||
return {
|
||||
name: 'my-plugin',
|
||||
async loadContent() {
|
||||
/* ... */
|
||||
},
|
||||
async contentLoaded({content, actions}) {
|
||||
/* ... */
|
||||
},
|
||||
/* other lifecycle API */
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
---
|
||||
id: using-themes
|
||||
title: Themes
|
||||
---
|
||||
|
||||
Like plugins, themes are designed to add functionality to your Docusaurus site. As a good rule of thumb, themes are mostly focused on client-side, where plugins are more focused on server-side functionalities. Themes are also designed to be replace-able with other themes.
|
||||
|
||||
**Themes are for providing UI components to present the content.** Most content plugins need to be paired with a theme in order to be actually useful. The UI is a separate layer from the data schema, which makes swapping designs easy.
|
||||
|
||||
For example, a Docusaurus blog consists of a blog plugin and a blog theme.
|
||||
|
||||
:::note
|
||||
|
||||
This is a contrived example: in practice, `@docusaurus/theme-classic` provides the theme for docs, blog, and layouts.
|
||||
|
||||
:::
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themes: ['theme-blog'],
|
||||
plugins: ['plugin-content-blog'],
|
||||
};
|
||||
```
|
||||
|
||||
And if you want to use Bootstrap styling, you can swap out the theme with `theme-blog-bootstrap` (another fictitious non-existing theme):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themes: ['theme-blog-bootstrap'],
|
||||
plugins: ['plugin-content-blog'],
|
||||
};
|
||||
```
|
||||
|
||||
## Available themes {#available-themes}
|
||||
|
||||
We maintain a [list of official themes](./api/themes/overview.md).
|
||||
|
||||
## Using themes {#using-themes}
|
||||
|
||||
To use themes, specify the themes in your `docusaurus.config.js`. You may use multiple themes:
|
||||
|
||||
```js {3} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themes: ['@docusaurus/theme-classic', '@docusaurus/theme-live-codeblock'],
|
||||
};
|
||||
```
|
||||
|
||||
## Theme components {#theme-components}
|
||||
|
||||
Most of the time, theme is used to provide a set of React components, e.g. `Navbar`, `Layout`, `Footer`.
|
||||
|
||||
Users can use these components in their code by importing them using the `@theme` webpack alias:
|
||||
|
||||
```js
|
||||
import Navbar from '@theme/Navbar';
|
||||
```
|
||||
|
||||
The alias `@theme` can refer to a few directories, in the following priority:
|
||||
|
||||
1. A user's `website/src/theme` directory, which is a special directory that has the higher precedence.
|
||||
2. A Docusaurus theme packages's `theme` directory.
|
||||
3. Fallback components provided by Docusaurus core (usually not needed).
|
||||
|
||||
## Swizzling theme components {#swizzling-theme-components}
|
||||
|
||||
```mdx-code-block
|
||||
import SwizzleWarning from "./_partials/swizzleWarning.mdx"
|
||||
|
||||
<SwizzleWarning/>
|
||||
```
|
||||
|
||||
Docusaurus Themes' components are designed to be replaceable. To make it easier for you, we created a command for you to replace theme components called `swizzle`. Given the following structure:
|
||||
|
||||
```
|
||||
website
|
||||
├── node_modules
|
||||
│ └── docusaurus-theme
|
||||
│ └── theme
|
||||
│ └── Navbar.js
|
||||
└── src
|
||||
└── theme
|
||||
└── Navbar.js
|
||||
```
|
||||
|
||||
`website/src/theme/Navbar.js` takes precedence whenever `@theme/Navbar` is imported. This behavior is called component swizzling. In iOS, method swizzling is the process of changing the implementation of an existing selector (method). In the context of a website, component swizzling means providing an alternative component that takes precedence over the component provided by the theme.
|
||||
|
||||
To swizzle a component for a theme, run the following command in your doc site:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle <theme name> [component name]
|
||||
```
|
||||
|
||||
As an example, to swizzle the `<Footer />` component in `@docusaurus/theme-classic` for your site, run:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic Footer
|
||||
```
|
||||
|
||||
This will copy the current `<Footer />` component used by the theme to a `src/theme/Footer` directory under the root of your site, which is where Docusaurus will look for swizzled components. Docusaurus will then use swizzled component in place of the original one from the theme.
|
||||
|
||||
Although we highly discourage swizzling of all components, if you wish to do that, run:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic
|
||||
```
|
||||
|
||||
**Note**: You need to restart your webpack dev server in order for Docusaurus to know about the new component.
|
||||
|
||||
## Wrapping theme components {#wrapping-theme-components}
|
||||
|
||||
Sometimes, you just want to wrap an existing theme component with additional logic, and it can be a pain to have to maintain an almost duplicate copy of the original theme component.
|
||||
|
||||
In such case, you should swizzle the component you want to wrap, but import the original theme component in your customized version to wrap it.
|
||||
|
||||
### For site owners {#for-site-owners}
|
||||
|
||||
The `@theme-original` alias allows you to import the original theme component.
|
||||
|
||||
Here is an example to display some text just above the footer, with minimal code duplication.
|
||||
|
||||
```js title="src/theme/Footer.js"
|
||||
// Note: importing from "@theme/Footer" would fail due to the file importing itself
|
||||
import OriginalFooter from '@theme-original/Footer';
|
||||
import React from 'react';
|
||||
|
||||
export default function Footer(props) {
|
||||
return (
|
||||
<>
|
||||
<div>Before footer</div>
|
||||
<OriginalFooter {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### For plugin authors {#for-plugin-authors}
|
||||
|
||||
One theme can wrap a component from another theme, by importing the component from the initial theme, using the `@theme-init` import.
|
||||
|
||||
Here's an example of using this feature to enhance the default theme `CodeBlock` component with a `react-live` playground feature.
|
||||
|
||||
```js
|
||||
import InitialCodeBlock from '@theme-init/CodeBlock';
|
||||
import React from 'react';
|
||||
|
||||
export default function CodeBlock(props) {
|
||||
return props.live ? (
|
||||
<ReactLivePlayground {...props} />
|
||||
) : (
|
||||
<InitialCodeBlock {...props} />
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Check the code of `docusaurus-theme-live-codeblock` for details.
|
||||
|
||||
:::caution
|
||||
|
||||
Unless you want publish to npm a "theme enhancer" (like `docusaurus-theme-live-codeblock`), you likely don't need `@theme-init`.
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
|
||||
<summary>How are theme aliases resolved?</summary>
|
||||
|
||||
It can be quite hard to wrap your mind around these aliases. Let's imagine the following case with a super convoluted setup where three themes/plugins and the site itself all try to define the same component. Internally, Docusaurus loads these themes as a "stack".
|
||||
|
||||
```text
|
||||
+-------------------------------------------------+
|
||||
| `website/src/theme/CodeBlock.js` | <-- `@theme/CodeBlock` always points to the top
|
||||
+-------------------------------------------------+
|
||||
| `theme-live-codeblock/theme/CodeBlock/index.js` | <-- `@theme-original/CodeBlock` points to the topmost non-swizzled component
|
||||
+-------------------------------------------------+
|
||||
| `plugin-awesome-codeblock/theme/CodeBlock.js` |
|
||||
+-------------------------------------------------+
|
||||
| `theme-classic/theme/CodeBlock/index.js` | <-- `@theme-init/CodeBlock` always points to the bottom
|
||||
+-------------------------------------------------+
|
||||
```
|
||||
|
||||
The components in this "stack" are pushed in the order of `preset plugins > preset themes > plugins > themes > site`, so the swizzled component in `website/src/theme` always comes out on top because it's loaded last.
|
||||
|
||||
`@theme/*` always points to the topmost component—when code block is swizzled, all other components requesting `@theme/CodeBlock` receive the swizzled version.
|
||||
|
||||
`@theme-original/*` always points to the topmost non-swizzled component. That's why you can import `@theme-original/CodeBlock` in the swizzled component—it points to the next one in the "component stack", a theme-provided one. Plugin authors should not try to use this because your component could be the topmost component and cause a self-import.
|
||||
|
||||
`@theme-init/*` always points to the bottommost component—usually this comes from the theme or plugin that first provides this component. Individual plugins / themes trying to enhance code block can safely use `@theme-init/CodeBlock` to get its basic version. Site creators should generally not use this because you likely want to enhance the _topmost_ instead of the _bottommost_ component. It's also possible that the `@theme-init/CodeBlock` alias does not exist at all—Docusaurus only creates it when it points to a different one from `@theme-original/CodeBlock`, i.e. when it's provided by more than one theme. We don't waste aliases!
|
||||
|
||||
</details>
|
||||
|
||||
## Wrapping your site with `<Root>` {#wrapper-your-site-with-root}
|
||||
|
||||
A `<Root>` theme component is rendered at the very top of your Docusaurus site. It allows you to wrap your site with additional logic, by creating a file at `src/theme/Root.js`:
|
||||
|
||||
```js title="website/src/theme/Root.js"
|
||||
import React from 'react';
|
||||
|
||||
// Default implementation, that you can customize
|
||||
function Root({children}) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export default Root;
|
||||
```
|
||||
|
||||
This component is applied above the router and the theme `<Layout>`, and will **never unmount**.
|
||||
|
||||
:::tip
|
||||
|
||||
Use this component to render React Context providers and global stateful logic.
|
||||
|
||||
:::
|
||||
|
||||
## Themes design {#themes-design}
|
||||
|
||||
While themes share the exact same lifecycle methods with plugins, their implementations can look very different from those of plugins based on themes' designed objectives.
|
||||
|
||||
Themes are designed to complete the build of your Docusaurus site and supply the components used by your site, plugins, and the themes themselves. So a typical theme implementation would look like a `src/index.js` file that hooks it up to the lifecycle methods. Most likely they would not use `loadContent`, which plugins would use. And it is typically accompanied by a `src/theme` directory full of components.
|
||||
|
||||
To summarize:
|
||||
|
||||
- Themes share the same lifecycle methods with Plugins
|
||||
- Themes are run after all existing Plugins
|
||||
- Themes exist to add component aliases by extending the webpack config
|
||||
|
||||
## Writing customized Docusaurus themes {#writing-customized-docusaurus-themes}
|
||||
|
||||
A Docusaurus theme normally includes an `index.js` file where you hook up to the lifecycle methods, alongside with a `theme/` directory of components. A typical Docusaurus `theme` folder looks like this:
|
||||
|
||||
```shell {5-7}
|
||||
website
|
||||
├── package.json
|
||||
└── src
|
||||
├── index.js
|
||||
└── theme
|
||||
├── MyThemeComponent
|
||||
└── AnotherThemeComponent.js
|
||||
```
|
||||
|
||||
There are two lifecycle methods that are essential to theme implementation:
|
||||
|
||||
- [`getThemePath()`](./api/plugin-methods/extend-infrastructure.md#getThemePath)
|
||||
- [`getClientModules()`](./api/plugin-methods/lifecycle-apis.md#getClientModules)
|
||||
|
||||
These lifecycle methods are not essential but recommended:
|
||||
|
||||
- [`validateThemeConfig({themeConfig, validate})`](./api/plugin-methods/static-methods.md#validateThemeConfig)
|
||||
- [`validateOptions({options, validate})`](./api/plugin-methods/static-methods.md#validateOptions)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
description: How Docusaurus works to build your app
|
||||
---
|
||||
|
||||
# Architecture
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Zoom from '@site/src/components/Zoom';
|
||||
```
|
||||
|
||||
<Zoom>
|
||||
|
||||

|
||||
|
||||
</Zoom>
|
||||
|
||||
This diagram shows how Docusaurus works to build your app. Plugins each collect their content and emit JSON data; themes provide layout components which receive the JSON data as route modules. The bundler bundles all the components and emits a server bundle and a client bundle.
|
||||
|
||||
Although you (either plugin authors or site creators) are writing JavaScript all the time, bear in mind that the JS is actually run in different environments:
|
||||
|
||||
- All plugin lifecycle methods are run in Node. Therefore, until we support ES Modules in our codebase, plugin source code must be provided as CommonJS that can be `require`'d.
|
||||
- The theme code is built with Webpack. They can be provided as ESM—following React conventions.
|
||||
|
||||
Plugin code and theme code never directly import each other: they only communicate through protocols (in our case, through JSON temp files and calls to `addRoute`). A useful mental model is to imagine that the plugins are not written in JavaScript, but in another language like Rust. The only way to interact with plugins for the user is through `docusaurus.config.js`, which itself is run in Node (hence you can use `require` and pass callbacks as plugin options).
|
||||
|
||||
During bundling, the config file itself is serialized and bundled, allowing the theme to access config options like `themeConfig` or `baseUrl` through [`useDocusaurusContext()`](../docusaurus-core.md#useDocusaurusContext). However, the `siteConfig` object only contains **serializable values** (values that are preserved after `JSON.stringify()`). Functions, regexes, etc. would be lost on the client side. The `themeConfig` is designed to be entirely serializable.
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# Client architecture
|
||||
|
||||
## Theme aliases {#theme-aliases}
|
||||
|
||||
A theme works by exporting a set of components, e.g. `Navbar`, `Layout`, `Footer`, to render the data passed down from plugins. Docusaurus and users use these components by importing them using the `@theme` webpack alias:
|
||||
|
||||
```js
|
||||
import Navbar from '@theme/Navbar';
|
||||
```
|
||||
|
||||
The alias `@theme` can refer to a few directories, in the following priority:
|
||||
|
||||
1. A user's `website/src/theme` directory, which is a special directory that has the higher precedence.
|
||||
2. A Docusaurus theme package's `theme` directory.
|
||||
3. Fallback components provided by Docusaurus core (usually not needed).
|
||||
|
||||
This is called a _layered architecture_: a higher-priority layer providing the component would shadow a lower-priority layer, making swizzling possible. Given the following structure:
|
||||
|
||||
```
|
||||
website
|
||||
├── node_modules
|
||||
│ └── @docusaurus/theme-classic
|
||||
│ └── theme
|
||||
│ └── Navbar.js
|
||||
└── src
|
||||
└── theme
|
||||
└── Navbar.js
|
||||
```
|
||||
|
||||
`website/src/theme/Navbar.js` takes precedence whenever `@theme/Navbar` is imported. This behavior is called component swizzling. If you are familiar with Objective C where a function's implementation can be swapped during runtime, it's the exact same concept here with changing the target `@theme/Navbar` is pointing to!
|
||||
|
||||
We already talked about how the "userland theme" in `src/theme` can re-use a theme component through the [`@theme-original`](#wrapping) alias. One theme package can also wrap a component from another theme, by importing the component from the initial theme, using the `@theme-init` import.
|
||||
|
||||
Here's an example of using this feature to enhance the default theme `CodeBlock` component with a `react-live` playground feature.
|
||||
|
||||
```js
|
||||
import InitialCodeBlock from '@theme-init/CodeBlock';
|
||||
import React from 'react';
|
||||
|
||||
export default function CodeBlock(props) {
|
||||
return props.live ? (
|
||||
<ReactLivePlayground {...props} />
|
||||
) : (
|
||||
<InitialCodeBlock {...props} />
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Check the code of `@docusaurus/theme-live-codeblock` for details.
|
||||
|
||||
:::caution
|
||||
|
||||
Unless you want to publish a re-usable "theme enhancer" (like `@docusaurus/theme-live-codeblock`), you likely don't need `@theme-init`.
|
||||
|
||||
:::
|
||||
|
||||
It can be quite hard to wrap your mind around these aliases. Let's imagine the following case with a super convoluted setup with three themes/plugins and the site itself all trying to define the same component. Internally, Docusaurus loads these themes as a "stack".
|
||||
|
||||
```text
|
||||
+-------------------------------------------------+
|
||||
| `website/src/theme/CodeBlock.js` | <-- `@theme/CodeBlock` always points to the top
|
||||
+-------------------------------------------------+
|
||||
| `theme-live-codeblock/theme/CodeBlock/index.js` | <-- `@theme-original/CodeBlock` points to the topmost non-swizzled component
|
||||
+-------------------------------------------------+
|
||||
| `plugin-awesome-codeblock/theme/CodeBlock.js` |
|
||||
+-------------------------------------------------+
|
||||
| `theme-classic/theme/CodeBlock/index.js` | <-- `@theme-init/CodeBlock` always points to the bottom
|
||||
+-------------------------------------------------+
|
||||
```
|
||||
|
||||
The components in this "stack" are pushed in the order of `preset plugins > preset themes > plugins > themes > site`, so the swizzled component in `website/src/theme` always comes out on top because it's loaded last.
|
||||
|
||||
`@theme/*` always points to the topmost component—when `CodeBlock` is swizzled, all other components requesting `@theme/CodeBlock` receive the swizzled version.
|
||||
|
||||
`@theme-original/*` always points to the topmost non-swizzled component. That's why you can import `@theme-original/CodeBlock` in the swizzled component—it points to the next one in the "component stack", a theme-provided one. Plugin authors should not try to use this because your component could be the topmost component and cause a self-import.
|
||||
|
||||
`@theme-init/*` always points to the bottommost component—usually, this comes from the theme or plugin that first provides this component. Individual plugins / themes trying to enhance code block can safely use `@theme-init/CodeBlock` to get its basic version. Site creators should generally not use this because you likely want to enhance the _topmost_ instead of the _bottommost_ component. It's also possible that the `@theme-init/CodeBlock` alias does not exist at all—Docusaurus only creates it when it points to a different one from `@theme-original/CodeBlock`, i.e. when it's provided by more than one theme. We don't waste aliases!
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Advanced Tutorials
|
||||
|
||||
This section is not going to be very structured, but we will cover the following topics:
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
|
||||
We will assume that you have finished the guides, and know the basics like how to configure plugins, how to write React components, etc. These sections will have plugin authors and code contributors in mind, so we may occasionally refer to [plugin APIs](../api/plugin-methods/README.md) or other architecture details. Don't panic if you don't understand everything😉
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
# Plugins
|
||||
|
||||
Plugins are the building blocks of features in a Docusaurus 2 site. Each plugin handles its own individual feature. Plugins may work and be distributed as part of a bundle via presets.
|
||||
|
||||
## Creating plugins {#creating-plugins}
|
||||
|
||||
A plugin is a function that takes two parameters: `context` and `options`. It returns a plugin instance object (or a promise). You can create plugins as functions or modules. For more information, refer to the [plugin method references section](./api/plugin-methods/README.md).
|
||||
|
||||
### Function definition {#function-definition}
|
||||
|
||||
You can use a plugin as a function directly included in the Docusaurus config file:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
// highlight-start
|
||||
async function myPlugin(context, options) {
|
||||
// ...
|
||||
return {
|
||||
name: 'my-plugin',
|
||||
async loadContent() {
|
||||
// ...
|
||||
},
|
||||
async contentLoaded({content, actions}) {
|
||||
// ...
|
||||
},
|
||||
/* other lifecycle API */
|
||||
};
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Module definition {#module-definition}
|
||||
|
||||
You can use a plugin as a module path referencing a separate file or NPM package:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
// without options:
|
||||
'./my-plugin',
|
||||
// or with options:
|
||||
['./my-plugin', options],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Then in the folder `my-plugin`, you can create an `index.js` such as this:
|
||||
|
||||
```js title="my-plugin.js"
|
||||
module.exports = async function myPlugin(context, options) {
|
||||
// ...
|
||||
return {
|
||||
name: 'my-plugin',
|
||||
async loadContent() {
|
||||
/* ... */
|
||||
},
|
||||
async contentLoaded({content, actions}) {
|
||||
/* ... */
|
||||
},
|
||||
/* other lifecycle API */
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can view all plugins installed in your site using the [debug plugin's metadata panel](/__docusaurus/debug/metadata).
|
||||
|
||||
Plugins come as several types:
|
||||
|
||||
- `package`: an external package you installed
|
||||
- `project`: a plugin you created in your project, given to Docusaurus as a local file path
|
||||
- `local`: a plugin created using the function definition
|
||||
- `synthetic`: a "fake plugin" Docusaurus created internally, so we take advantage of our modular architecture and don't let the core do much special work. You won't see this in the metadata because it's an implementation detail.
|
||||
|
||||
You can access them on the client side with `useDocusaurusContext().siteMetadata.pluginVersions`.
|
||||
|
||||
## Plugin design {#plugin-design}
|
||||
|
||||
Docusaurus' implementation of the plugins system provides us with a convenient way to hook into the website's lifecycle to modify what goes on during development/build, which involves (but is not limited to) extending the webpack config, modifying the data loaded, and creating new components to be used in a page.
|
||||
|
||||
### Theme design {#theme-design}
|
||||
|
||||
When plugins have loaded their content, the data is made available to the client side through actions like [`createData` + `addRoute`](../api/plugin-methods/lifecycle-apis.md#addRoute) or [`setGlobalData`](../api/plugin-methods/lifecycle-apis.md#setGlobalData). This data has to be _serialized_ to plain strings, because [plugins and themes run in different environments](./architecture.md). Once the data arrives on the client side, the rest becomes familiar to React developers: data is passed along components, components are bundled with Webpack, and rendered to the window through `ReactDOM.render`...
|
||||
|
||||
**Themes provide the set of UI components to render the content.** Most content plugins need to be paired with a theme in order to be actually useful. The UI is a separate layer from the data schema, which makes swapping designs easy.
|
||||
|
||||
For example, a Docusaurus blog may consist of a blog plugin and a blog theme.
|
||||
|
||||
:::note
|
||||
|
||||
This is a contrived example: in practice, `@docusaurus/theme-classic` provides the theme for docs, blog, and layouts.
|
||||
|
||||
:::
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// highlight-next-line
|
||||
themes: ['theme-blog'],
|
||||
plugins: ['plugin-content-blog'],
|
||||
};
|
||||
```
|
||||
|
||||
And if you want to use Bootstrap styling, you can swap out the theme with `theme-blog-bootstrap` (another fictitious non-existing theme):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// highlight-next-line
|
||||
themes: ['theme-blog-bootstrap'],
|
||||
plugins: ['plugin-content-blog'],
|
||||
};
|
||||
```
|
||||
|
||||
Now, although the theme receives the same data from the plugin, how the theme chooses to _render_ the data as UI can be drastically different.
|
||||
|
||||
While themes share the exact same lifecycle methods with plugins, themes' implementations can look very different from those of plugins based on themes' designed objectives.
|
||||
|
||||
Themes are designed to complete the build of your Docusaurus site and supply the components used by your site, plugins, and the themes themselves. A theme still acts like a plugin and exposes some lifecycle methods, but most likely they would not use [`loadContent`](../api/plugin-methods/lifecycle-apis.md#loadContent), since they only receive data from plugins, but don't generate data themselves; themes are typically also accompanied by an `src/theme` directory full of components, which are made known to the core through the [`getThemePath`](../api/plugin-methods/extend-infrastructure.md#getThemePath) lifecycle.
|
||||
|
||||
To summarize:
|
||||
|
||||
- Themes share the same lifecycle methods with Plugins
|
||||
- Themes are run after all existing Plugins
|
||||
- Themes add component aliases by providing `getThemePath`.
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
---
|
||||
description: "Docusaurus' routing system follows single-page application conventions: one route, one component."
|
||||
---
|
||||
|
||||
# Routing
|
||||
|
||||
```mdx-code-block
|
||||
import Link from '@docusaurus/Link';
|
||||
import {useLatestVersion, useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
|
||||
import {useLocation} from '@docusaurus/router';
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
```
|
||||
|
||||
Docusaurus' routing system follows single-page application conventions: one route, one component. In this section, we will begin by talking about routing within the three content plugins (docs, blog, and pages), and then go beyond to talk about the underlying routing system.
|
||||
|
||||
## Routing in content plugins {#routing-in-content-plugins}
|
||||
|
||||
Every content plugin provides a `routeBasePath` option. It defines where the plugins append their routes to. By default, the docs plugin puts its routes under `/docs`; the blog plugin, `/blog`; and the pages plugin, `/`. You can think about the route structure like this:
|
||||
|
||||

|
||||
|
||||
Any route will be matched against this nested route config until a good match is found. For example, when given a route `/docs/configuration`, Docusaurus first enters the `/docs` branch, and then searches among the subroutes created by the docs plugin.
|
||||
|
||||
Changing `routeBasePath` can effectively alter your site's route structure. For example, in [Docs-only mode](../guides/docs/docs-introduction.md#docs-only-mode), we mentioned that configuring `routeBasePath: '/'` for docs means that all routes that the docs plugin create would not have the `/docs` prefix, yet it doesn't prevent you from having more subroutes like `/blog` created by other plugins.
|
||||
|
||||
Next, let's look at how the three plugins structure their own "boxes of subroutes".
|
||||
|
||||
### Pages routing {#pages-routing}
|
||||
|
||||
Pages routing are straightforward: the file paths directly map to URLs, without any other way to customize. See the [pages docs](../guides/creating-pages.md#routing) for more information.
|
||||
|
||||
The component used for Markdown pages is `@theme/MDXPage`. React pages are directly used as the route's component.
|
||||
|
||||
### Blog routing {#blog-routing}
|
||||
|
||||
The blog creates the following routes:
|
||||
|
||||
- **Posts list pages**: `/`, `/page/2`, `/page/3`...
|
||||
- The component is `@theme/BlogListPage`.
|
||||
- **Post pages**: `/2021/11/21/algolia-docsearch-migration`, `/2021/05/12/announcing-docusaurus-two-beta`...
|
||||
- Generated from each Markdown post.
|
||||
- The routes are fully customizable through the `slug` front matter.
|
||||
- The component is `@theme/BlogPostPage`.
|
||||
- **Tags list page**: `/tags`
|
||||
- The route is customizable through the `tagsBasePath` option.
|
||||
- The component is `@theme/BlogTagsListPage`.
|
||||
- **Tag pages**: `/tags/adoption`, `/tags/beta`...
|
||||
- Generated through the tags defined in each post's front matter.
|
||||
- The routes always have base defined in `tagsBasePath`, but the subroutes are customizable through the tag's `permalink` field.
|
||||
- The component is `@theme/BlogTagsPostsPage`.
|
||||
- **Archive page**: `/archive`
|
||||
- The route is customizable through the `archiveBasePath` option.
|
||||
- The component is `@theme/BlogArchivePage`.
|
||||
|
||||
### Docs routing {#docs-routing}
|
||||
|
||||
The docs is the only plugin that creates **nested routes**. At the top, it registers [**version paths**](../guides/docs/versioning.md): `/`, `/next`, `/2.0.0-beta.13`... which provide the version context, including the layout and sidebar. This ensures that when switching between individual docs, the sidebar's state is preserved, and that you can switch between versions through the navbar dropdown while staying on the same doc. The component used is `@theme/DocPage`.
|
||||
|
||||
```mdx-code-block
|
||||
export const URLPath = () => <code>{useLocation().pathname}</code>;
|
||||
|
||||
export const FilePath = () => {
|
||||
const currentVersion = useActiveDocContext('default').activeVersion.name;
|
||||
return <code>{currentVersion === 'current' ? './docs/' : `./versioned_docs/version-${currentVersion}/`}advanced/routing.md</code>;
|
||||
}
|
||||
```
|
||||
|
||||
The individual docs are rendered in the remaining space after the navbar, footer, sidebar, etc. have all been provided by the `DocPage` component. For example, this page, <URLPath />, is generated from the file at <FilePath />. The component used is `@theme/DocItem`.
|
||||
|
||||
The doc's `slug` front matter customizes the last part of the route, but the base route is always defined by the plugin's `routeBasePath` and the version's `path`.
|
||||
|
||||
### File paths and URL paths {#file-paths-and-url-paths}
|
||||
|
||||
Throughout the documentation, we always try to be unambiguous about whether we are talking about file paths or URL paths. Content plugins usually map file paths directly to URL paths, for example, `./docs/advanced/routing.md` will become `/docs/advanced/routing`. However, with `slug`, you can make URLs totally decoupled from the file structure.
|
||||
|
||||
When writing links in Markdown, you could either mean a _file path_, or a _URL path_, which Docusaurus would use several heuristics to determine.
|
||||
|
||||
- If the path has a `@site` prefix, it is _always_ an asset file path.
|
||||
- If the path has an `http(s)://` prefix, it is _always_ a URL path.
|
||||
- If the path doesn't have an extension, it is a URL path. For example, a link `[page](../plugins)` on a page with URL `/docs/advanced/routing` will link to `/docs/plugins`. Docusaurus will only detect broken links when building your site (when it knows the full route structure), but will make no assumptions about the existence of a file. It is exactly equivalent to writing `<a href="../plugins">page</a>` in a JSX file.
|
||||
- If the path has an `.md(x)` extension, Docusaurus would try to resolve that Markdown file to a URL, and replace the file path with a URL path.
|
||||
- If the path has any other extension, Docusaurus would treat it as [an asset](../guides/markdown-features/markdown-features-assets.mdx) and bundle it.
|
||||
|
||||
The following directory structure may help you visualize this file -> URL mapping. Assume that there's no slug customization in any page.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>A sample site structure</summary>
|
||||
|
||||
```bash
|
||||
.
|
||||
├── blog # blog plugin has routeBasePath: '/blog'
|
||||
│ ├── 2019-05-28-first-blog-post.md # -> /blog/2019/05/28/first-blog-post
|
||||
│ ├── 2019-05-29-long-blog-post.md # -> /blog/2019/05/29/long-blog-post
|
||||
│ ├── 2021-08-01-mdx-blog-post.mdx # -> /blog/2021/08/01/mdx-blog-post
|
||||
│ └── 2021-08-26-welcome
|
||||
│ ├── docusaurus-plushie-banner.jpeg
|
||||
│ └── index.md # -> /blog/2021/08/26/welcome
|
||||
├── docs # docs plugin has routeBasePath: '/docs'; current version has base path '/'
|
||||
│ ├── intro.md # -> /docs/intro
|
||||
│ ├── tutorial-basics
|
||||
│ │ ├── _category_.json
|
||||
│ │ ├── congratulations.md # -> /docs/tutorial-basics/congratulations
|
||||
│ │ └── markdown-features.mdx # -> /docs/tutorial-basics/congratulations
|
||||
│ └── tutorial-extras
|
||||
│ ├── _category_.json
|
||||
│ ├── manage-docs-versions.md # -> /docs/tutorial-extras/manage-docs-versions
|
||||
│ └── translate-your-site.md # -> /docs/tutorial-extras/translate-your-site
|
||||
├── src
|
||||
│ └── pages # pages plugin has routeBasePath: '/'
|
||||
│ ├── index.module.css
|
||||
│ ├── index.tsx # -> /
|
||||
│ └── markdown-page.md # -> /markdown-page
|
||||
└── versioned_docs
|
||||
└── version-1.0.0 # version has base path '/1.0.0'
|
||||
├── intro.md # -> /docs/1.0.0/intro
|
||||
├── tutorial-basics
|
||||
│ ├── _category_.json
|
||||
│ ├── congratulations.md # -> /docs/1.0.0/tutorial-basics/congratulations
|
||||
│ └── markdown-features.mdx # -> /docs/1.0.0/tutorial-basics/congratulations
|
||||
└── tutorial-extras
|
||||
├── _category_.json
|
||||
├── manage-docs-versions.md # -> /docs/1.0.0/tutorial-extras/manage-docs-versions
|
||||
└── translate-your-site.md # -> /docs/1.0.0/tutorial-extras/translate-your-site
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
So much about content plugins. Let's take one step back and talk about how routing works in a Docusaurus app in general.
|
||||
|
||||
## Routes become HTML files {#routes-become-html-files}
|
||||
|
||||
Because Docusaurus is a server-side rendering framework, all routes generated will be server-side rendered into static HTML files. If you are familiar with the behavior of HTTP servers like [Apache2](https://httpd.apache.org/docs/trunk/getting-started.html), you will understand how this is done: when the browser sends a request to the route `/docs/advanced/routing`, the server interprets that as request for the HTML file `/docs/advanced/routing/index.html`, and returns that.
|
||||
|
||||
The `/docs/advanced/routing` route can correspond to either `/docs/advanced/routing/index.html` or `/docs/advanced/routing.html`. Some hosting providers differentiate between them using the presence of a trailing slash, and may or may not tolerate the other. Read more in the [trailing slash guide](https://github.com/slorber/trailing-slash-guide).
|
||||
|
||||
For example, the build output of the directory above is (ignoring other assets and JS bundle):
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Output of the above workspace</summary>
|
||||
|
||||
```bash
|
||||
build
|
||||
├── 404.html # /404/
|
||||
├── blog
|
||||
│ ├── archive
|
||||
│ │ └── index.html # /blog/archive/
|
||||
│ ├── first-blog-post
|
||||
│ │ └── index.html # /blog/first-blog-post/
|
||||
│ ├── index.html # /blog/
|
||||
│ ├── long-blog-post
|
||||
│ │ └── index.html # /blog/long-blog-post/
|
||||
│ ├── mdx-blog-post
|
||||
│ │ └── index.html # /blog/mdx-blog-post/
|
||||
│ ├── tags
|
||||
│ │ ├── docusaurus
|
||||
│ │ │ └── index.html # /blog/tags/docusaurus/
|
||||
│ │ ├── hola
|
||||
│ │ │ └── index.html # /blog/tags/hola/
|
||||
│ │ └── index.html # /blog/tags/
|
||||
│ └── welcome
|
||||
│ └── index.html # /blog/welcome/
|
||||
├── docs
|
||||
│ ├── 1.0.0
|
||||
│ │ ├── intro
|
||||
│ │ │ └── index.html # /docs/1.0.0/intro/
|
||||
│ │ ├── tutorial-basics
|
||||
│ │ │ ├── congratulations
|
||||
│ │ │ │ └── index.html # /docs/1.0.0/tutorial-basics/congratulations/
|
||||
│ │ │ └── markdown-features
|
||||
│ │ │ └── index.html # /docs/1.0.0/tutorial-basics/markdown-features/
|
||||
│ │ └── tutorial-extras
|
||||
│ │ ├── manage-docs-versions
|
||||
│ │ │ └── index.html # /docs/1.0.0/tutorial-extras/manage-docs-versions/
|
||||
│ │ └── translate-your-site
|
||||
│ │ └── index.html # /docs/1.0.0/tutorial-extras/translate-your-site/
|
||||
│ ├── intro
|
||||
│ │ └── index.html # /docs/1.0.0/intro/
|
||||
│ ├── tutorial-basics
|
||||
│ │ ├── congratulations
|
||||
│ │ │ └── index.html # /docs/tutorial-basics/congratulations/
|
||||
│ │ └── markdown-features
|
||||
│ │ └── index.html # /docs/tutorial-basics/markdown-features/
|
||||
│ └── tutorial-extras
|
||||
│ ├── manage-docs-versions
|
||||
│ │ └── index.html # /docs/tutorial-extras/manage-docs-versions/
|
||||
│ └── translate-your-site
|
||||
│ └── index.html # /docs/tutorial-extras/translate-your-site/
|
||||
├── index.html # /
|
||||
└── markdown-page
|
||||
└── index.html # /markdown-page/
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
If `trailingSlash` is set to `false`, the build would emit `intro.html` instead of `intro/index.html`.
|
||||
|
||||
All HTML files will reference its JS assets using absolute URLs, so in order for the correct assets to be located, you have to configure the `baseUrl` field. Note that `baseUrl` doesn't affect the emitted bundle's file structure: the base URL is one level above the Docusaurus routing system. You can see the aggregate of `url` and `baseUrl` as the actual location of your Docusaurus site.
|
||||
|
||||
For example, the emitted HTML would contain links like `<link rel="preload" href="/assets/js/runtime~main.7ed5108a.js" as="script">`. Because absolute URLs are resolved from the host, if the bundle placed under the path `https://example.com/base/`, the link will point to `https://example.com/assets/js/runtime~main.7ed5108a.js`, which is, well, non-existent. By specifying `/base/` as base URL, the link will correctly point to `/base/assets/js/runtime~main.7ed5108a.js`.
|
||||
|
||||
Localized sites have the locale as part of the base URL as well. For example, `https://docusaurus.io/zh-CN/docs/advanced/routing/` has base URL `/zh-CN/`.
|
||||
|
||||
## Generating and accessing routes {#generating-and-accessing-routes}
|
||||
|
||||
The `addRoute` lifecycle action is used to generate routes. It registers a piece of route config to the route tree, giving a route, a component, and props that the component needs. The props and the component are both provided as paths for the bundler to `require`, because as explained in the [architecture overview](architecture.md), server and client only communicate through temp files.
|
||||
|
||||
All routes are aggregated in `.docusaurus/routes.js`, which you can view with the debug plugin's [routes panel](/__docusaurus/debug/routes).
|
||||
|
||||
On the client side, we offer `@docusaurus/router` to access the page's route. `@docusaurus/router` is a re-export of the [`react-router-dom`](https://www.npmjs.com/package/react-router-dom/v/5.3.0) package. For example, you can use `useLocation` to get the current page's [location](https://developer.mozilla.org/en-US/docs/Web/API/Location), and `useHistory` to access the [history object](https://developer.mozilla.org/en-US/docs/Web/API/History). (They are not the same as the browser API, although similar in functionality. Refer to the React Router documentation for specific APIs.)
|
||||
|
||||
This API is **SSR safe**, as opposed to the browser-only `window.location`.
|
||||
|
||||
```jsx title="myComponent.js"
|
||||
import React from 'react';
|
||||
import {useLocation} from '@docusaurus/router';
|
||||
|
||||
export function PageRoute() {
|
||||
// React router provides the current component's route, even in SSR
|
||||
const location = useLocation();
|
||||
return (
|
||||
<span>
|
||||
We are currently on <code>{location.pathname}</code>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
export function PageRoute() {
|
||||
const location = useLocation();
|
||||
return (
|
||||
<span>
|
||||
We are currently on <code>{location.pathname}</code>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
<PageRoute />
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Escaping from SPA redirects {#escaping-from-spa-redirects}
|
||||
|
||||
Docusaurus builds a [single-page application](https://developer.mozilla.org/en-US/docs/Glossary/SPA), where route transitions are done through the `history.push()` method of React router. This operation is done on the client side. However, the prerequisite for a route transition to happen this way is that the target URL is known to our router. Otherwise, the router catches this path and displays a 404 page instead.
|
||||
|
||||
If you put some HTML pages under the `static` folder, they will be copied to the build output and therefore become accessible as part of your website, yet it's not part of the Docusaurus route system. We provide a `pathname://` protocol that allows you to redirect to another part of your domain in a non-SPA fashion, as if this route is an external link. Try the following two links:
|
||||
|
||||
```md
|
||||
- [/pure-html](/pure-html)
|
||||
- [pathname:///pure-html](pathname:///pure-html)
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
- <Link data-noBrokenLinkCheck="true" to="/pure-html">/pure-html</Link>
|
||||
- [pathname:///pure-html](pathname:///pure-html)
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::tip
|
||||
|
||||
The first link will trigger a "broken links detected" check during the production build.
|
||||
|
||||
:::
|
||||
|
||||
The `pathname://` protocol is useful for referencing any content in the static folder. For example, Docusaurus would convert [all Markdown static assets to require() calls](../guides/markdown-features/markdown-features-assets.mdx#static-assets). You can use `pathname://` to keep it a regular link instead of being hashed by Webpack.
|
||||
|
||||
```md title="my-doc.md"
|
||||

|
||||
|
||||
[An asset from the static](pathname:///files/asset.pdf)
|
||||
```
|
||||
|
||||
Docusaurus will only strip the `pathname://` prefix without processing the content.
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
---
|
||||
sidebar_label: Static site generation
|
||||
description: Docusaurus statically renders your React code into HTML, allowing faster load speed and better SEO.
|
||||
---
|
||||
|
||||
# Static site generation (SSG)
|
||||
|
||||
In [architecture](architecture.md), we mentioned that the theme is run in Webpack. But beware: that doesn't mean it always has access to browser globals! The theme is built twice:
|
||||
|
||||
- During **server-side rendering**, the theme is compiled in a sandbox called [React DOM Server](https://reactjs.org/docs/react-dom-server.html). You can see this as a "headless browser", where there is no `window` or `document`, only React. SSR produces static HTML pages.
|
||||
- During **client-side rendering**, the theme is compiled with standard React DOM, and has access to browser variables. CSR produces dynamic JavaScript.
|
||||
|
||||
:::info SSR or SSG?
|
||||
|
||||
_Server-side rendering_ and _static site generation_ can be different concepts, but we use them interchangeably.
|
||||
|
||||
:::
|
||||
|
||||
Therefore, while you probably know not to access Node globals like `process` ([or can we?](#node-env)) or the `'fs'` module, you can't freely access browser globals either.
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
export default function WhereAmI() {
|
||||
return <span>{window.location.href}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
This looks like idiomatic React, but if you run `docusaurus build`, you will get an error:
|
||||
|
||||
```
|
||||
ReferenceError: window is not defined
|
||||
```
|
||||
|
||||
This is because during server-side rendering, the Docusaurus app isn't actually run in browser, and it doesn't know what `window` is.
|
||||
|
||||
<details id="node-env">
|
||||
|
||||
<summary>What about <code>process.env.NODE_ENV</code>?</summary>
|
||||
|
||||
One exception to the "no Node globals" rule is `process.env.NODE_ENV`. In fact, you can use it in React, because Webpack injects this variable as a global:
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
export default function expensiveComp() {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return <>This component is not shown in development</>;
|
||||
}
|
||||
const res = someExpensiveOperationThatLastsALongTime();
|
||||
return <>{res}</>;
|
||||
}
|
||||
```
|
||||
|
||||
During Webpack build, the `process.env.NODE_ENV` will be replaced with the value, either `'development'` or `'production'`. You will then get different build results after dead code elimination:
|
||||
|
||||
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Development">
|
||||
|
||||
```diff
|
||||
import React from 'react';
|
||||
|
||||
export default function expensiveComp() {
|
||||
// highlight-next-line
|
||||
if ('development' === 'development') {
|
||||
+ return <>This component is not shown in development</>;
|
||||
}
|
||||
- const res = someExpensiveOperationThatLastsALongTime();
|
||||
- return <>{res}</>;
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Production">
|
||||
|
||||
```diff
|
||||
import React from 'react';
|
||||
|
||||
export default function expensiveComp() {
|
||||
// highlight-next-line
|
||||
- if ('production' === 'development') {
|
||||
- return <>This component is not shown in development</>;
|
||||
- }
|
||||
+ const res = someExpensiveOperationThatLastsALongTime();
|
||||
+ return <>{res}</>;
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</details>
|
||||
|
||||
## Understanding SSR {#understanding-ssr}
|
||||
|
||||
React is not just a dynamic UI runtime—it's also a templating engine. Because Docusaurus sites mostly contain static contents, it should be able to work without any JavaScript (which React runs in), but only plain HTML/CSS. And that's what server-side rendering offers: statically rendering your React code into HTML, without any dynamic content. An HTML file has no concept of client state (it's purely markup), hence it shouldn't rely on browser APIs.
|
||||
|
||||
These HTML files are the first to arrive at the user's browser screen when a URL is visited (see [routing](routing.md)). Afterwards, the browser fetches and runs other JS code to provide the "dynamic" parts of your site—anything implemented with JavaScript. However, before that, the main content of your page is already visible, allowing faster loading.
|
||||
|
||||
In CSR-only apps, all DOM elements are generated on client side with React, and the HTML file only ever contains one root element for React to mount DOM to; in SSR, React is already facing a fully built HTML page, and it only needs to correlate the DOM elements with the virtual DOM in its model. This step is called "hydration". After React has hydrated the static markup, the app starts to work as any normal React app.
|
||||
|
||||
## Escape hatches {#escape-hatches}
|
||||
|
||||
If you want to render any dynamic content on your screen that relies on the browser API to be functional at all, for example:
|
||||
|
||||
- Our [live codeblock](../guides/markdown-features/markdown-features-code-blocks.mdx#interactive-code-editor), which runs in the browser's JS runtime
|
||||
- Our [themed image](../guides/markdown-features/markdown-features-assets.mdx#themed-images) that detects the user's color scheme to display different images
|
||||
- The JSON viewer of our debug panel which uses the `window` global for styling
|
||||
|
||||
You may need to escape from SSR since static HTML can't display anything useful without knowing the client state.
|
||||
|
||||
:::caution
|
||||
|
||||
It is important for the first client-side render to produce the exact same DOM structure as server-side rendering, otherwise, React will correlate virtual DOM with the wrong DOM elements.
|
||||
|
||||
Therefore, the naïve attempt of `if (typeof window !== 'undefined) {/* render something */}` won't work appropriately as a browser vs. server detection, because the first client render would instantly render different markup from the server-generated one.
|
||||
|
||||
You can read more about this pitfall in [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/).
|
||||
|
||||
:::
|
||||
|
||||
We provide several more reliable ways to escape SSR.
|
||||
|
||||
### `<BrowserOnly>` {#browseronly}
|
||||
|
||||
If you need to render some component in browser only (for example, because the component relies on browser specifics to be functional at all), one common approach is to wrap your component with [`<BrowserOnly>`](../docusaurus-core.md#browseronly) to make sure it's invisible during SSR and only rendered in CSR.
|
||||
|
||||
```jsx
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
|
||||
function MyComponent(props) {
|
||||
return (
|
||||
// highlight-start
|
||||
<BrowserOnly fallback={<div>Loading...</div>}>
|
||||
{() => {
|
||||
const LibComponent =
|
||||
require('some-lib-that-accesses-window').LibComponent;
|
||||
return <LibComponent {...props} />;
|
||||
}}
|
||||
</BrowserOnly>
|
||||
// highlight-end
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
It's important to realize that the children of `<BrowserOnly>` is not a JSX element, but a function that _returns_ an element. This is a design decision. Consider this code:
|
||||
|
||||
```jsx
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
|
||||
function MyComponent() {
|
||||
return (
|
||||
<BrowserOnly>
|
||||
{/* highlight-start */}
|
||||
{/* DON'T DO THIS - doesn't actually work */}
|
||||
<span>page url = {window.location.href}</span>
|
||||
{/* highlight-end */}
|
||||
</BrowserOnly>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
While you may expect that `BrowserOnly` hides away the children during server-side rendering, it actually can't. When the React renderer tries to render this JSX tree, it does see the `{window.location.href}` variable as a node of this tree and tries to render it, although it's actually not used! Using a function ensures that we only let the renderer see the browser-only component when it's needed.
|
||||
|
||||
### `useIsBrowser` {#useisbrowser}
|
||||
|
||||
You can also use the `useIsBrowser()` hook to test if the component is currently in a browser environment. It returns `false` in SSR and `true` is CSR, after first client render. Use this hook if you only need to perform certain conditional operations on client-side, but not render an entirely different UI.
|
||||
|
||||
```jsx
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
|
||||
function MyComponent() {
|
||||
const isBrowser = useIsBrowser();
|
||||
const location = isBrowser ? window.location.href : 'fetching location...';
|
||||
return <span>{location}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
### `useEffect` {#useeffect}
|
||||
|
||||
Lastly, you can put your logic in `useEffect()` to delay its execution until after first CSR. This is most appropriate if you are only performing side-effects but don't _get_ data from the client state.
|
||||
|
||||
```jsx
|
||||
function MyComponent() {
|
||||
useEffect(() => {
|
||||
// Only logged in the browser console; nothing is logged during server-side rendering
|
||||
console.log("I'm now in the browser");
|
||||
}, []);
|
||||
return <span>Some content...</span>;
|
||||
}
|
||||
```
|
||||
|
||||
### `ExecutionEnvironment` {#executionenvironment}
|
||||
|
||||
The [`ExecutionEnvironment`](../docusaurus-core.md#executionenvironment) namespace contains several values, and `canUseDOM` is an effective way to detect browser environment.
|
||||
|
||||
Beware that it essentially checked `typeof window !== 'undefined'` under the hood, so you should not use it for rendering-related logic, but only imperative code, like reacting to user input by sending web requests, or dynamically importing libraries, where DOM isn't updated at all.
|
||||
|
||||
```js title="a-client-module.js"
|
||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
document.title = "I'm loaded!";
|
||||
}
|
||||
```
|
||||
|
|
@ -11,6 +11,41 @@ slug: /api/docusaurus-config
|
|||
|
||||
`docusaurus.config.js` contains configurations for your site and is placed in the root directory of your site.
|
||||
|
||||
It usually exports a site configuration object:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// site config...
|
||||
};
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Config files also support config creator functions and async code.</summary>
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = function configCreator() {
|
||||
return {
|
||||
// site config...
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = async function configCreatorAsync() {
|
||||
return {
|
||||
// site config...
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = Promise.resolve({
|
||||
// site config...
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Required fields {#required-fields}
|
||||
|
||||
### `title` {#title}
|
||||
|
|
@ -41,7 +76,7 @@ module.exports = {
|
|||
|
||||
- Type: `string`
|
||||
|
||||
Base URL for your site. This can also be considered the path after the host. For example, `/metro/` is the baseUrl of https://facebook.github.io/metro/. For URLs that have no path, the baseUrl should be set to `/`. This field is related to the [url](#url) field.
|
||||
Base URL for your site. This can also be considered the path after the host. For example, `/metro/` is the base URL of https://facebook.github.io/metro/. For URLs that have no path, the baseUrl should be set to `/`. This field is related to the [url](#url) field.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -55,9 +90,7 @@ module.exports = {
|
|||
|
||||
- Type: `string | undefined`
|
||||
|
||||
Path to your site favicon
|
||||
|
||||
Example, if your favicon is in `static/img/favicon.ico`:
|
||||
Path to your site favicon. For example, if your favicon is in `static/img/favicon.ico`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -77,7 +110,7 @@ Allow to customize the presence/absence of a trailing slash at the end of URLs/l
|
|||
|
||||
:::tip
|
||||
|
||||
Each static hosting provider serve static files differently (this behavior may even change over time).
|
||||
Each static hosting provider serves static files differently (this behavior may even change over time).
|
||||
|
||||
Refer to the [deployment guide](../deployment.mdx) and [slorber/trailing-slash-guide](https://github.com/slorber/trailing-slash-guide) to choose the appropriate setting.
|
||||
|
||||
|
|
@ -100,10 +133,12 @@ module.exports = {
|
|||
en: {
|
||||
label: 'English',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'en-US',
|
||||
},
|
||||
fr: {
|
||||
label: 'Français',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'fr-FR',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -112,6 +147,7 @@ module.exports = {
|
|||
|
||||
- `label`: the label to use for this locale
|
||||
- `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Arabic, Hebrew, etc.)
|
||||
- `htmlLang`: BCP 47 language tag to use in `<html lang="...">` and in `<link ... hreflang="...">`
|
||||
|
||||
### `noIndex` {#noindex}
|
||||
|
||||
|
|
@ -243,6 +279,7 @@ Example:
|
|||
module.exports = {
|
||||
themeConfig: {
|
||||
hideableSidebar: false,
|
||||
autoCollapseSidebarCategories: false,
|
||||
colorMode: {
|
||||
defaultMode: 'light',
|
||||
disableSwitch: false,
|
||||
|
|
@ -306,33 +343,45 @@ module.exports = {
|
|||
|
||||
### `plugins` {#plugins}
|
||||
|
||||
<!-- TODO: configuration for plugins -->
|
||||
- Type: `PluginConfig[]`
|
||||
|
||||
- Type: `any[]`
|
||||
```ts
|
||||
type PluginConfig = string | [string, any] | PluginModule | [PluginModule, any];
|
||||
```
|
||||
|
||||
See [plugin method references](./plugin-methods/README.md) for the shape of a `PluginModule`.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [],
|
||||
plugins: [
|
||||
'docusaurus-plugin-awesome',
|
||||
['docusuarus-plugin-confetti', {fancy: false}],
|
||||
() => ({
|
||||
postBuild() {
|
||||
console.log('Build finished');
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### `themes` {#themes}
|
||||
|
||||
<!-- TODO: configuration for plugins -->
|
||||
|
||||
- Type: `any[]`
|
||||
- Type: `PluginConfig[]`
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themes: [],
|
||||
themes: ['@docusaurus/theme-classic'],
|
||||
};
|
||||
```
|
||||
|
||||
### `presets` {#presets}
|
||||
|
||||
<!-- TODO: configuration for presets -->
|
||||
- Type: `PresetConfig[]`
|
||||
|
||||
- Type: `any[]`
|
||||
```ts
|
||||
type PresetConfig = string | [string, any];
|
||||
```
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -355,7 +404,7 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
Attempting to add unknown field in the config will lead to error in build time:
|
||||
Attempting to add unknown fields in the config will lead to errors during build time:
|
||||
|
||||
```bash
|
||||
Error: The field(s) 'foo', 'bar' are not recognized in docusaurus.config.js
|
||||
|
|
@ -513,7 +562,7 @@ module.exports = {
|
|||
|
||||
:::caution
|
||||
|
||||
This banner need to inline CSS / JS.
|
||||
This banner needs to inline CSS / JS in case all asset loading fails due to wrong base URL.
|
||||
|
||||
If you have a strict [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), you should rather disable it.
|
||||
|
||||
|
|
@ -8,16 +8,16 @@ This section is a work in progress. Anchor links or even URLs are not guaranteed
|
|||
|
||||
Plugin APIs are shared by themes and plugins—themes are loaded just like plugins.
|
||||
|
||||
## Plugin module
|
||||
## Plugin module {#plugin-module}
|
||||
|
||||
Every plugin is imported as a module. The module is expected to have the following members:
|
||||
|
||||
- A **default export**: the constructor function for the plugin.
|
||||
- **Named exports**: the [static methods](./static-methods.md) called before plugins are initialized.
|
||||
|
||||
## Plugin constructor
|
||||
## Plugin constructor {#plugin-constructor}
|
||||
|
||||
The plugin module's default export is a constructor function with the signature `(context: LoadContext, options: PluginOptions) => Plugin`.
|
||||
The plugin module's default export is a constructor function with the signature `(context: LoadContext, options: PluginOptions) => Plugin | Promise<Plugin>`.
|
||||
|
||||
### `context` {#context}
|
||||
|
||||
|
|
@ -37,17 +37,17 @@ interface LoadContext {
|
|||
|
||||
`options` are the [second optional parameter when the plugins are used](../../using-plugins.md#configuring-plugins). `options` are plugin-specific and are specified by users when they use them in `docusaurus.config.js`. If there's a [`validateOptions`](./static-methods.md#validateOptions) function exported, the `options` will be validated and normalized beforehand.
|
||||
|
||||
Alternatively, if preset contains the plugin, the preset will then be in charge of passing the correct options into the plugin. It is up to individual plugin to define what options it takes.
|
||||
Alternatively, if a preset contains the plugin, the preset will then be in charge of passing the correct options into the plugin. It is up to the individual plugin to define what options it takes.
|
||||
|
||||
## Example {#example}
|
||||
|
||||
Here's a mind model for a presumptuous plugin implementation.
|
||||
Here's a mental model for a presumptuous plugin implementation.
|
||||
|
||||
```js
|
||||
// A JavaScript function that returns an object.
|
||||
// `context` is provided by Docusaurus. Example: siteConfig can be accessed from context.
|
||||
// `opts` is the user-defined options.
|
||||
function myPlugin(context, opts) {
|
||||
async function myPlugin(context, opts) {
|
||||
return {
|
||||
// A compulsory field used as the namespace for directories to cache
|
||||
// the intermediate data for each plugin.
|
||||
|
|
@ -8,26 +8,30 @@ Docusaurus has some infrastructure like hot reloading, CLI, and swizzling, that
|
|||
|
||||
## `getPathsToWatch()` {#getPathsToWatch}
|
||||
|
||||
Specifies the paths to watch for plugins and themes. The paths are watched by the dev server so that the plugin lifecycles are reloaded when contents in the watched paths change. Note that the plugins and themes modules are initially called with `context` and `options` from Node, which you may use to find the necessary directory information about the site. Use this for files that are consumed server-side, because theme files are automatically watched by Webpack dev server.
|
||||
Specifies the paths to watch for plugins and themes. The paths are watched by the dev server so that the plugin lifecycles are reloaded when contents in the watched paths change. Note that the plugins and themes modules are initially called with `context` and `options` from Node, which you may use to find the necessary directory information about the site.
|
||||
|
||||
Use this for files that are consumed server-side, because theme files are automatically watched by Webpack dev server.
|
||||
|
||||
Example:
|
||||
|
||||
```js {5-7} title="docusaurus-plugin/src/index.js"
|
||||
```js title="docusaurus-plugin/src/index.js"
|
||||
const path = require('path');
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
// highlight-start
|
||||
getPathsToWatch() {
|
||||
const contentPath = path.resolve(context.siteDir, options.path);
|
||||
return [`${contentPath}/**/*.{ts,tsx}`];
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## `extendCli(cli)` {#extendCli}
|
||||
|
||||
Register an extra command to enhance the CLI of Docusaurus. `cli` is [commander](https://www.npmjs.com/package/commander/v/5.1.0) object.
|
||||
Register an extra command to enhance the CLI of Docusaurus. `cli` is a [commander](https://www.npmjs.com/package/commander/v/5.1.0) object.
|
||||
|
||||
:::caution
|
||||
|
||||
|
|
@ -37,10 +41,11 @@ The commander version matters! We use commander v5, and make sure you are referr
|
|||
|
||||
Example:
|
||||
|
||||
```js {4-11} title="docusaurus-plugin/src/index.js"
|
||||
```js title="docusaurus-plugin/src/index.js"
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
// highlight-start
|
||||
extendCli(cli) {
|
||||
cli
|
||||
.command('roll')
|
||||
|
|
@ -49,32 +54,35 @@ module.exports = function (context, options) {
|
|||
console.log(Math.floor(Math.random() * 1000 + 1));
|
||||
});
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## `getThemePath()` {#getThemePath}
|
||||
|
||||
Returns the path to the directory where the theme components can be found. When your users calls `swizzle`, `getThemePath` is called and its returned path is used to find your theme components.
|
||||
Returns the path to the directory where the theme components can be found. When your users call `swizzle`, `getThemePath` is called and its returned path is used to find your theme components.
|
||||
|
||||
For example, your `getThemePath` can be:
|
||||
|
||||
```js {6-8} title="my-theme/src/index.js"
|
||||
```js title="my-theme/src/index.js"
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'my-theme',
|
||||
// highlight-start
|
||||
getThemePath() {
|
||||
return path.resolve(__dirname, './theme');
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## `getTypeScriptThemePath()` {#getTypeScriptThemePath}
|
||||
|
||||
Similar to `getThemePath()`, it should return the path to the directory where the source code of TypeScript theme components can be found. This path is purely for swizzling TypeScript theme components, and theme components under this path will **not** be resolved by Webpack. Therefore, it is not a replacement of `getThemePath()`. Typically, you can make the path returned by `getTypeScriptThemePath()` be your source directory, and make path returned by `getThemePath()` be the compiled JavaScript output.
|
||||
Similar to `getThemePath()`, it should return the path to the directory where the source code of TypeScript theme components can be found. This path is purely for swizzling TypeScript theme components, and theme components under this path will **not** be resolved by Webpack. Therefore, it is not a replacement for `getThemePath()`. Typically, you can make the path returned by `getTypeScriptThemePath()` be your source directory, and make the path returned by `getThemePath()` be the compiled JavaScript output.
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
@ -86,12 +94,13 @@ You should also format these files with Prettier. Remember—JS files can and wi
|
|||
|
||||
Example:
|
||||
|
||||
```js {6-13} title="my-theme/src/index.js"
|
||||
```js title="my-theme/src/index.js"
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'my-theme',
|
||||
// highlight-start
|
||||
getThemePath() {
|
||||
// Where compiled JavaScript output lives
|
||||
return path.join(__dirname, '../lib/theme');
|
||||
|
|
@ -100,6 +109,7 @@ module.exports = function (context, options) {
|
|||
// Where TypeScript source code lives
|
||||
return path.resolve(__dirname, '../src/theme');
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
@ -108,9 +118,9 @@ module.exports = function (context, options) {
|
|||
|
||||
**This is a static method, not attached to any plugin instance.**
|
||||
|
||||
Returns a list of stable component that are considered as safe for swizzling. These components will be listed in swizzle component without `--danger`. All the components are considers unstable by default. If an empty array is returned, all components are considered unstable. If `undefined` is returned, all component are considered stable.
|
||||
Returns a list of stable components that are considered safe for swizzling. These components will be swizzlable without `--danger`. All components are considered unstable by default. If an empty array is returned, all components are considered unstable. If `undefined` is returned, all components are considered stable.
|
||||
|
||||
```js {0-12} title="my-theme/src/index.js"
|
||||
```js title="my-theme/src/index.js"
|
||||
const swizzleAllowedComponents = [
|
||||
'CodeBlock',
|
||||
'DocSidebar',
|
||||
|
|
@ -103,7 +103,7 @@ module.exports = function (context, options) {
|
|||
|
||||
Themes using the `<Translate>` API can provide default code translation messages.
|
||||
|
||||
It should return messages in `Record<string, string>`, where keys are translation ids and values are messages (without the description) localized using the site current locale.
|
||||
It should return messages in `Record<string, string>`, where keys are translation ids and values are messages (without the description) localized using the site's current locale.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ toc_max_heading_level: 4
|
|||
|
||||
# Lifecycle APIs
|
||||
|
||||
During build, plugins are loaded in parallel to fetch their own contents and render them to routes. Plugins may also configure webpack or post-process the generated files.
|
||||
During the build, plugins are loaded in parallel to fetch their own contents and render them to routes. Plugins may also configure webpack or post-process the generated files.
|
||||
|
||||
## `async loadContent()` {#loadContent}
|
||||
|
||||
|
|
@ -13,13 +13,15 @@ Plugins should use this lifecycle to fetch from data sources (filesystem, remote
|
|||
|
||||
For example, this plugin below return a random integer between 1 to 10 as content.
|
||||
|
||||
```js {5-6} title="docusaurus-plugin/src/index.js"
|
||||
```js title="docusaurus-plugin/src/index.js"
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
// highlight-start
|
||||
async loadContent() {
|
||||
return 1 + Math.floor(Math.random() * 10);
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
@ -63,9 +65,9 @@ type Module =
|
|||
|
||||
#### `createData(name: string, data: any): Promise<string>` {#createData}
|
||||
|
||||
A declarative callback to create static data (generally json or string) which can later be provided to your routes as props. Takes the file name and data to be stored, and returns the actual data file's path.
|
||||
A declarative callback to create static data (generally JSON or string) which can later be provided to your routes as props. Takes the file name and data to be stored, and returns the actual data file's path.
|
||||
|
||||
For example, this plugin below create a `/friends` page which display `Your friends are: Yangshun, Sebastien`:
|
||||
For example, this plugin below creates a `/friends` page which displays `Your friends are: Yangshun, Sebastien`:
|
||||
|
||||
```jsx title="website/src/components/Friends.js"
|
||||
import React from 'react';
|
||||
|
|
@ -75,10 +77,11 @@ export default function FriendsComponent({friends}) {
|
|||
}
|
||||
```
|
||||
|
||||
```js {4-23} title="docusaurus-friends-plugin/src/index.js"
|
||||
```js title="docusaurus-friends-plugin/src/index.js"
|
||||
export default function friendsPlugin(context, options) {
|
||||
return {
|
||||
name: 'docusaurus-friends-plugin',
|
||||
// highlight-start
|
||||
async contentLoaded({content, actions}) {
|
||||
const {createData, addRoute} = actions;
|
||||
// Create friends.json
|
||||
|
|
@ -99,13 +102,14 @@ export default function friendsPlugin(context, options) {
|
|||
exact: true,
|
||||
});
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### `setGlobalData(data: any): void`
|
||||
#### `setGlobalData(data: any): void` {#setGlobalData}
|
||||
|
||||
This function permits to create some global plugin data that can be read from any page, including the pages created by other plugins, and your theme layout.
|
||||
This function permits one to create some global plugin data that can be read from any page, including the pages created by other plugins, and your theme layout.
|
||||
|
||||
This data becomes accessible to your client-side/theme code through the [`useGlobalData`](../../docusaurus-core.md#useGlobalData) and [`usePluginData`](../../docusaurus-core.md#usePluginData) hooks.
|
||||
|
||||
|
|
@ -115,7 +119,7 @@ Global data is... global: its size affects the loading time of all pages of your
|
|||
|
||||
:::
|
||||
|
||||
For example, this plugin below create a `/friends` page which display `Your friends are: Yangshun, Sebastien`:
|
||||
For example, this plugin below creates a `/friends` page which displays `Your friends are: Yangshun, Sebastien`:
|
||||
|
||||
```jsx title="website/src/components/Friends.js"
|
||||
import React from 'react';
|
||||
|
|
@ -127,10 +131,11 @@ export default function FriendsComponent() {
|
|||
}
|
||||
```
|
||||
|
||||
```js {4-14} title="docusaurus-friends-plugin/src/index.js"
|
||||
```js title="docusaurus-friends-plugin/src/index.js"
|
||||
export default function friendsPlugin(context, options) {
|
||||
return {
|
||||
name: 'docusaurus-friends-plugin',
|
||||
// highlight-start
|
||||
async contentLoaded({content, actions}) {
|
||||
const {setGlobalData, addRoute} = actions;
|
||||
// Create friends global data
|
||||
|
|
@ -143,6 +148,7 @@ export default function friendsPlugin(context, options) {
|
|||
exact: true,
|
||||
});
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
@ -174,7 +180,7 @@ The API of `configureWebpack` will be modified in the future to accept an object
|
|||
|
||||
You may use them to return your webpack configures conditionally.
|
||||
|
||||
For example, this plugin below modify the webpack config to transpile `.foo` file.
|
||||
For example, this plugin below modify the webpack config to transpile `.foo` files.
|
||||
|
||||
```js title="docusaurus-plugin/src/index.js"
|
||||
module.exports = function (context, options) {
|
||||
|
|
@ -199,7 +205,7 @@ module.exports = function (context, options) {
|
|||
};
|
||||
```
|
||||
|
||||
### `content` {#content}
|
||||
### `content` {#content-1}
|
||||
|
||||
`configureWebpack` will be called both with the content loaded by the plugin.
|
||||
|
||||
|
|
@ -275,21 +281,24 @@ interface Props {
|
|||
postBodyTags: string;
|
||||
routesPaths: string[];
|
||||
plugins: Plugin<any>[];
|
||||
content: Content;
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js {4-11} title="docusaurus-plugin/src/index.js"
|
||||
```js title="docusaurus-plugin/src/index.js"
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
// highlight-start
|
||||
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
|
||||
// Print out to console all the rendered routes.
|
||||
routesPaths.map((route) => {
|
||||
console.log(route);
|
||||
});
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
@ -300,7 +309,7 @@ Inject head and/or body HTML tags to Docusaurus generated HTML.
|
|||
|
||||
`injectHtmlTags` will be called both with the content loaded by the plugin.
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
function injectHtmlTags(): {
|
||||
headTags?: HtmlTags;
|
||||
preBodyTags?: HtmlTags;
|
||||
|
|
@ -369,20 +378,22 @@ module.exports = function (context, options) {
|
|||
|
||||
## `getClientModules()` {#getClientModules}
|
||||
|
||||
Returns an array of paths to the modules that are to be imported in the client bundle. These modules are imported globally before React even renders the initial UI.
|
||||
Returns an array of paths to the modules that are to be imported into the client bundle. These modules are imported globally before React even renders the initial UI.
|
||||
|
||||
As an example, to make your theme load a `customCss` or `customJs` file path from `options` passed in by the user:
|
||||
|
||||
```js {7-9} title="my-theme/src/index.js"
|
||||
```js title="my-theme/src/index.js"
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function (context, options) {
|
||||
const {customCss, customJs} = options || {};
|
||||
return {
|
||||
name: 'name-of-my-theme',
|
||||
// highlight-start
|
||||
getClientModules() {
|
||||
return [customCss, customJs];
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
@ -8,7 +8,7 @@ Static methods are not part of the plugin instance—they are attached to the co
|
|||
|
||||
## `validateOptions({options, validate})` {#validateOptions}
|
||||
|
||||
Return validated and normalized options for the plugin. This method is called before the plugin is initialized.You must return options since the returned options will be passed to plugin during initialization.
|
||||
Returns validated and normalized options for the plugin. This method is called before the plugin is initialized. You must return the options since they will be passed to the plugin during initialization.
|
||||
|
||||
### `options` {#options}
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ Return validated and normalized options for the plugin. This method is called be
|
|||
|
||||
### `validate` {#validate}
|
||||
|
||||
`validateOptions` is called with `validate` function which takes a **[Joi](https://www.npmjs.com/package/joi)** schema and options as argument, returns validated and normalized options. `validate` will automatically handle error and validation config.
|
||||
`validateOptions` is called with `validate` function which takes a **[Joi](https://www.npmjs.com/package/joi)** schema and options as the arguments, returns validated and normalized options. `validate` will automatically handle error and validation config.
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ To avoid mixing Joi versions, use `const {Joi} = require("@docusaurus/utils-vali
|
|||
|
||||
If you don't use **[Joi](https://www.npmjs.com/package/joi)** for validation you can throw an Error in case of invalid options and return options in case of success.
|
||||
|
||||
```js {8-11} title="my-plugin/src/index.js"
|
||||
```js title="my-plugin/src/index.js"
|
||||
function myPlugin(context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
|
|
@ -36,17 +36,19 @@ function myPlugin(context, options) {
|
|||
};
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
myPlugin.validateOptions = ({options, validate}) => {
|
||||
const validatedOptions = validate(myValidationSchema, options);
|
||||
return validationOptions;
|
||||
};
|
||||
// highlight-end
|
||||
|
||||
module.exports = myPlugin;
|
||||
```
|
||||
|
||||
In TypeScript, you can also choose to export this as a separate named export.
|
||||
|
||||
```ts {8-11} title="my-plugin/src/index.ts"
|
||||
```ts title="my-plugin/src/index.ts"
|
||||
export default function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
|
|
@ -54,10 +56,12 @@ export default function (context, options) {
|
|||
};
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
export function validateOptions({options, validate}) {
|
||||
const validatedOptions = validate(myValidationSchema, options);
|
||||
return validationOptions;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
## `validateThemeConfig({themeConfig, validate})` {#validateThemeConfig}
|
||||
|
|
@ -70,7 +74,7 @@ Return validated and normalized configuration for the theme.
|
|||
|
||||
### `validate` {#validate-1}
|
||||
|
||||
`validateThemeConfig` is called with `validate` function which takes a **[Joi](https://www.npmjs.com/package/joi)** schema and `themeConfig` as argument, returns validated and normalized options. `validate` will automatically handle error and validation config.
|
||||
`validateThemeConfig` is called with `validate` function which takes a **[Joi](https://www.npmjs.com/package/joi)** schema and `themeConfig` as the arguments, returns validated and normalized options. `validate` will automatically handle error and validation config.
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
@ -82,7 +86,7 @@ To avoid mixing Joi versions, use `const {Joi} = require("@docusaurus/utils-vali
|
|||
|
||||
If you don't use **[Joi](https://www.npmjs.com/package/joi)** for validation you can throw an Error in case of invalid options.
|
||||
|
||||
```js {8-11} title="my-theme/src/index.js"
|
||||
```js title="my-theme/src/index.js"
|
||||
function myPlugin(context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
|
|
@ -90,17 +94,19 @@ function myPlugin(context, options) {
|
|||
};
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
myPlugin.validateThemeConfig = ({themeConfig, validate}) => {
|
||||
const validatedThemeConfig = validate(myValidationSchema, options);
|
||||
return validatedThemeConfig;
|
||||
};
|
||||
// highlight-end
|
||||
|
||||
module.exports = validateThemeConfig;
|
||||
```
|
||||
|
||||
In TypeScript, you can also choose to export this as a separate named export.
|
||||
|
||||
```ts {8-11} title="my-theme/src/index.ts"
|
||||
```ts title="my-theme/src/index.ts"
|
||||
export default function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
|
|
@ -108,8 +114,10 @@ export default function (context, options) {
|
|||
};
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
export function validateThemeConfig({themeConfig, validate}) {
|
||||
const validatedThemeConfig = validate(myValidationSchema, options);
|
||||
return validatedThemeConfig;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
sidebar_position: 4
|
||||
id: plugin-client-redirects
|
||||
title: '📦 plugin-client-redirects'
|
||||
slug: '/api/plugins/@docusaurus/plugin-client-redirects'
|
||||
---
|
||||
|
||||
import APITable from '@site/src/components/APITable';
|
||||
|
||||
Docusaurus Plugin to generate **client-side redirects**.
|
||||
|
||||
This plugin will write additional HTML pages to your static site that redirect the user to your existing Docusaurus pages with JavaScript.
|
||||
|
||||
:::caution production only
|
||||
|
||||
This plugin is always inactive in development and **only active in production** because it works on the build output.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
It is better to use server-side redirects whenever possible.
|
||||
|
||||
Before using this plugin, you should look if your hosting provider doesn't offer this feature.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-client-redirects
|
||||
```
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable>
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `fromExtensions` | `string[]` | `[]` | The extensions to be removed from the route after redirecting. |
|
||||
| `toExtensions` | `string[]` | `[]` | The extensions to be appended to the route after redirecting. |
|
||||
| `redirects` | `RedirectRule[]` | `[]` | The list of redirect rules. |
|
||||
| `createRedirects` | `CreateRedirectsFn` | `undefined` | A callback to create a redirect rule. |
|
||||
|
||||
</APITable>
|
||||
|
||||
```ts
|
||||
type RedirectRule = {
|
||||
to: string;
|
||||
from: string | string[];
|
||||
};
|
||||
|
||||
type CreateRedirectsFn = (path: string) => string[] | string | null | undefined;
|
||||
```
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-client-redirects',
|
||||
// highlight-start
|
||||
{
|
||||
fromExtensions: ['html', 'htm'], // /myPage.html -> /myPage
|
||||
toExtensions: ['exe', 'zip'], // /myAsset -> /myAsset.zip (if latter exists)
|
||||
redirects: [
|
||||
// /docs/oldDoc -> /docs/newDoc
|
||||
{
|
||||
to: '/docs/newDoc',
|
||||
from: '/docs/oldDoc',
|
||||
},
|
||||
// Redirect from multiple old paths to the new path
|
||||
{
|
||||
to: '/docs/newDoc2',
|
||||
from: ['/docs/oldDocFrom2019', '/docs/legacyDocFrom2016'],
|
||||
},
|
||||
],
|
||||
createRedirects(existingPath) {
|
||||
if (existingPath.includes('/community')) {
|
||||
// Redirect from /docs/team/X to /community/X and /docs/support/X to /community/X
|
||||
return [
|
||||
existingPath.replace('/community', '/docs/team'),
|
||||
existingPath.replace('/community', '/docs/support'),
|
||||
];
|
||||
}
|
||||
return undefined; // Return a falsy value: no redirect created
|
||||
},
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -9,6 +9,12 @@ import APITable from '@site/src/components/APITable';
|
|||
|
||||
Provides the [Blog](blog.mdx) feature and is the default blog plugin for Docusaurus.
|
||||
|
||||
:::caution some features production only
|
||||
|
||||
The [feed feature](../../blog.mdx#feed) works by extracting the build output, and is **only active in production**.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
|
|
@ -40,7 +46,7 @@ Accepted fields:
|
|||
| `blogSidebarTitle` | `string` | `'Recent posts'` | Title of the blog sidebar. |
|
||||
| `routeBasePath` | `string` | `'blog'` | URL route for the blog section of your site. **DO NOT** include a trailing slash. Use `/` to put the blog at root path. |
|
||||
| `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. |
|
||||
| `archiveBasePath` | `string` | `'/archive'` | URL route for the archive blog section of your site. It is prepended to the `routeBasePath`. **DO NOT** include a trailing slash. |
|
||||
| `archiveBasePath` | <code>string \| null</code> | `'/archive'` | URL route for the archive blog section of your site. It is prepended to the `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. |
|
||||
| `include` | `string[]` | `['**/*.{md,mdx}']` | Matching files will be included and processed. |
|
||||
| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. |
|
||||
| `postsPerPage` | <code>number \| 'ALL'</code> | `10` | Number of posts to show per page in the listing page. Use `'ALL'` to display all posts on one listing page. |
|
||||
|
|
@ -48,6 +54,7 @@ Accepted fields:
|
|||
| `blogPostComponent` | `string` | `'@theme/BlogPostPage'` | Root component of each blog post page. |
|
||||
| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page |
|
||||
| `blogTagsPostsComponent` | `string` | `'@theme/BlogTagsPostsPage'` | Root component of the "posts containing tag" page. |
|
||||
| `blogArchiveComponent` | `string` | `'@theme/BlogArchivePage'` | Root component of the blog archive page. |
|
||||
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
|
||||
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
|
||||
| `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. |
|
||||
|
|
@ -66,7 +73,7 @@ Accepted fields:
|
|||
|
||||
</APITable>
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
type EditUrlFunction = (params: {
|
||||
blogDirPath: string;
|
||||
blogPath: string;
|
||||
|
|
@ -94,27 +101,27 @@ type ReadingTimeFunctionOption = (params: {
|
|||
type FeedType = 'rss' | 'atom' | 'json';
|
||||
```
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration object.
|
||||
|
||||
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
```js config-tabs
|
||||
// Preset Options: blog
|
||||
// Plugin Options: @docusaurus/plugin-content-blog
|
||||
|
||||
const config = {
|
||||
path: 'blog',
|
||||
// Simple use-case: string editUrl
|
||||
// editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/',
|
||||
// Advanced use-case: functional editUrl
|
||||
editUrl: ({locale, blogDirPath, blogPath, permalink}) => {
|
||||
return `https://github.com/facebook/docusaurus/edit/main/website/${blogDirPath}/${blogPath}`;
|
||||
},
|
||||
editUrl: ({locale, blogDirPath, blogPath, permalink}) =>
|
||||
`https://github.com/facebook/docusaurus/edit/main/website/${blogDirPath}/${blogPath}`,
|
||||
editLocalizedFiles: false,
|
||||
blogTitle: 'Blog title',
|
||||
blogDescription: 'Blog',
|
||||
|
|
@ -149,51 +156,9 @@ const config = {
|
|||
};
|
||||
```
|
||||
|
||||
### Preset options {#ex-config-preset}
|
||||
## Markdown front matter {#markdown-front-matter}
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-start
|
||||
blog: {
|
||||
path: 'blog',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin options {#ex-config-plugin}
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-blog',
|
||||
// highlight-start
|
||||
{
|
||||
path: 'blog',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Markdown Frontmatter {#markdown-frontmatter}
|
||||
|
||||
Markdown documents can use the following Markdown FrontMatter metadata fields, enclosed by a line `---` on either side.
|
||||
Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side.
|
||||
|
||||
Accepted fields:
|
||||
|
||||
|
|
@ -201,7 +166,7 @@ Accepted fields:
|
|||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `authors` | `Authors` | `undefined` | List of blog post authors (or unique author). Read the [`authors` guide](../../blog.mdx#blog-post-authors) for more explanations. Prefer `authors` over the `author_*` FrontMatter fields, even for single author blog posts. |
|
||||
| `authors` | `Authors` | `undefined` | List of blog post authors (or unique author). Read the [`authors` guide](../../blog.mdx#blog-post-authors) for more explanations. Prefer `authors` over the `author_*` front matter fields, even for single author blog posts. |
|
||||
| `author` | `string` | `undefined` | ⚠️ Prefer using `authors`. The blog post author's name. |
|
||||
| `author_url` | `string` | `undefined` | ⚠️ Prefer using `authors`. The URL that the author's name will be linked to. This could be a GitHub, Twitter, Facebook profile URL, etc. |
|
||||
| `author_image_url` | `string` | `undefined` | ⚠️ Prefer using `authors`. The URL to the author's thumbnail image. |
|
||||
|
|
@ -220,7 +185,7 @@ Accepted fields:
|
|||
|
||||
</APITable>
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
type Tag = string | {label: string; permalink: string};
|
||||
|
||||
// An author key references an author from the global plugin authors.yml file
|
||||
|
|
@ -234,13 +199,13 @@ type Author = {
|
|||
image_url?: string;
|
||||
};
|
||||
|
||||
// The FrontMatter authors field allows various possible shapes
|
||||
// The front matter authors field allows various possible shapes
|
||||
type Authors = AuthorKey | Author | (AuthorKey | Author)[];
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
title: Welcome Docusaurus v2
|
||||
authors:
|
||||
|
|
@ -255,6 +220,7 @@ description: This is my first post on Docusaurus 2.
|
|||
image: https://i.imgur.com/mErPwqL.png
|
||||
hide_table_of_contents: false
|
||||
---
|
||||
|
||||
A Markdown blog post
|
||||
```
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ npm install --save @docusaurus/plugin-content-docs
|
|||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the [preset options](#ex-config-preset).
|
||||
You can configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -32,6 +32,7 @@ Accepted fields:
|
|||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `path` | `string` | `'docs'` | Path to data on filesystem relative to site dir. |
|
||||
| `breadcrumbs` | `boolean` | `true` | To enable or disable the breadcrumbs on docs pages. |
|
||||
| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. |
|
||||
| `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. |
|
||||
| `editCurrentVersion` | `boolean` | `false` | The edit URL will always target the current version doc instead of older versions. Ignored when `editUrl` is a function. |
|
||||
|
|
@ -55,15 +56,15 @@ Accepted fields:
|
|||
| `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. |
|
||||
| `showLastUpdateAuthor` | `boolean` | `false` | Whether to display the author who last updated the doc. |
|
||||
| `showLastUpdateTime` | `boolean` | `false` | Whether to display the last date the doc was updated. |
|
||||
| `disableVersioning` | `boolean` | `false` | Explicitly disable the versioning feature even with versions. This will only include the "current" version (the `/docs` directory). |
|
||||
| `includeCurrentVersion` | `boolean` | `true` | Include the "current" version of your docs (the `/docs` directory). <br /> Tip: turn it off if the current version is a work-in-progress, not ready to be published. |
|
||||
| `lastVersion` | `string` | `current` (alias for the first version to appear in `versions.json` and at the "root" (docs have `path=/docs/myDoc`)) | Set the version navigated to in priority on versioned sites and the one displayed by default in docs navbar items. <br /> Note: the path and label of the last version are configurable. <br /> Tip: `lastVersion: 'current'` makes sense in many cases. |
|
||||
| `disableVersioning` | `boolean` | `false` | Explicitly disable versioning even with versions. This will make the site only include the current version. |
|
||||
| `includeCurrentVersion` | `boolean` | `true` | Include the current version of your docs. |
|
||||
| `lastVersion` | `string` | First version in `versions.json` | Set the version navigated to in priority and displayed by default for docs navbar items. |
|
||||
| `onlyIncludeVersions` | `string[]` | All versions available | Only include a subset of all available versions. |
|
||||
| `versions` | `Versions` | `{}` | Independent customization of each version's properties. |
|
||||
| `onlyIncludeVersions` | `string[]` | All versions available | Only include a subset of all available versions. <br /> Tip: limit to 2 or 3 versions to improve startup and build time in dev and deploy previews. |
|
||||
|
||||
</APITable>
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
type EditUrlFunction = (params: {
|
||||
version: string;
|
||||
versionDocsDirPath: string;
|
||||
|
|
@ -77,6 +78,12 @@ type PrefixParser = (filename: string) => {
|
|||
numberPrefix?: number;
|
||||
};
|
||||
|
||||
type CategoryIndexMatcher = (doc: {
|
||||
fileName: string;
|
||||
directories: string[];
|
||||
extension: string;
|
||||
}) => boolean;
|
||||
|
||||
type SidebarGenerator = (generatorArgs: {
|
||||
item: {type: 'autogenerated'; dirName: string}; // the sidebar item with type "autogenerated"
|
||||
version: {contentPath: string; versionName: string}; // the current version
|
||||
|
|
@ -88,6 +95,8 @@ type SidebarGenerator = (generatorArgs: {
|
|||
sidebarPosition?: number | undefined;
|
||||
}>; // all the docs of that version (unfiltered)
|
||||
numberPrefixParser: PrefixParser; // numberPrefixParser configured for this plugin
|
||||
categoriesMetadata: Record<string, CategoryMetadata>; // key is the path relative to the doc directory, value is the category metadata file's content
|
||||
isCategoryIndex: CategoryIndexMatcher; // the default category index matcher, that you can override
|
||||
defaultSidebarItemsGenerator: SidebarGenerator; // useful to re-use/enhance default sidebar generation logic from Docusaurus
|
||||
}) => Promise<SidebarItem[]>;
|
||||
|
||||
|
|
@ -103,21 +112,23 @@ type Versions = Record<
|
|||
>;
|
||||
```
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration object.
|
||||
|
||||
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
```js config-tabs
|
||||
// Preset Options: docs
|
||||
// Plugin Options: @docusaurus/plugin-content-docs
|
||||
|
||||
const config = {
|
||||
path: 'docs',
|
||||
breadcrumbs: true,
|
||||
// Simple use-case: string editUrl
|
||||
// editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/',
|
||||
// Advanced use-case: functional editUrl
|
||||
|
|
@ -134,12 +145,13 @@ const config = {
|
|||
'**/__tests__/**',
|
||||
],
|
||||
sidebarPath: 'sidebars.js',
|
||||
sidebarItemsGenerator: async function ({
|
||||
async sidebarItemsGenerator({
|
||||
defaultSidebarItemsGenerator,
|
||||
numberPrefixParser,
|
||||
item,
|
||||
version,
|
||||
docs,
|
||||
isCategoryIndex,
|
||||
}) {
|
||||
// Use the provided data to generate a custom sidebar slice
|
||||
return [
|
||||
|
|
@ -154,7 +166,7 @@ const config = {
|
|||
},
|
||||
];
|
||||
},
|
||||
numberPrefixParser: function (filename) {
|
||||
numberPrefixParser(filename) {
|
||||
// Implement your own logic to extract a potential number prefix
|
||||
const numberPrefix = findNumberPrefix(filename);
|
||||
// Prefix found: return it with the cleaned filename
|
||||
|
|
@ -194,51 +206,9 @@ const config = {
|
|||
};
|
||||
```
|
||||
|
||||
### Preset options {#ex-config-preset}
|
||||
## Markdown front matter {#markdown-front-matter}
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-start
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin options {#ex-config-plugin}
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
// highlight-start
|
||||
{
|
||||
path: 'docs',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Markdown Frontmatter {#markdown-frontmatter}
|
||||
|
||||
Markdown documents can use the following Markdown FrontMatter metadata fields, enclosed by a line `---` on either side.
|
||||
Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side.
|
||||
|
||||
Accepted fields:
|
||||
|
||||
|
|
@ -252,7 +222,7 @@ Accepted fields:
|
|||
| `sidebar_label` | `string` | `title` | The text shown in the document sidebar for this document. |
|
||||
| `sidebar_position` | `number` | Default ordering | Controls the position of a doc inside the generated sidebar slice when using `autogenerated` sidebar items. See also [Autogenerated sidebar metadata](/docs/sidebar#autogenerated-sidebar-metadata). |
|
||||
| `sidebar_class_name` | `string` | `undefined` | Gives the corresponding sidebar label a special class name when using autogenerated sidebars. |
|
||||
| `hide_title` | `boolean` | `false` | Whether to hide the title at the top of the doc. It only hides a title declared through the frontmatter, and have no effect on a Markdown title at the top of your document. |
|
||||
| `hide_title` | `boolean` | `false` | Whether to hide the title at the top of the doc. It only hides a title declared through the front matter, and have no effect on a Markdown title at the top of your document. |
|
||||
| `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. |
|
||||
| `toc_min_heading_level` | `number` | `2` | The minimum heading level shown in the table of contents. Must be between 2 and 6 and lower or equal to the max value. |
|
||||
| `toc_max_heading_level` | `number` | `3` | The max heading level shown in the table of contents. Must be between 2 and 6. |
|
||||
|
|
@ -268,13 +238,13 @@ Accepted fields:
|
|||
|
||||
</APITable>
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
type Tag = string | {label: string; permalink: string};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
id: doc-markdown
|
||||
title: Docs Markdown Features
|
||||
|
|
@ -291,6 +261,7 @@ keywords:
|
|||
image: https://i.imgur.com/mErPwqL.png
|
||||
slug: /myDoc
|
||||
---
|
||||
|
||||
# Markdown Features
|
||||
|
||||
My Document Markdown content
|
||||
|
|
@ -314,15 +285,15 @@ website/i18n/[locale]/docusaurus-plugin-content-docs
|
|||
│
|
||||
│ # translations for website/docs
|
||||
├── current
|
||||
│ ├── api
|
||||
│ │ └── config.md
|
||||
│ └── getting-started.md
|
||||
│ ├── api
|
||||
│ │ └── config.md
|
||||
│ └── getting-started.md
|
||||
├── current.json
|
||||
│
|
||||
│ # translations for website/versioned_docs/version-1.0.0
|
||||
├── version-1.0.0
|
||||
│ ├── api
|
||||
│ │ └── config.md
|
||||
│ └── getting-started.md
|
||||
│ ├── api
|
||||
│ │ └── config.md
|
||||
│ └── getting-started.md
|
||||
└── version-1.0.0.json
|
||||
```
|
||||
|
|
@ -19,7 +19,7 @@ npm install --save @docusaurus/plugin-content-pages
|
|||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the [preset options](#ex-config-preset).
|
||||
You can configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -43,19 +43,20 @@ Accepted fields:
|
|||
|
||||
</APITable>
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration object.
|
||||
|
||||
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js
|
||||
```js config-tabs
|
||||
// Preset Options: pages
|
||||
// Plugin Options: @docusaurus/plugin-content-pages
|
||||
|
||||
const config = {
|
||||
path: 'src/pages',
|
||||
routeBasePath: '',
|
||||
|
|
@ -74,48 +75,6 @@ const config = {
|
|||
};
|
||||
```
|
||||
|
||||
### Preset options {#ex-config-preset}
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-start
|
||||
pages: {
|
||||
path: 'src/pages',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin options {#ex-config-plugin}
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-pages',
|
||||
// highlight-start
|
||||
{
|
||||
path: 'src/pages',
|
||||
// ... configuration object here
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## i18n {#i18n}
|
||||
|
||||
Read the [i18n introduction](../../i18n/i18n-introduction.md) first.
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
sidebar_position: 5
|
||||
id: plugin-debug
|
||||
title: '📦 plugin-debug'
|
||||
slug: '/api/plugins/@docusaurus/plugin-debug'
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
The debug plugin will display useful debug information at [http://localhost:3000/\_\_docusaurus/debug](http://localhost:3000/__docusaurus/debug).
|
||||
|
||||
It is mostly useful for plugin authors, that will be able to inspect more easily the content of the `.docusaurus` folder (like the creates routes), but also be able to inspect data structures that are never written to disk, like the plugin data loaded through the `contentLoaded` lifecycle.
|
||||
|
||||
:::info
|
||||
|
||||
If you use the plugin via the classic preset, the preset will **enable the plugin in development and disable it in production** by default (`debug: undefined`) to avoid exposing potentially sensitive information. You can use `debug: true` to always enable it or `debug: false` to always disable it.
|
||||
|
||||
If you use a standalone plugin, you may need to achieve the same effect by checking the environment:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// highlight-next-line
|
||||
process.env.NODE_ENV === 'production' && '@docusaurus/plugin-debug',
|
||||
].filter(Boolean),
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
If you report a bug, we will probably ask you to have this plugin turned on in the production, so that we can inspect your deployment config more easily.
|
||||
|
||||
If you don't have any sensitive information, you can keep it on in production [like we do](/__docusaurus/debug).
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-debug
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
This plugin currently has no options.
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Preset Options">
|
||||
|
||||
If you use a preset, configure this plugin through the [preset options](../../using-plugins.md#docusauruspreset-classic):
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
// highlight-next-line
|
||||
debug: true, // This will enable the plugin in production
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Plugin Options">
|
||||
|
||||
If you are using a standalone plugin, provide options directly to the plugin:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// highlight-next-line
|
||||
plugins: ['@docusaurus/plugin-debug'],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
sidebar_position: 6
|
||||
id: plugin-google-analytics
|
||||
title: '📦 plugin-google-analytics'
|
||||
slug: '/api/plugins/@docusaurus/plugin-google-analytics'
|
||||
---
|
||||
|
||||
import APITable from '@site/src/components/APITable';
|
||||
|
||||
The default [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/) plugin. It is a JavaScript library for measuring how users interact with your website **in the production build**. If you are using Google Analytics 4 you might need to consider using [plugin-google-gtag](./plugin-google-gtag.md) instead.
|
||||
|
||||
:::caution production only
|
||||
|
||||
This plugin is always inactive in development and **only active in production** to avoid polluting the analytics statistics.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-google-analytics
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable>
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `trackingID` | `string` | **Required** | The tracking ID of your analytics service. |
|
||||
| `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
|
||||
|
||||
</APITable>
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js config-tabs
|
||||
// Preset Options: googleAnalytics
|
||||
// Plugin Options: @docusaurus/plugin-google-analytics
|
||||
|
||||
const config = {
|
||||
trackingID: 'UA-141789564-1',
|
||||
anonymizeIP: true,
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
sidebar_position: 7
|
||||
id: plugin-google-gtag
|
||||
title: '📦 plugin-google-gtag'
|
||||
slug: '/api/plugins/@docusaurus/plugin-google-gtag'
|
||||
---
|
||||
|
||||
import APITable from '@site/src/components/APITable';
|
||||
|
||||
The default [Global Site Tag (gtag.js)](https://developers.google.com/analytics/devguides/collection/gtagjs/) plugin. It is a JavaScript tagging framework and API that allows you to send event data to Google Analytics, Google Ads, and Google Marketing Platform. This section describes how to configure a Docusaurus site to enable global site tag for Google Analytics.
|
||||
|
||||
:::tip
|
||||
|
||||
You can use [Google's Tag Assistant](https://tagassistant.google.com/) tool to check if your gtag is set up correctly!
|
||||
|
||||
:::
|
||||
|
||||
:::caution production only
|
||||
|
||||
This plugin is always inactive in development and **only active in production** to avoid polluting the analytics statistics.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-google-gtag
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable>
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `trackingID` | `string` | **Required** | The tracking ID of your gtag service. |
|
||||
| `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
|
||||
|
||||
</APITable>
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js config-tabs
|
||||
// Preset Options: gtag
|
||||
// Plugin Options: @docusaurus/plugin-google-gtag
|
||||
|
||||
const config = {
|
||||
trackingID: '141789564',
|
||||
anonymizeIP: true,
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
sidebar_position: 8
|
||||
id: plugin-ideal-image
|
||||
title: '📦 plugin-ideal-image'
|
||||
slug: '/api/plugins/@docusaurus/plugin-ideal-image'
|
||||
---
|
||||
|
||||
import APITable from '@site/src/components/APITable';
|
||||
|
||||
Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).
|
||||
|
||||
:::info
|
||||
|
||||
By default, the plugin is **inactive in development** so you could always view full-scale images. If you want to debug the ideal image behavior, you could set the [`disableInDev`](#disableInDev) option to `false`.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-ideal-image
|
||||
```
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
This plugin supports the PNG and JPG formats only.
|
||||
|
||||
```jsx
|
||||
import Image from '@theme/IdealImage';
|
||||
import thumbnail from './path/to/img.png';
|
||||
|
||||
// your React code
|
||||
<Image img={thumbnail} />
|
||||
|
||||
// or
|
||||
<Image img={require('./path/to/img.png')} />
|
||||
```
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable>
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | `string` | `ideal-img/[name].[hash:hex:7].[width].[ext]` | Filename template for output files. |
|
||||
| `sizes` | `number[]` | _original size_ | Specify all widths you want to use. If a specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up). |
|
||||
| `size` | `number` | _original size_ | Specify one width you want to use; if the specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up) |
|
||||
| `min` | `number` | | As an alternative to manually specifying `sizes`, you can specify `min`, `max` and `steps`, and the sizes will be generated for you. |
|
||||
| `max` | `number` | | See `min` above |
|
||||
| `steps` | `number` | `4` | Configure the number of images generated between `min` and `max` (inclusive) |
|
||||
| `quality` | `number` | `85` | JPEG compression quality |
|
||||
| `disableInDev` | `boolean` | `true` | You can test ideal image behavior in dev mode by setting this to `false`. **Tip**: use [network throttling](https://www.browserstack.com/guide/how-to-perform-network-throttling-in-chrome) in your browser to simulate slow networks. |
|
||||
|
||||
</APITable>
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
Here's an example configuration:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-ideal-image',
|
||||
// highlight-start
|
||||
{
|
||||
quality: 70,
|
||||
max: 1030, // max resized image's size.
|
||||
min: 640, // min resized image's size. if original is lower, use that size.
|
||||
steps: 2, // the max number of images generated between min and max (inclusive)
|
||||
disableInDev: false,
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
sidebar_position: 10
|
||||
id: plugin-sitemap
|
||||
title: '📦 plugin-sitemap'
|
||||
slug: '/api/plugins/@docusaurus/plugin-sitemap'
|
||||
---
|
||||
|
||||
import APITable from '@site/src/components/APITable';
|
||||
|
||||
This plugin creates sitemaps for your site so that search engine crawlers can crawl your site more accurately.
|
||||
|
||||
:::caution production only
|
||||
|
||||
This plugin is always inactive in development and **only active in production** because it works on the build output.
|
||||
|
||||
:::
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/plugin-sitemap
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you use the preset `@docusaurus/preset-classic`, you don't need to install this plugin as a dependency.
|
||||
|
||||
You can configure this plugin through the [preset options](#ex-config-preset).
|
||||
|
||||
:::
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable>
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `changefreq` | `string` | `'weekly'` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) |
|
||||
| `priority` | `number` | `0.5` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) |
|
||||
|
||||
</APITable>
|
||||
|
||||
:::info
|
||||
|
||||
This plugin also respects some site config:
|
||||
|
||||
- [`noIndex`](../docusaurus.config.js.md#noindex): results in no sitemap generated
|
||||
- [`trailingSlash`](../docusaurus.config.js.md#trailing-slash): determines if the URLs in the sitemap have trailing slashes
|
||||
|
||||
:::
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
||||
You can configure this plugin through preset options or plugin options.
|
||||
|
||||
:::tip
|
||||
|
||||
Most Docusaurus users configure this plugin through the preset options.
|
||||
|
||||
:::
|
||||
|
||||
```js config-tabs
|
||||
// Preset Options: sitemap
|
||||
// Plugin Options: @docusaurus/plugin-sitemap
|
||||
|
||||
const config = {
|
||||
changefreq: 'weekly',
|
||||
priority: 0.5,
|
||||
};
|
||||
```
|
||||
|
||||
You can find your sitemap at `/sitemap.xml`.
|
||||
|
|
@ -124,7 +124,7 @@ module.exports = {
|
|||
|
||||
### Announcement bar {#announcement-bar}
|
||||
|
||||
Sometimes you want to announce something in your website. Just for such a case, you can add an announcement bar. This is a non-fixed and optionally dismissable panel above the navbar. All configuration are in the `announcementBar` object.
|
||||
Sometimes you want to announce something in your website. Just for such a case, you can add an announcement bar. This is a non-fixed and optionally dismissible panel above the navbar. All configuration are in the `announcementBar` object.
|
||||
|
||||
Accepted fields:
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ module.exports = {
|
|||
|
||||
Accepted fields:
|
||||
|
||||
<APITable name="navbar">
|
||||
<APITable name="navbar-overview">
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
|
|
@ -325,6 +325,7 @@ Navbar dropdown items only accept the following **"link-like" item types**:
|
|||
- [Navbar link](#navbar-link)
|
||||
- [Navbar doc link](#navbar-doc-link)
|
||||
- [Navbar docs version](#navbar-docs-version)
|
||||
- [Navbar doc sidebar](#navbar-doc-sidebar)
|
||||
|
||||
Note that the dropdown base item is a clickable link as well, so this item can receive any of the props of a [plain navbar link](#navbar-link).
|
||||
|
||||
|
|
@ -412,6 +413,71 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
#### Navbar linked to a sidebar {#navbar-doc-sidebar}
|
||||
|
||||
You can link a navbar item to the first document link (which can be a doc link or a generated category index) of a given sidebar without having to hardcode a doc ID.
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable name="navbar-doc-sidebar">
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `type` | `'docSidebar'` | **Required** | Sets the type of this navbar item to a sidebar's first document. |
|
||||
| `sidebarId` | `string` | **Required** | The ID of the sidebar that this item is linked to. |
|
||||
| `label` | `string` | First document link's sidebar label | The name to be shown for this item. |
|
||||
| `position` | <code>'left' \| 'right'</code> | `'left'` | The side of the navbar this item should appear on. |
|
||||
| `docsPluginId` | `string` | `'default'` | The ID of the docs plugin that the sidebar belongs to. |
|
||||
|
||||
</APITable>
|
||||
|
||||
:::tip
|
||||
|
||||
Use this navbar item type if your sidebar is updated often and the order is not stable.
|
||||
|
||||
:::
|
||||
|
||||
Example configuration:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'docSidebar',
|
||||
position: 'left',
|
||||
sidebarId: 'api',
|
||||
label: 'API',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorial: [
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'guides',
|
||||
},
|
||||
],
|
||||
api: [
|
||||
// highlight-next-line
|
||||
'cli', // The navbar item will be linking to this doc
|
||||
'docusaurus-core',
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'api',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Navbar docs version dropdown {#navbar-docs-version-dropdown}
|
||||
|
||||
If you use docs with versioning, this special navbar item type that will render a dropdown with all your site's available versions.
|
||||
|
|
@ -839,20 +905,20 @@ module.exports = {
|
|||
|
||||
## Hooks {#hooks}
|
||||
|
||||
### `useThemeContext` {#usethemecontext}
|
||||
### `useColorMode` {#use-color-mode}
|
||||
|
||||
React hook to access theme context. This context contains functions for setting light and dark mode and exposes boolean variable, indicating which mode is currently in use.
|
||||
A React hook to access the color context. This context contains functions for setting light and dark mode and exposes boolean variable, indicating which mode is currently in use.
|
||||
|
||||
Usage example:
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
import {useColorMode} from '@docusaurus/theme-common';
|
||||
|
||||
const Example = () => {
|
||||
// highlight-next-line
|
||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
|
||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
|
||||
|
||||
return <h1>Dark mode is now {isDarkTheme ? 'on' : 'off'}</h1>;
|
||||
};
|
||||
|
|
@ -860,7 +926,7 @@ const Example = () => {
|
|||
|
||||
:::note
|
||||
|
||||
The component calling `useThemeContext` must be a child of the `Layout` component.
|
||||
The component calling `useColorMode` must be a child of the `Layout` component.
|
||||
|
||||
```jsx
|
||||
function ExamplePage() {
|
||||
|
|
@ -13,7 +13,7 @@ npm install --save @docusaurus/theme-live-codeblock
|
|||
|
||||
### Configuration {#configuration}
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: ['@docusaurus/theme-live-codeblock'],
|
||||
themeConfig: {
|
||||
|
|
@ -11,7 +11,7 @@ This theme provides a `@theme/SearchBar` component that integrates with Algolia
|
|||
npm install --save @docusaurus/theme-search-algolia
|
||||
```
|
||||
|
||||
This theme also adds search page available at `/search` (as swizzleable `SearchPage` component) path with OpenSearch support.
|
||||
This theme also adds search page available at `/search` (as swizzlable `SearchPage` component) path with OpenSearch support. You can this default path via `themeConfig.algolia.searchPagePath`. Use `false` to disable search page.
|
||||
|
||||
:::tip
|
||||
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
|
@ -16,7 +16,7 @@ Check the [Blog Plugin API Reference documentation](./api/plugins/plugin-content
|
|||
|
||||
## Initial setup {#initial-setup}
|
||||
|
||||
To setup your site's blog, start by creating a `blog` directory.
|
||||
To set up your site's blog, start by creating a `blog` directory.
|
||||
|
||||
Then, add an item link to your blog within `docusaurus.config.js`:
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ To publish in the blog, create a Markdown file within the blog directory.
|
|||
|
||||
For example, create a file at `website/blog/2019-09-05-hello-docusaurus-v2.md`:
|
||||
|
||||
```yml title="website/blog/2019-09-05-hello-docusaurus-v2.md"
|
||||
```md title="website/blog/2019-09-05-hello-docusaurus-v2.md"
|
||||
---
|
||||
title: Welcome Docusaurus v2
|
||||
description: This is my first post on Docusaurus 2.
|
||||
|
|
@ -59,6 +59,7 @@ tags: [hello, docusaurus-v2]
|
|||
image: https://i.imgur.com/mErPwqL.png
|
||||
hide_table_of_contents: false
|
||||
---
|
||||
|
||||
Welcome to this blog. This blog is created with [**Docusaurus 2**](https://docusaurus.io/).
|
||||
|
||||
<!--truncate-->
|
||||
|
|
@ -68,35 +69,7 @@ This is my first post on Docusaurus 2.
|
|||
A whole bunch of exploration to follow.
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Docusaurus will extract a `YYYY-MM-DD` date from a file/folder name such as `YYYY-MM-DD-my-blog-post-title.md`.
|
||||
|
||||
This naming convention is optional, and you can provide the date as FrontMatter.
|
||||
|
||||
<details>
|
||||
<summary>Example supported patterns</summary>
|
||||
|
||||
- `2021-05-28-my-blog-post-title.md`
|
||||
- `2021-05-28-my-blog-post-title.mdx`
|
||||
- `2021-05-28-my-blog-post-title/index.md`
|
||||
- `2021-05-28/my-blog-post-title.md`
|
||||
- `2021/05/28/my-blog-post-title.md`
|
||||
- `2021/05-28-my-blog-post-title.md`
|
||||
- `2021/05/28/my-blog-post-title/index.md`
|
||||
- ...
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Using a folder can be convenient to co-locate blog post images alongside the Markdown file.
|
||||
|
||||
:::
|
||||
|
||||
The only required field in the front matter is `title`; however, we provide options to add more metadata to your blog post, for example, author information. For all possible fields, see [the API documentation](api/plugins/plugin-content-blog.md#markdown-frontmatter).
|
||||
The front matter is useful to add more metadata to your blog post, for example, author information, but Docusaurus will be able to infer all necessary metadata without the front matter. For all possible fields, see [the API documentation](api/plugins/plugin-content-blog.md#markdown-front-matter).
|
||||
|
||||
## Blog list {#blog-list}
|
||||
|
||||
|
|
@ -104,10 +77,11 @@ The blog's index page (by default, it is at `/blog`) is the _blog list page_, wh
|
|||
|
||||
Use the `<!--truncate-->` marker in your blog post to represent what will be shown as the summary when viewing all published blog posts. Anything above `<!--truncate-->` will be part of the summary. For example:
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
title: Truncation Example
|
||||
---
|
||||
|
||||
All these will be part of the blog post summary.
|
||||
|
||||
Even this.
|
||||
|
|
@ -121,7 +95,7 @@ Not this.
|
|||
Or this.
|
||||
```
|
||||
|
||||
By default, 10 posts are shown on each blog list page, but you can control pagination with the `postsPerPage` option in the plugin configuration. If you set `postsPerPage: 'ALL'`, pagination will be disabled and all posts will be displayed on the first page. You can also add meta description to the blog list page for better SEO:
|
||||
By default, 10 posts are shown on each blog list page, but you can control pagination with the `postsPerPage` option in the plugin configuration. If you set `postsPerPage: 'ALL'`, pagination will be disabled and all posts will be displayed on the first page. You can also add a meta description to the blog list page for better SEO:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -147,7 +121,7 @@ module.exports = {
|
|||
|
||||
The blog sidebar displays recent blog posts. The default number of items shown is 5, but you can customize with the `blogSidebarCount` option in the plugin configuration. By setting `blogSidebarCount: 0`, the sidebar will be completely disabled, with the container removed as well. This will increase the width of the main container. Specially, if you have set `blogSidebarCount: 'ALL'`, _all_ posts will be displayed.
|
||||
|
||||
You can also alter the sidebar heading text with the `blogSidebarTitle` option. For example, if you have set `blogSidebarCount: 'ALL'`, instead of the default "Recent posts", you may would rather make it say "All posts":
|
||||
You can also alter the sidebar heading text with the `blogSidebarTitle` option. For example, if you have set `blogSidebarCount: 'ALL'`, instead of the default "Recent posts", you may rather make it say "All posts":
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -167,19 +141,61 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
## Blog post date {#blog-post-date}
|
||||
|
||||
Docusaurus will extract a `YYYY-MM-DD` date from a file/folder name such as `YYYY-MM-DD-my-blog-post-title.md`.
|
||||
|
||||
<details>
|
||||
<summary>Example supported patterns</summary>
|
||||
|
||||
| Pattern | Example |
|
||||
| --- | --- |
|
||||
| Single file | `2021-05-28-my-blog-post-title.md` |
|
||||
| MDX file | `2021-05-28-my-blog-post-title.mdx` |
|
||||
| Single folder + `index.md` | `2021-05-28-my-blog-post-title/index.md` |
|
||||
| Folder named by date | `2021-05-28/my-blog-post-title.md` |
|
||||
| Nested folders by date | `2021/05/28/my-blog-post-title.md` |
|
||||
| Partially nested folders by date | `2021/05-28-my-blog-post-title.md` |
|
||||
| Nested folders + `index.md` | `2021/05/28/my-blog-post-title/index.md` |
|
||||
| Date in the middle of path | `category/2021/05-28-my-blog-post-title.md` |
|
||||
|
||||
The date will be excised from the path and appended to the beginning of the URL slug.
|
||||
|
||||
</details>
|
||||
|
||||
:::tip
|
||||
|
||||
Using a folder can be convenient to co-locate blog post images alongside the Markdown file.
|
||||
|
||||
:::
|
||||
|
||||
This naming convention is optional, and you can also provide the date as front matter. Since the front matter follows YAML syntax where the datetime notation is supported, you can use front matter if you need more fine-grained publish dates. For example, if you have multiple posts published on the same day, you can order them according to the time of the day:
|
||||
|
||||
```md title="earlier-post.md"
|
||||
---
|
||||
date: 2021-09-13T10:00
|
||||
---
|
||||
```
|
||||
|
||||
```md title="later-post.md"
|
||||
---
|
||||
date: 2021-09-13T18:00
|
||||
---
|
||||
```
|
||||
|
||||
## Blog post authors {#blog-post-authors}
|
||||
|
||||
Use the `authors` FrontMatter field to declare blog post authors.
|
||||
Use the `authors` front matter field to declare blog post authors.
|
||||
|
||||
### Inline authors {#inline-authors}
|
||||
|
||||
Blog post authors can be declared directly inside the FrontMatter:
|
||||
Blog post authors can be declared directly inside the front matter:
|
||||
|
||||
````mdx-code-block
|
||||
<Tabs groupId="author-frontmatter">
|
||||
<Tabs groupId="author-front-matter">
|
||||
<TabItem value="single" label="Single author">
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors:
|
||||
name: Joel Marcey
|
||||
|
|
@ -192,7 +208,7 @@ authors:
|
|||
</TabItem>
|
||||
<TabItem value="multiple" label="Multiple authors">
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors:
|
||||
- name: Joel Marcey
|
||||
|
|
@ -218,9 +234,9 @@ This option works best to get started, or for casual, irregular authors.
|
|||
|
||||
:::info
|
||||
|
||||
Prefer usage of the `authors` FrontMatter, but the legacy `author_*` FrontMatter remains supported:
|
||||
Prefer using the `authors` front matter, but the legacy `author_*` front matter remains supported:
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
author: Joel Marcey
|
||||
author_title: Co-creator of Docusaurus 1
|
||||
|
|
@ -233,9 +249,9 @@ author_image_url: https://github.com/JoelMarcey.png
|
|||
|
||||
### Global authors {#global-authors}
|
||||
|
||||
For regular blog post authors, it can be tedious to maintain authors information inlined in each blog post.
|
||||
For regular blog post authors, it can be tedious to maintain authors' information inlined in each blog post.
|
||||
|
||||
It is possible declare those authors globally in a configuration file:
|
||||
It is possible to declare those authors globally in a configuration file:
|
||||
|
||||
```yml title="website/blog/authors.yml"
|
||||
jmarcey:
|
||||
|
|
@ -257,13 +273,13 @@ Use the `authorsMapPath` plugin option to configure the path. JSON is also suppo
|
|||
|
||||
:::
|
||||
|
||||
In blog posts FrontMatter, you can reference the authors declared in the global configuration file:
|
||||
In blog posts front matter, you can reference the authors declared in the global configuration file:
|
||||
|
||||
````mdx-code-block
|
||||
<Tabs groupId="author-frontmatter">
|
||||
<Tabs groupId="author-front-matter">
|
||||
<TabItem value="single" label="Single author">
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors: jmarcey
|
||||
---
|
||||
|
|
@ -272,7 +288,7 @@ authors: jmarcey
|
|||
</TabItem>
|
||||
<TabItem value="multiple" label="Multiple authors">
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors: [jmarcey, slorber]
|
||||
---
|
||||
|
|
@ -291,7 +307,7 @@ The `authors` system is very flexible and can suit more advanced use-case:
|
|||
|
||||
You can use global authors most of the time, and still use inline authors:
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors:
|
||||
- jmarcey
|
||||
|
|
@ -310,7 +326,7 @@ authors:
|
|||
|
||||
You can customize the global author's data on per-blog-post basis:
|
||||
|
||||
```yml title="my-blog-post.md"
|
||||
```md title="my-blog-post.md"
|
||||
---
|
||||
authors:
|
||||
- key: jmarcey
|
||||
|
|
@ -335,6 +351,8 @@ website/i18n/[locale]/docusaurus-plugin-content-blog/authors.yml
|
|||
|
||||
:::
|
||||
|
||||
An author, either declared through front matter or through the authors map, needs to have a name or an avatar, or both. If all authors of a post don't have names, Docusaurus will display their avatars compactly. See [this test post](/tests/blog/2022/01/20/image-only-authors) for the effect.
|
||||
|
||||
## Reading time {#reading-time}
|
||||
|
||||
Docusaurus generates a reading time estimation for each blog post based on word count. We provide an option to customize this.
|
||||
|
|
@ -393,7 +411,7 @@ module.exports = {
|
|||
|
||||
Usage:
|
||||
|
||||
```yml "my-blog-post.md"
|
||||
```md "my-blog-post.md"
|
||||
---
|
||||
hide_reading_time: true
|
||||
---
|
||||
|
|
@ -473,7 +491,7 @@ type BlogOptions = {
|
|||
|
||||
Example usage:
|
||||
|
||||
```js {8-11} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
|
|
@ -481,10 +499,12 @@ module.exports = {
|
|||
'@docusaurus/preset-classic',
|
||||
{
|
||||
blog: {
|
||||
// highlight-start
|
||||
feedOptions: {
|
||||
type: 'all',
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`,
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -552,7 +572,7 @@ Don't forget to delete the existing homepage at `./src/pages/index.js` or else t
|
|||
|
||||
:::tip
|
||||
|
||||
There's also a "Docs-only mode" for those who only want to use the docs. Read [Docs-only mode](./guides/docs/docs-introduction.md) for detailed instructions or a more elaborated explanation of `routeBasePath`.
|
||||
There's also a "Docs-only mode" for those who only want to use the docs. Read [Docs-only mode](./guides/docs/docs-introduction.md) for detailed instructions or a more elaborate explanation of `routeBasePath`.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -7,13 +7,34 @@ Docusaurus allows sites to define the list of supported browsers through a [brow
|
|||
|
||||
## Purpose {#purpose}
|
||||
|
||||
Websites need to balance between backward compatibility and bundle size. As old browsers do not support modern APIs or syntax, more code is needed to implement the same functionality, penalizing all other users with increased site load time. As a tradeoff, the Docusaurus bundler only supports browser versions defined in the browser list.
|
||||
Websites need to balance between backward compatibility and bundle size. As old browsers do not support modern APIs or syntax, more code is needed to implement the same functionality.
|
||||
|
||||
For example, you may use the [optional chaining syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining):
|
||||
|
||||
```js
|
||||
const value = obj?.prop?.val;
|
||||
```
|
||||
|
||||
...which unfortunately is only recognized by browser versions released after 2020. To be compatible with earlier browser versions, when building your site for production, our JS loader will transpile your code to a more verbose syntax:
|
||||
|
||||
```js
|
||||
var _obj, _obj$prop;
|
||||
|
||||
const value =
|
||||
(_obj = obj) === null || _obj === void 0
|
||||
? void 0
|
||||
: (_obj$prop = _obj.prop) === null || _obj$prop === void 0
|
||||
? void 0
|
||||
: _obj$prop.val;
|
||||
```
|
||||
|
||||
However, this penalizes all other users with increased site load time because the 29-character line now becomes 168 characters—a 6-fold increase! (In practice, it will be better because the names used will be shorter.) As a tradeoff, the JS loader only transpiles the syntax to the degree that's supported by all browser versions defined in the browser list.
|
||||
|
||||
The browser list by default is provided through the `package.json` file as a root `browserslist` field.
|
||||
|
||||
:::caution
|
||||
|
||||
On old browsers, the compiled output will use unsupported (too recent) JS syntax, causing React to fail to initialize and ending up with a static website with only HTML/CSS and no JS.
|
||||
On old browsers, the compiled output will use unsupported (too recent) JS syntax, causing React to fail to initialize and end up with a static website with only HTML/CSS and no JS.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -21,10 +42,11 @@ On old browsers, the compiled output will use unsupported (too recent) JS syntax
|
|||
|
||||
Websites initialized with the default classic template has the following in `package.json`:
|
||||
|
||||
```json {4-11} title="package.json"
|
||||
```json title="package.json"
|
||||
{
|
||||
"name": "docusaurus",
|
||||
// ...
|
||||
// highlight-start
|
||||
"browserslist": {
|
||||
"production": [">0.5%", "not dead", "not op_mini all"],
|
||||
"development": [
|
||||
|
|
@ -33,6 +55,7 @@ Websites initialized with the default classic template has the following in `pac
|
|||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
// highlight-end
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
|
@ -47,29 +70,34 @@ And browsers used in development are:
|
|||
|
||||
- The latest version of Chrome _or_ Firefox _or_ Safari.
|
||||
|
||||
You can "evaluate" any config with the `browserlist` cli to obtain the actual list:
|
||||
You can "evaluate" any config with the `browserslist` cli to obtain the actual list:
|
||||
|
||||
```bash
|
||||
npx browserslist --env="production"
|
||||
```
|
||||
|
||||
The output are all browsers supported in production. Below is the output in May, 2021:
|
||||
The output is all browsers supported in production. Below is the output in January 2022:
|
||||
|
||||
```text
|
||||
and_chr 89
|
||||
and_chr 96
|
||||
and_uc 12.12
|
||||
chrome 89
|
||||
chrome 88
|
||||
chrome 87
|
||||
edge 89
|
||||
edge 88
|
||||
firefox 86
|
||||
chrome 96
|
||||
chrome 95
|
||||
chrome 94
|
||||
edge 96
|
||||
firefox 95
|
||||
firefox 94
|
||||
ie 11
|
||||
ios_saf 14.0-14.5
|
||||
ios_saf 13.4-13.7
|
||||
safari 14
|
||||
ios_saf 15.2
|
||||
ios_saf 15.0-15.1
|
||||
ios_saf 14.5-14.8
|
||||
ios_saf 14.0-14.4
|
||||
ios_saf 12.2-12.5
|
||||
opera 82
|
||||
opera 81
|
||||
safari 15.1
|
||||
safari 14.1
|
||||
safari 13.1
|
||||
samsung 13.0
|
||||
```
|
||||
|
||||
## Read more {#read-more}
|
||||
|
|
@ -39,7 +39,7 @@ Builds and serves a preview of your site locally with [Webpack Dev Server](https
|
|||
| --- | --- | --- |
|
||||
| `--port` | `3000` | Specifies the port of the dev server. |
|
||||
| `--host` | `localhost` | Specify a host to use. For example, if you want your server to be accessible externally, you can use `--host 0.0.0.0`. |
|
||||
| `--hot-only` | `false` | Enables Hot Module Replacement without page refresh as fallback in case of build failures. More information [here](https://webpack.js.org/configuration/dev-server/#devserverhotonly). |
|
||||
| `--hot-only` | `false` | Enables Hot Module Replacement without page refresh as a fallback in case of build failures. More information [here](https://webpack.js.org/configuration/dev-server/#devserverhotonly). |
|
||||
| `--no-open` | `false` | Do not open automatically the page in the browser. |
|
||||
| `--config` | `undefined` | Path to docusaurus config file, default to `[siteDir]/docusaurus.config.js` |
|
||||
| `--poll [optionalIntervalMs]` | `false` | Use polling of files rather than watching for live reload as a fallback in environments where watching doesn't work. More information [here](https://webpack.js.org/configuration/watch/#watchoptionspoll). |
|
||||
|
|
@ -60,7 +60,7 @@ There are multiple ways to obtain a certificate. We will use [mkcert](https://gi
|
|||
|
||||
3. Start the app with Docusaurus HTTPS env variables:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
HTTPS=true SSL_CRT_FILE=localhost.pem SSL_KEY_FILE=localhost-key.pem yarn start
|
||||
```
|
||||
|
||||
|
|
@ -85,55 +85,37 @@ For advanced minification of CSS bundle, we use the [advanced cssnano preset](ht
|
|||
|
||||
:::
|
||||
|
||||
### `docusaurus swizzle [siteDir]` {#docusaurus-swizzle-sitedir}
|
||||
### `docusaurus swizzle [themeName] [componentName] [siteDir]` {#docusaurus-swizzle}
|
||||
|
||||
```mdx-code-block
|
||||
import SwizzleWarning from "./_partials/swizzleWarning.mdx"
|
||||
|
||||
<SwizzleWarning/>
|
||||
```
|
||||
|
||||
Change any Docusaurus theme components to your liking with `npm run swizzle`.
|
||||
[Swizzle](./swizzling.md) a theme component to customize it.
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle [themeName] [componentName] [siteDir]
|
||||
|
||||
# Example (leaving out the siteDir to indicate this directory)
|
||||
npm run swizzle @docusaurus/theme-classic DocSidebar
|
||||
npm run swizzle @docusaurus/theme-classic Footer -- --eject
|
||||
```
|
||||
|
||||
Running the command will copy the relevant theme files to your site folder. You may then make any changes to it and Docusaurus will use it instead of the one provided from the theme.
|
||||
The swizzle CLI is interactive and will guide you through the whole [swizzle process](./swizzling.md).
|
||||
|
||||
`npm run swizzle` without `themeName` lists all the themes available for swizzling; similarly, `npm run swizzle <themeName>` without `componentName` lists all the components available for swizzling.
|
||||
#### Options {#options-swizzle}
|
||||
|
||||
#### Options {#options-2}
|
||||
|
||||
| Name | Description |
|
||||
| ------------------ | -------------------------------------- |
|
||||
| `themeName` | The name of the theme you are using. |
|
||||
| `swizzleComponent` | The name of the component to swizzle. |
|
||||
| `--danger` | Allow swizzling of unstable components |
|
||||
| `--typescript` | Swizzle TypeScript components |
|
||||
|
||||
An example to use `--danger` flag let's consider the below code:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic Logo -- --danger
|
||||
```
|
||||
| Name | Description |
|
||||
| --------------- | ---------------------------------------------------- |
|
||||
| `themeName` | The name of the theme to swizzle from. |
|
||||
| `componentName` | The name of the theme component to swizzle. |
|
||||
| `--list` | Display components available for swizzling |
|
||||
| `--eject` | [Eject](./swizzling.md#ejecting) the theme component |
|
||||
| `--wrap` | [Wrap](./swizzling.md#wrapping) the theme component |
|
||||
| `--danger` | Allow immediate swizzling of unsafe components |
|
||||
| `--typescript` | Swizzle the TypeScript variant component |
|
||||
|
||||
:::caution
|
||||
|
||||
Unstable Components: components that have a higher risk of breaking changes due to internal refactorings.
|
||||
Unsafe components have a higher risk of breaking changes due to internal refactorings.
|
||||
|
||||
:::
|
||||
|
||||
To unswizzle a component, simply delete the files of the swizzled component.
|
||||
|
||||
<!--
|
||||
TODO a separate section for swizzle tutorial.
|
||||
To learn more about swizzling, check [here](#).
|
||||
-->
|
||||
|
||||
### `docusaurus deploy [siteDir]` {#docusaurus-deploy-sitedir}
|
||||
|
||||
Deploys your site with [GitHub Pages](https://pages.github.com/). Check out the docs on [deployment](deployment.mdx#deploying-to-github-pages) for more details.
|
||||
|
|
@ -143,7 +125,7 @@ Deploys your site with [GitHub Pages](https://pages.github.com/). Check out the
|
|||
| Name | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `--out-dir` | `build` | The full path for the new output directory, relative to the current workspace. |
|
||||
| `--skip-build` | `false` | Deploy website without building it. This may be useful when using custom deploy script. |
|
||||
| `--skip-build` | `false` | Deploy website without building it. This may be useful when using a custom deploy script. |
|
||||
| `--config` | `undefined` | Path to docusaurus config file, default to `[siteDir]/docusaurus.config.js` |
|
||||
|
||||
### `docusaurus serve [siteDir]` {#docusaurus-serve-sitedir}
|
||||
|
|
@ -175,7 +157,7 @@ By default, the files are written in `website/i18n/<defaultLocale>/...`.
|
|||
| `--locale` | `<defaultLocale>` | Define which locale folder you want to write translations the JSON files in |
|
||||
| `--override` | `false` | Override existing translation messages |
|
||||
| `--config` | `undefined` | Path to docusaurus config file, default to `[siteDir]/docusaurus.config.js` |
|
||||
| `--messagePrefix` | `''` | Allows to add a prefix to each translation message, to help you highlight untranslated strings |
|
||||
| `--messagePrefix` | `''` | Allows adding a prefix to each translation message, to help you highlight untranslated strings |
|
||||
|
||||
### `docusaurus write-heading-ids [siteDir] [files]` {#docusaurus-write-heading-ids-sitedir}
|
||||
|
||||
|
|
@ -5,9 +5,9 @@ title: Configuration
|
|||
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
Docusaurus has a unique take on configurations. We encourage you to congregate information of your site into one place. We guard the fields of this file, and facilitate making this data object accessible across your site.
|
||||
Docusaurus has a unique take on configurations. We encourage you to congregate information about your site into one place. We guard the fields of this file and facilitate making this data object accessible across your site.
|
||||
|
||||
Keeping a well-maintained `docusaurus.config.js` helps you, your collaborators, and your open source contributors be able to focus on documentation while still being able to customize the site.
|
||||
Keeping a well-maintained `docusaurus.config.js` helps you, your collaborators, and your open source contributors to be able to focus on documentation while still being able to customize the site.
|
||||
|
||||
## What goes into a `docusaurus.config.js`? {#what-goes-into-a-docusaurusconfigjs}
|
||||
|
||||
|
|
@ -23,9 +23,9 @@ For exact reference to each of the configurable fields, you may refer to [**`doc
|
|||
|
||||
### Site metadata {#site-metadata}
|
||||
|
||||
Site metadata contains the essential global metadata such as `title`, `url`, `baseUrl` and `favicon`.
|
||||
Site metadata contains the essential global metadata such as `title`, `url`, `baseUrl`, and `favicon`.
|
||||
|
||||
They are used in a number of places such as your site's title and headings, browser tab icon, social sharing (Facebook, Twitter) information or even to generate the correct path to serve your static files.
|
||||
They are used in several places such as your site's title and headings, browser tab icon, social sharing (Facebook, Twitter) information or even to generate the correct path to serve your static files.
|
||||
|
||||
### Deployment configurations {#deployment-configurations}
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ It is recommended to check the [deployment docs](deployment.mdx) for more inform
|
|||
|
||||
### Theme, plugin, and preset configurations {#theme-plugin-and-preset-configurations}
|
||||
|
||||
List the [theme](using-themes.md), [plugins](using-plugins.md), and [presets](presets.md) for your site in the `themes`, `plugins`, and `presets` fields, respectively. These are typically npm packages:
|
||||
List the [themes](./using-plugins.md#using-themes), [plugins](./using-plugins.md), and [presets](./using-plugins.md#using-presets) for your site in the `themes`, `plugins`, and `presets` fields, respectively. These are typically npm packages:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -50,7 +50,7 @@ module.exports = {
|
|||
|
||||
:::tip
|
||||
|
||||
Docusaurus supports **module shorthands**, allowing you to simplify the above configuration as:
|
||||
Docusaurus supports [**module shorthands**](./using-plugins.md#module-shorthands), allowing you to simplify the above configuration as:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -60,51 +60,6 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
<summary>How are shorthands resolved?</summary>
|
||||
|
||||
When it sees a plugin / theme / preset name, it tries to load one of the following, in that order:
|
||||
|
||||
- `[name]`
|
||||
- `@docusaurus/[moduleType]-[name]`
|
||||
- `docusaurus-[moduleType]-[name]`,
|
||||
|
||||
where `moduleType` is one of `'preset'`, `'theme'`, `'plugin'`, depending on which field the module name is declared in. The first module name that's successfully found is loaded.
|
||||
|
||||
If the name is scoped (beginning with `@`), the name is first split into scope and package name by the first slash:
|
||||
|
||||
```
|
||||
@scope
|
||||
^----^
|
||||
scope (no name!)
|
||||
|
||||
@scope/awesome
|
||||
^----^ ^-----^
|
||||
scope name
|
||||
|
||||
@scope/awesome/main
|
||||
^----^ ^----------^
|
||||
scope name
|
||||
```
|
||||
|
||||
If the name is not specified, `{scope}/docusaurus-{type}` is loaded. Otherwise, the following are attempted:
|
||||
|
||||
- `{scope}/{name}`
|
||||
- `{scope}/docusaurus-{type}-{name}`
|
||||
|
||||
Below are some examples, for a plugin registered in the `plugins` field. Note that unlike [ESLint](https://eslint.org/docs/user-guide/configuring/plugins#configuring-plugins) or [Babel](https://babeljs.io/docs/en/options#name-normalization) where a consistent naming convention for plugins is mandated, Docusaurus permits greater naming freedom, so the resolutions are not certain, but follows the priority defined above.
|
||||
|
||||
| Declaration | May be resolved as |
|
||||
| --- | --- |
|
||||
| `awesome` | `docusaurus-plugin-awesome` |
|
||||
| `sitemap` | [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) |
|
||||
| `@mycompany` | `@mycompany/docusaurus-plugin` (the only possible resolution!) |
|
||||
| `@mycompany/awesome` | `@mycompany/docusaurus-plugin-awesome` |
|
||||
| `@mycompany/awesome/web` | `@mycompany/docusaurus-plugin-awesome/web` |
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
They can also be loaded from local directories:
|
||||
|
|
@ -165,7 +120,7 @@ The `presets: [['classic', {...}]]` shorthand works as well.
|
|||
|
||||
:::
|
||||
|
||||
For further help configuring themes, plugins, and presets, see [Using Themes](using-themes.md), [Using Plugins](using-plugins.md), and [Using Presets](presets.md).
|
||||
For further help configuring themes, plugins, and presets, see [Using Plugins](./using-plugins.md).
|
||||
|
||||
### Custom configurations {#custom-configurations}
|
||||
|
||||
|
|
@ -215,7 +170,7 @@ If you just want to use those fields on the client side, you could create your o
|
|||
|
||||
## Customizing Babel Configuration {#customizing-babel-configuration}
|
||||
|
||||
For new Docusaurus projects, we automatically generated a `babel.config.js` in project root.
|
||||
For new Docusaurus projects, we automatically generated a `babel.config.js` in the project root.
|
||||
|
||||
```js title="babel.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -223,4 +178,4 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
Most of the times, this configuration will work just fine. If you want to customize it, you can directly edit this file to customize babel configuration. For your changes to take effect, you need to restart Docusaurus devserver.
|
||||
Most of the time, this configuration will work just fine. If you want to customize your babel configuration (e.g. to add support for Flow), you can directly edit this file. For your changes to take effect, you need to restart the Docusaurus dev server.
|
||||
|
|
@ -25,7 +25,7 @@ A Docusaurus site is statically rendered, and it can generally work without Java
|
|||
|
||||
## Configuration {#configuration}
|
||||
|
||||
The following parameters are required in `docusaurus.config.js` in order for Docusaurus to optimize routing and serve files from the correct location:
|
||||
The following parameters are required in `docusaurus.config.js` to optimize routing and serve files from the correct location:
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
|
|
@ -34,7 +34,7 @@ The following parameters are required in `docusaurus.config.js` in order for Doc
|
|||
|
||||
## Testing your Build Locally {#testing-build-locally}
|
||||
|
||||
It is important to test your build locally before deploying to production. Docusaurus provides a [`docusaurus serve`](cli.md#docusaurus-serve-sitedir) command for that:
|
||||
It is important to test your build locally before deploying it for production. Docusaurus provides a [`docusaurus serve`](cli.md#docusaurus-serve-sitedir) command for that:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run serve
|
||||
|
|
@ -54,7 +54,38 @@ Use [slorber/trailing-slash-guide](https://github.com/slorber/trailing-slash-gui
|
|||
|
||||
:::
|
||||
|
||||
## Choosing a hosting provider
|
||||
## Using environment variables {#using-environment-variables}
|
||||
|
||||
Putting potentially sensitive information in the environment is common practice. However, in a typical Docusaurus website, the `docusaurus.config.js` file is the only interface to the Node.js environment (see [our architecture overview](advanced/architecture.md)), while everything else—MDX pages, React components... are client side and do not have direct access to the `process` global. In this case, you can consider using [`customFields`](api/docusaurus.config.js.md#customfields) to pass environment variables to the client side.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// If you are using dotenv (https://www.npmjs.com/package/dotenv)
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
title: '...',
|
||||
url: process.env.URL, // You can use environment variables to control site specifics as well
|
||||
// highlight-start
|
||||
customFields: {
|
||||
// Put your custom environment here
|
||||
teamEmail: process.env.EMAIL,
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
```jsx title="home.jsx"
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
export default function Home() {
|
||||
const {
|
||||
siteConfig: {customFields},
|
||||
} = useDocusaurusContext();
|
||||
return <div>Contact us through {customFields.teamEmail}!</div>;
|
||||
}
|
||||
```
|
||||
|
||||
## Choosing a hosting provider {#choosing-a-hosting-provider}
|
||||
|
||||
There are a few common hosting options:
|
||||
|
||||
|
|
@ -70,8 +101,8 @@ If you are unsure of which one to choose, ask the following questions:
|
|||
How much resource (person-hours, money) am I willing to invest in this?
|
||||
</summary>
|
||||
|
||||
- 🔴 Self-hosting is the hardest to set up—you would usually need an experienced person to manage this. Cloud services is almost never free, and setting up an on-site server and connecting it to the WAN can be more costly.
|
||||
- 🟢 Jamstack providers can help you set up a working website in almost no time and offers features like server-side redirects that are easily configurable. Many providers offer generous build time quota even for free plans that you would almost never exceed. However, it's still ultimately limited—you would need to pay once you hit the limit. Check the pricing page of your provider for details.
|
||||
- 🔴 Self-hosting is the hardest to set up—you would usually need an experienced person to manage this. Cloud services are almost never free, and setting up an on-site server and connecting it to the WAN can be even more costly.
|
||||
- 🟢 Jamstack providers can help you set up a working website in almost no time and offers features like server-side redirects that are easily configurable. Many providers offer generous build time quotas even for free plans that you would almost never exceed. However, it's still ultimately limited—you would need to pay once you hit the limit. Check the pricing page of your provider for details.
|
||||
- 🟡 The GitHub Pages deployment workflow can be tedious to set up. (Evidence: see the length of [Deploying to GitHub Pages](#deploying-to-github-pages)!) However, this service (including build and deployment) is always free for public repositories, and we have detailed instructions to help you make it work.
|
||||
|
||||
</details>
|
||||
|
|
@ -124,10 +155,12 @@ For the same concern of up-to-datedness, we have stopped accepting PRs adding ne
|
|||
|
||||
To deploy your Docusaurus 2 sites to [Netlify](https://www.netlify.com/), first make sure the following options are properly configured:
|
||||
|
||||
```js {2-3} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// highlight-start
|
||||
url: 'https://docusaurus-2.netlify.app', // Url to your site with no trailing slash
|
||||
baseUrl: '/', // Base directory of your site relative to your repo
|
||||
// highlight-end
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
|
@ -192,7 +225,7 @@ Docusaurus provides an easy way to publish to [GitHub Pages](https://pages.githu
|
|||
|
||||
### Overview {#github-pages-overview}
|
||||
|
||||
Usually, there are two repositories (at least, two branches) involved in a publishing process: the branch containing the source files, and the branch containing the build output to be served with GitHub Pages. In the following tutorial they will be referred to as **"source"** and **"deployment"**, respectively.
|
||||
Usually, there are two repositories (at least, two branches) involved in a publishing process: the branch containing the source files, and the branch containing the build output to be served with GitHub Pages. In the following tutorial, they will be referred to as **"source"** and **"deployment"**, respectively.
|
||||
|
||||
Each GitHub repository is associated with a GitHub Pages service. If the deployment repository is called `my-org/my-project` (where `my-org` is the organization name or username), the deployed site will appear at `https://my-org.github.io/my-project/`. Specially, if the deployment repository is called `my-org/my-org.github.io` (the _organization GitHub Pages repo_), the site will appear at `https://my-org.github.io/`.
|
||||
|
||||
|
|
@ -228,14 +261,16 @@ GitHub Pages adds a trailing slash to Docusaurus URLs by default. It is recommen
|
|||
|
||||
Example:
|
||||
|
||||
```jsx {3-6} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
url: 'https://endiliey.github.io', // Your website URL
|
||||
baseUrl: '/',
|
||||
// highlight-start
|
||||
projectName: 'endiliey.github.io',
|
||||
organizationName: 'endiliey',
|
||||
trailingSlash: false,
|
||||
// highlight-end
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
|
@ -296,7 +331,7 @@ cmd /C 'set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy'
|
|||
|
||||
Beginning in August 2021, GitHub requires every command-line sign-in to use the **personal access token** instead of the password. When GitHub prompts for your password, enter the PAT instead. See the [GitHub documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for more information.
|
||||
|
||||
Alternatively, you can use SSH (`USE_SSH=true`) to login.
|
||||
Alternatively, you can use SSH (`USE_SSH=true`) to log in.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -309,7 +344,7 @@ The workflow examples below assume your website source resides in the `main` bra
|
|||
Our goal is that:
|
||||
|
||||
1. When a new pull request is made to `main` and updates `website/`, there's an action that ensures the site builds successfully, without actually deploying. This job will be called `test-deploy`.
|
||||
2. When a pull request is merged to the `main` branch or someone pushes to the `main` branch directly and `website/` is updated, it will be built and deployed to the `gh-pages` branch. After that, the new built output will be served on the GitHub Pages site. This job will be called `deploy`.
|
||||
2. When a pull request is merged to the `main` branch or someone pushes to the `main` branch directly and `website/` is updated, it will be built and deployed to the `gh-pages` branch. After that, the new build output will be served on the GitHub Pages site. This job will be called `deploy`.
|
||||
|
||||
Here are two approaches to deploying your docs with GitHub Actions. Based on the location of your deployment branch (`gh-pages`), choose the relevant tab below:
|
||||
|
||||
|
|
@ -320,7 +355,7 @@ Here are two approaches to deploying your docs with GitHub Actions. Based on the
|
|||
<Tabs>
|
||||
<TabItem value="same" label="Same">
|
||||
|
||||
While you can have both jobs defined in the same workflow file, the `deploy` job will always be listed as skipped in the PR check suite status. That's added noise providing no value to the review process, and as you cannot easily share common snippets, it is better to manage them as separate workflows instead.
|
||||
While you can have both jobs defined in the same workflow file, the original `deploy` workflow will always be listed as skipped in the PR check suite status, which is not communicative of the actual status and provides no value to the review process. We therefore propose to manage them as separate workflows instead.
|
||||
|
||||
We will use a popular third-party deployment action: [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus).
|
||||
|
||||
|
|
@ -330,10 +365,12 @@ We will use a popular third-party deployment action: [peaceiris/actions-gh-pages
|
|||
|
||||
Add these two workflow files:
|
||||
|
||||
:::warning
|
||||
:::warning Tweak the parameters for your setup
|
||||
|
||||
These files assume you are using yarn. If you use npm, change `cache: yarn`, `yarn install --frozen-lockfile`, `yarn build` to `cache: npm`, `npm ci`, `npm run build` accordingly.
|
||||
|
||||
If your Docusaurus project is not at the root of the repo, you would need to change the paths as well.
|
||||
|
||||
:::
|
||||
|
||||
```yml title=".github/workflows/deploy.yml"
|
||||
|
|
@ -341,8 +378,10 @@ name: Deploy to GitHub Pages
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: [website/**]
|
||||
branches:
|
||||
- main
|
||||
# Review gh actions docs if you want to further define triggers, paths, etc
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
|
@ -352,13 +391,13 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 16.x
|
||||
cache: yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build website
|
||||
working-directory: website
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn build
|
||||
run: yarn build
|
||||
|
||||
# Popular action to deploy to GitHub Pages:
|
||||
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
|
||||
|
|
@ -367,8 +406,9 @@ jobs:
|
|||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Build output to publish to the `gh-pages` branch:
|
||||
publish_dir: ./website/build
|
||||
# Assign commit authorship to the official GH-Actions bot for deploys to `gh-pages` branch:
|
||||
publish_dir: ./build
|
||||
# The following lines assign commit authorship to the official
|
||||
# GH-Actions bot for deploys to `gh-pages` branch:
|
||||
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
|
||||
# The GH actions bot is used by default if you didn't specify the two fields.
|
||||
# You can swap them out with your own user credentials.
|
||||
|
|
@ -381,8 +421,10 @@ name: Test deployment
|
|||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths: [website/**]
|
||||
branches:
|
||||
- main
|
||||
# Review gh actions docs if you want to further define triggers, paths, etc
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
|
||||
|
||||
jobs:
|
||||
test-deploy:
|
||||
|
|
@ -392,13 +434,13 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 16.x
|
||||
cache: yarn
|
||||
- name: Test build
|
||||
working-directory: website
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn build
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Test build website
|
||||
run: yarn build
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
@ -444,12 +486,12 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 16.x
|
||||
cache: yarn
|
||||
- name: Test deployment
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn build
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Test build website
|
||||
run: yarn build
|
||||
deploy:
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -571,10 +613,10 @@ steps:
|
|||
|
||||
1. Create a new ssh key that will be the [deploy key](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys) for your project.
|
||||
2. Name your private and public keys to be specific and so that it does not overwrite your other [ssh keys](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
|
||||
3. Go to `https://github.com/USERNAME/REPO/settings/keys` and add a new deploy key by pasting in our public key you just generated.
|
||||
4. Open your Drone.io dashboard and login. The URL looks like `https://cloud.drone.io/USERNAME/REPO`.
|
||||
3. Go to `https://github.com/USERNAME/REPO/settings/keys` and add a new deploy key by pasting in the public key you just generated.
|
||||
4. Open your Drone.io dashboard and log in. The URL looks like `https://cloud.drone.io/USERNAME/REPO`.
|
||||
5. Click on the repository, click on activate repository, and add a secret called `git_deploy_private_key` with your private key value that you just generated.
|
||||
6. Create a `.drone.yml` on the root of your repository with below text.
|
||||
6. Create a `.drone.yml` on the root of your repository with the below text.
|
||||
|
||||
```yml title=".drone.yml"
|
||||
kind: pipeline
|
||||
|
|
@ -600,13 +642,17 @@ trigger:
|
|||
|
||||
Now, whenever you push a new tag to GitHub, this trigger will start the drone CI job to publish your website.
|
||||
|
||||
## Deploying to Koyeb {#deploying-to-koyeb}
|
||||
|
||||
[Koyeb](https://www.koyeb.com) is a developer-friendly serverless platform to deploy apps globally. The platform lets you seamlessly run Docker containers, web apps, and APIs with git-based deployment, native autoscaling, a global edge network, and built-in service mesh and discovery. Check out the [Koyeb's Docusaurus deployment guide](https://www.koyeb.com/tutorials/deploy-docusaurus-on-koyeb) to get started.
|
||||
|
||||
## Deploying to Render {#deploying-to-render}
|
||||
|
||||
[Render](https://render.com) offers [free static site hosting](https://render.com/docs/static-sites) with fully managed SSL, custom domains, a global CDN and continuous auto-deploy from your Git repo. Get started in just a few minutes by following [Render's guide to deploying Docusaurus](https://render.com/docs/deploy-docusaurus).
|
||||
[Render](https://render.com) offers [free static site hosting](https://render.com/docs/static-sites) with fully managed SSL, custom domains, a global CDN, and continuous auto-deploy from your Git repo. Get started in just a few minutes by following [Render's guide to deploying Docusaurus](https://render.com/docs/deploy-docusaurus).
|
||||
|
||||
## Deploying to Qovery {#deploying-to-qovery}
|
||||
|
||||
[Qovery](https://www.qovery.com) is a fully-managed cloud platform that runs on your AWS, Digital Ocean and Scaleway account where you can host static sites, backend APIs, databases, cron jobs, and all your other apps in one place.
|
||||
[Qovery](https://www.qovery.com) is a fully-managed cloud platform that runs on your AWS, Digital Ocean, and Scaleway account where you can host static sites, backend APIs, databases, cron jobs, and all your other apps in one place.
|
||||
|
||||
1. Create a Qovery account. Visit the [Qovery dashboard](https://console.qovery.com) to create an account if you don't already have one.
|
||||
2. Create a project.
|
||||
|
|
@ -637,13 +683,13 @@ That's it. Watch the status and wait till the app is deployed. To open the appli
|
|||
|
||||
2. Select the project to deploy.
|
||||
|
||||
If you are logged in to Hostman with your GitHub, GitLab or Bitbucket account, at this point you will see the repository with your projects, including the private ones.
|
||||
If you are logged in to Hostman with your GitHub, GitLab, or Bitbucket account, at this point you will see the repository with your projects, including the private ones.
|
||||
|
||||
Choose the project you want to deploy. It must contain the directory with the project’s files (usually it is website or my-website).
|
||||
Choose the project you want to deploy. It must contain the directory with the project's files (e.g. `website`).
|
||||
|
||||
To access a different repository, click **Connect another repository**.
|
||||
|
||||
If you didn’t use your Git account credentials to log in, you’ll be able to access the necessary account now, and then select the project.
|
||||
If you didn't use your Git account credentials to log in, you'll be able to access the necessary account now, and then select the project.
|
||||
|
||||
3. Configure the build settings.
|
||||
|
||||
|
|
@ -686,7 +732,7 @@ Deploy your app in a matter of seconds using surge with the following steps:
|
|||
surge build/
|
||||
```
|
||||
|
||||
First-time users of Surge would be prompted to create an account from the command line(happens only once).
|
||||
First-time users of Surge would be prompted to create an account from the command line (which happens only once).
|
||||
|
||||
Confirm that the site you want to publish is in the `build` directory, a randomly generated subdomain `*.surge.sh subdomain` is always given (which can be edited).
|
||||
|
||||
|
|
@ -695,10 +741,10 @@ Confirm that the site you want to publish is in the `build` directory, a randoml
|
|||
If you have a domain name you can deploy your site using surge to your domain using the command:
|
||||
|
||||
```bash
|
||||
surge build/ yourdomain.com
|
||||
surge build/ your-domain.com
|
||||
```
|
||||
|
||||
Your site is now deployed for free at `subdomain.surge.sh` or `yourdomain.com` depending on the method you chose.
|
||||
Your site is now deployed for free at `subdomain.surge.sh` or `your-domain.com` depending on the method you chose.
|
||||
|
||||
### Setting up CNAME file {#setting-up-cname-file}
|
||||
|
||||
|
|
@ -724,3 +770,11 @@ You can deploy any other changes in the future with the command `surge`.
|
|||
```
|
||||
|
||||
See [docs](https://docs.quantcdn.io/docs/cli/continuous-integration) and [blog](https://www.quantcdn.io/blog) for more examples and use cases for deploying to QuantCDN.
|
||||
|
||||
## Deploying to Layer0 {#deploying-to-layer0}
|
||||
|
||||
[Layer0](https://www.layer0.co) is an all-in-one platform to develop, deploy, preview, experiment on, monitor, and run your headless frontend. It is focused on large, dynamic websites and best-in-class performance through EdgeJS (a JavaScript-based Content Delivery Network), predictive prefetching, and performance monitoring. Layer0 offers a free tier. Get started in just a few minutes by following [Layer0's guide to deploying Docusaurus](https://docs.layer0.co/guides/docusaurus).
|
||||
|
||||
## Deploying to Cloudflare Pages {#deploying-to-cloudflare-pages}
|
||||
|
||||
[Cloudflare Pages](https://pages.cloudflare.com/) is a Jamstack platform for frontend developers to collaborate and deploy websites. Get started within a few minutes by following [this article](https://dev.to/apidev234/deploying-docusaurus-to-cloudflare-pages-565g).
|
||||
|
|
@ -49,7 +49,7 @@ Docusaurus uses this component to catch errors within the theme's layout, and al
|
|||
|
||||
:::note
|
||||
|
||||
This component doesn't catch build-time errors, and only protects against client-side render errors that can happen when using stateful React components.
|
||||
This component doesn't catch build-time errors and only protects against client-side render errors that can happen when using stateful React components.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -63,33 +63,40 @@ This reusable React component will manage all of your changes to the document he
|
|||
|
||||
Usage Example:
|
||||
|
||||
```jsx {2,5,10}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import Head from '@docusaurus/Head';
|
||||
|
||||
const MySEO = () => (
|
||||
// highlight-start
|
||||
<Head>
|
||||
<meta property="og:description" content="My custom description" />
|
||||
<meta charSet="utf-8" />
|
||||
<title>My Title</title>
|
||||
<link rel="canonical" href="http://mysite.com/example" />
|
||||
</Head>
|
||||
// highlight-end
|
||||
);
|
||||
```
|
||||
|
||||
Nested or latter components will override duplicate usages:
|
||||
|
||||
```jsx {2,5,8,11}
|
||||
```jsx
|
||||
<Parent>
|
||||
{/* highlight-start */}
|
||||
<Head>
|
||||
<title>My Title</title>
|
||||
<meta name="description" content="Helmet application" />
|
||||
</Head>
|
||||
{/* highlight-end */}
|
||||
<Child>
|
||||
{/* highlight-start */}
|
||||
<Head>
|
||||
<title>Nested Title</title>
|
||||
<meta name="description" content="Nested component" />
|
||||
</Head>
|
||||
{/* highlight-end */}
|
||||
</Child>
|
||||
</Parent>
|
||||
```
|
||||
|
|
@ -111,16 +118,19 @@ The component is a wrapper around react-router’s `<Link>` component that adds
|
|||
|
||||
External links also work, and automatically have these props: `target="_blank" rel="noopener noreferrer"`.
|
||||
|
||||
```jsx {2,7}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
const Page = () => (
|
||||
<div>
|
||||
<p>
|
||||
{/* highlight-next-line */}
|
||||
Check out my <Link to="/blog">blog</Link>!
|
||||
</p>
|
||||
<p>
|
||||
{/* highlight-next-line */}
|
||||
Follow me on <Link to="https://twitter.com/docusaurus">Twitter</Link>!
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -135,17 +145,25 @@ The target location to navigate to. Example: `/docs/introduction`.
|
|||
<Link to="/courses" />
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Prefer this component to vanilla `<a>` tags because Docusaurus does a lot of optimizations (e.g. broken path detection, prefetching, applying base URL...) if you use `<Link>`.
|
||||
|
||||
:::
|
||||
|
||||
### `<Redirect/>` {#redirect}
|
||||
|
||||
Rendering a `<Redirect>` will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do. You can refer to [React Router's Redirect documentation](https://reacttraining.com/react-router/web/api/Redirect) for more info on available props.
|
||||
Rendering a `<Redirect>` will navigate to a new location. The new location will override the current location in the history stack like server-side redirects (HTTP 3xx) do. You can refer to [React Router's Redirect documentation](https://reacttraining.com/react-router/web/api/Redirect) for more info on available props.
|
||||
|
||||
Example usage:
|
||||
|
||||
```jsx {2,5}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import {Redirect} from '@docusaurus/router';
|
||||
|
||||
const Home = () => {
|
||||
// highlight-next-line
|
||||
return <Redirect to="/docs/test" />;
|
||||
};
|
||||
```
|
||||
|
|
@ -158,11 +176,11 @@ const Home = () => {
|
|||
|
||||
### `<BrowserOnly/>` {#browseronly}
|
||||
|
||||
The `<BrowserOnly>` component permits to render React components only in the browser, after the React app has hydrated.
|
||||
The `<BrowserOnly>` component permits to render React components only in the browser after the React app has hydrated.
|
||||
|
||||
:::tip
|
||||
|
||||
Use it for integrating with code that can't run in Node.js, because `window` or `document` objects are being accessed.
|
||||
Use it for integrating with code that can't run in Node.js, because the `window` or `document` objects are being accessed.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -249,20 +267,20 @@ export default function VisitMyWebsiteMessage() {
|
|||
|
||||
When [localizing your site](./i18n/i18n-introduction.md), the `<Translate/>` component will allow providing **translation support to React components**, such as your homepage. The `<Translate>` component supports [interpolation](#interpolate).
|
||||
|
||||
The translation strings will be extracted from your code with the [`docusaurus write-translations`](./cli.md#docusaurus-write-translations-sitedir) CLI and create a `code.json` translation file in `website/i18n/[locale]`.
|
||||
The translation strings will statically extracted from your code with the [`docusaurus write-translations`](./cli.md#docusaurus-write-translations-sitedir) CLI and a `code.json` translation file will be created in `website/i18n/[locale]`.
|
||||
|
||||
:::note
|
||||
|
||||
The `<Translate/>` props **must be hardcoded strings**.
|
||||
|
||||
Apart the `values` prop used for interpolation, it is **not possible to use variables**, or the static extraction wouldn't work.
|
||||
Apart from the `values` prop used for interpolation, it is **not possible to use variables**, or the static extraction wouldn't work.
|
||||
|
||||
:::
|
||||
|
||||
#### Props {#translate-props}
|
||||
|
||||
- `children`: untranslated string in the default site locale (can contain [interpolation placeholders](#interpolate))
|
||||
- `id`: optional value to use as key in JSON translation files
|
||||
- `id`: optional value to be used as the key in JSON translation files
|
||||
- `description`: optional text to help the translator
|
||||
- `values`: optional object containing interpolation placeholder values
|
||||
|
||||
|
|
@ -302,7 +320,7 @@ export default function Home() {
|
|||
|
||||
:::note
|
||||
|
||||
You can even omit a children prop and specify a translation string in your `code.json` file manually after running the `docusaurus write-translations` CLI command.
|
||||
You can even omit the children prop and specify a translation string in your `code.json` file manually after running the `docusaurus write-translations` CLI command.
|
||||
|
||||
```jsx
|
||||
<Translate id="homepage.title" />
|
||||
|
|
@ -314,7 +332,7 @@ You can even omit a children prop and specify a translation string in your `code
|
|||
|
||||
### `useDocusaurusContext` {#useDocusaurusContext}
|
||||
|
||||
React hook to access Docusaurus Context. Context contains `siteConfig` object from [docusaurus.config.js](api/docusaurus.config.js.md), and some additional site metadata.
|
||||
React hook to access Docusaurus Context. The context contains the `siteConfig` object from [docusaurus.config.js](api/docusaurus.config.js.md) and some additional site metadata.
|
||||
|
||||
```ts
|
||||
type DocusaurusPluginVersionInformation =
|
||||
|
|
@ -352,22 +370,31 @@ interface DocusaurusContext {
|
|||
|
||||
Usage example:
|
||||
|
||||
```jsx {5,8-10}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
const MyComponent = () => {
|
||||
// highlight-next-line
|
||||
const {siteConfig, siteMetadata} = useDocusaurusContext();
|
||||
return (
|
||||
<div>
|
||||
{/* highlight-start */}
|
||||
<h1>{siteConfig.title}</h1>
|
||||
<div>{siteMetadata.siteVersion}</div>
|
||||
<div>{siteMetadata.docusaurusVersion}</div>
|
||||
{/* highlight-end */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
The `siteConfig` object only contains **serializable values** (values that are preserved after `JSON.stringify()`). Functions, regexes, etc. would be lost on the client side.
|
||||
|
||||
:::
|
||||
|
||||
### `useIsBrowser` {#useIsBrowser}
|
||||
|
||||
Returns `true` when the React app has successfully hydrated in the browser.
|
||||
|
|
@ -376,9 +403,7 @@ Returns `true` when the React app has successfully hydrated in the browser.
|
|||
|
||||
Use this hook instead of `typeof windows !== 'undefined'` in React rendering logic.
|
||||
|
||||
The first client-side render output (in the browser) **must be exactly the same** as the server-side render output (Node.js).
|
||||
|
||||
Not following this rule can lead to unexpected hydration behaviors, as described in [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/).
|
||||
The first client-side render output (in the browser) **must be exactly the same** as the server-side render output (Node.js). Not following this rule can lead to unexpected hydration behaviors, as described in [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/).
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -450,7 +475,7 @@ Prefer a `require()` call for [assets](./guides/markdown-features/markdown-featu
|
|||
|
||||
Sometimes `useBaseUrl` is not good enough. This hook return additional utils related to your site's base url.
|
||||
|
||||
- `withBaseUrl`: useful if you need to add base urls to multiple urls at once.
|
||||
- `withBaseUrl`: useful if you need to add base URLs to multiple URLs at once.
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
|
@ -470,11 +495,11 @@ const Component = () => {
|
|||
|
||||
React hook to access Docusaurus global data created by all the plugins.
|
||||
|
||||
Global data is namespaced by plugin name, and plugin id.
|
||||
Global data is namespaced by plugin name then by plugin ID.
|
||||
|
||||
:::info
|
||||
|
||||
Plugin id is only useful when a plugin is used multiple times on the same site. Each plugin instance is able to create its own global data.
|
||||
Plugin ID is only useful when a plugin is used multiple times on the same site. Each plugin instance is able to create its own global data.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -490,14 +515,17 @@ type GlobalData = Record<
|
|||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5-7}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import useGlobalData from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
// highlight-start
|
||||
const globalData = useGlobalData();
|
||||
const myPluginData = globalData['my-plugin']['default'];
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -511,23 +539,26 @@ Inspect your site's global data at `./docusaurus/globalData.json`
|
|||
|
||||
Access global data created by a specific plugin instance.
|
||||
|
||||
This is the most convenient hook to access plugin global data, and should be used most of the time.
|
||||
This is the most convenient hook to access plugin global data and should be used most of the time.
|
||||
|
||||
`pluginId` is optional if you don't use multi-instance plugins.
|
||||
|
||||
```ts
|
||||
usePluginData(pluginName: string, pluginId?: string)
|
||||
function usePluginData(pluginName: string, pluginId?: string);
|
||||
```
|
||||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5-6}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import {usePluginData} from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
// highlight-start
|
||||
const myPluginData = usePluginData('my-plugin');
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -541,14 +572,17 @@ useAllPluginInstancesData(pluginName: string)
|
|||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5-7}
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// highlight-next-line
|
||||
import {useAllPluginInstancesData} from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
// highlight-start
|
||||
const allPluginInstancesData = useAllPluginInstancesData('my-plugin');
|
||||
const myPluginData = allPluginInstancesData['default'];
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -573,10 +607,9 @@ function interpolate(
|
|||
|
||||
#### Example {#example-1}
|
||||
|
||||
```jsx
|
||||
// highlight-start
|
||||
```js
|
||||
// highlight-next-line
|
||||
import {interpolate} from '@docusaurus/Interpolate';
|
||||
// highlight-end
|
||||
|
||||
const message = interpolate('Welcome {firstName}', {firstName: 'Sébastien'});
|
||||
```
|
||||
|
|
@ -610,17 +643,14 @@ function translate(
|
|||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
// highlight-start
|
||||
// highlight-next-line
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
// highlight-end
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout
|
||||
// highlight-start
|
||||
title={translate({message: 'My page meta title'})}
|
||||
// highlight-end
|
||||
>
|
||||
// highlight-next-line
|
||||
title={translate({message: 'My page meta title'})}>
|
||||
<img
|
||||
src={'https://docusaurus.io/logo.png'}
|
||||
aria-label={
|
||||
|
|
@ -646,7 +676,7 @@ export default function Home() {
|
|||
|
||||
### `ExecutionEnvironment` {#executionenvironment}
|
||||
|
||||
A module which exposes a few boolean variables to check the current rendering environment.
|
||||
A module that exposes a few boolean variables to check the current rendering environment.
|
||||
|
||||
:::caution
|
||||
|
||||
|
|
@ -656,7 +686,7 @@ For React rendering logic, use [`useIsBrowser()`](#useIsBrowser) or [`<BrowserOn
|
|||
|
||||
Example:
|
||||
|
||||
```jsx
|
||||
```js
|
||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
|
|
@ -675,7 +705,7 @@ if (ExecutionEnvironment.canUseDOM) {
|
|||
|
||||
A module exposing useful constants to client-side theme code.
|
||||
|
||||
```jsx
|
||||
```js
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/constants';
|
||||
```
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ sidebar_label: Pages
|
|||
|
||||
In this section, we will learn about creating pages in Docusaurus.
|
||||
|
||||
This is useful for creating **one-off standalone pages** like a showcase page, playground page or support page.
|
||||
This is useful for creating **one-off standalone pages** like a showcase page, playground page, or support page.
|
||||
|
||||
The functionality of pages is powered by `@docusaurus/plugin-content-pages`.
|
||||
|
||||
|
|
@ -27,6 +27,8 @@ Check the [Pages Plugin API Reference documentation](./../api/plugins/plugin-con
|
|||
|
||||
## Add a React page {#add-a-react-page}
|
||||
|
||||
React is used as the UI library to create pages. Every page component should export a React component, and you can leverage the expressiveness of React to build rich and interactive content.
|
||||
|
||||
Create a file `/src/pages/helloReact.js`:
|
||||
|
||||
```jsx title="/src/pages/helloReact.js"
|
||||
|
|
@ -55,7 +57,7 @@ function Hello() {
|
|||
export default Hello;
|
||||
```
|
||||
|
||||
Once you save the file, the development server will automatically reload the changes. Now open `http://localhost:3000/helloReact`, you will see the new page you just created.
|
||||
Once you save the file, the development server will automatically reload the changes. Now open `http://localhost:3000/helloReact` and you will see the new page you just created.
|
||||
|
||||
Each page doesn't come with any styling. You will need to import the `Layout` component from `@theme/Layout` and wrap your contents within that component if you want the navbar and/or footer to appear.
|
||||
|
||||
|
|
@ -83,7 +85,7 @@ How are you?
|
|||
|
||||
In the same way, a page will be created at `http://localhost:3000/helloMarkdown`.
|
||||
|
||||
Markdown pages are less flexible than React pages, because it always uses the theme layout.
|
||||
Markdown pages are less flexible than React pages because it always uses the theme layout.
|
||||
|
||||
Here's an [example Markdown page](/examples/markdownPageExample).
|
||||
|
||||
|
|
@ -102,20 +104,31 @@ If you are familiar with other static site generators like Jekyll and Next, this
|
|||
- `/src/pages/foo/test.js` → `[baseUrl]/foo/test`
|
||||
- `/src/pages/foo/index.js` → `[baseUrl]/foo/`
|
||||
|
||||
In this component-based development era, it is encouraged to co-locate your styling, markup and behavior together into components. Each page is a component, and if you need to customize your page design with your own styles, we recommend co-locating your styles with the page component in its own directory. For example, to create a "Support" page, you could do one of the following:
|
||||
In this component-based development era, it is encouraged to co-locate your styling, markup, and behavior together into components. Each page is a component, and if you need to customize your page design with your own styles, we recommend co-locating your styles with the page component in its own directory. For example, to create a "Support" page, you could do one of the following:
|
||||
|
||||
- Add a `/src/pages/support.js` file
|
||||
- Create a `/src/pages/support/` directory and a `/src/pages/support/index.js` file.
|
||||
|
||||
The latter is preferred as it has the benefits of letting you put files related to the page within that directory. For example, a CSS module file (`styles.module.css`) with styles meant to only be used on the "Support" page. **Note:** this is merely a recommended directory structure and you will still need to manually import the CSS module file within your component module (`support/index.js`). By default, any Markdown or Javascript file starting with `_` will be ignored, and no routes will be created for that file (see the `exclude` option).
|
||||
The latter is preferred as it has the benefits of letting you put files related to the page within that directory. For example, a CSS module file (`styles.module.css`) with styles meant to only be used on the "Support" page.
|
||||
|
||||
```sh
|
||||
:::note
|
||||
|
||||
This is merely a recommended directory structure, and you will still need to manually import the CSS module file within your component module (`support/index.js`).
|
||||
|
||||
:::
|
||||
|
||||
By default, any Markdown or Javascript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option).
|
||||
|
||||
```bash
|
||||
my-website
|
||||
├── src
|
||||
│ └── pages
|
||||
│ ├── styles.module.css
|
||||
│ ├── index.js
|
||||
| ├──_ignored.js
|
||||
│ ├── _ignored.js
|
||||
│ ├── _ignored-folder
|
||||
│ │ ├── Component1.js
|
||||
│ │ └── Component2.js
|
||||
│ └── support
|
||||
│ ├── index.js
|
||||
│ └── styles.module.css
|
||||
|
|
@ -124,14 +137,10 @@ my-website
|
|||
|
||||
:::caution
|
||||
|
||||
All JavaScript/TypeScript files within the `src/pages/` directory will have corresponding website paths generated for them. If you want to create reusable components into that directory, use the `exclude` option (by default, files prefixed with `_`, test files(`.test.js`) and files in `__tests__` directory are not turned into pages).
|
||||
All JavaScript/TypeScript files within the `src/pages/` directory will have corresponding website paths generated for them. If you want to create reusable components into that directory, use the `exclude` option (by default, files prefixed with `_`, test files(`.test.js`), and files in `__tests__` directory are not turned into pages).
|
||||
|
||||
:::
|
||||
|
||||
## Using React {#using-react}
|
||||
|
||||
React is used as the UI library to create pages. Every page component should export a React component, and you can leverage on the expressiveness of React to build rich and interactive content.
|
||||
|
||||
## Duplicate Routes {#duplicate-routes}
|
||||
### Duplicate Routes {#duplicate-routes}
|
||||
|
||||
You may accidentally create multiple pages that are meant to be accessed on the same route. When this happens, Docusaurus will warn you about duplicate routes when you run `yarn start` or `yarn build`, but the site will still be built successfully. The page that was created last will be accessible, but it will override other conflicting pages. To resolve this issue, you should modify or remove any conflicting routes.
|
||||
|
|
@ -10,16 +10,16 @@ Create a Markdown file, `greeting.md`, and place it under the `docs` directory.
|
|||
```bash
|
||||
website # root directory of your site
|
||||
├── docs
|
||||
│ └── greeting.md
|
||||
│ └── greeting.md
|
||||
├── src
|
||||
│ └── pages
|
||||
│ └── pages
|
||||
├── docusaurus.config.js
|
||||
├── ...
|
||||
```
|
||||
|
||||
At the top of the file, specify `id` and `title` in the front matter, so that Docusaurus will pick them up correctly when generating your site.
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
id: greeting
|
||||
title: Hello
|
||||
|
|
@ -35,7 +35,7 @@ will show up on the table of contents on the upper right
|
|||
|
||||
So that your users will know what this page is all about without scrolling down or even without reading too much.
|
||||
|
||||
### Only h2 and h3 will be in the toc by default.
|
||||
### Only h2 and h3 will be in the TOC by default.
|
||||
|
||||
You can configure the TOC heading levels either per-document or in the theme configuration.
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ This will render in the browser as follows:
|
|||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
<BrowserWindow>
|
||||
|
||||
<h2>Hello from Docusaurus</h2>
|
||||
|
||||
|
|
@ -69,9 +69,9 @@ will show up on the table of contents on the upper right
|
|||
|
||||
So that your users will know what this page is all about without scrolling down or even without reading too much.
|
||||
|
||||
<h3>Only h2 and h3 will be in the toc by default.</h3>
|
||||
<h3>Only h2 and h3 will be in the TOC by default.</h3>
|
||||
|
||||
You can configure the TOC heading levels either per-document or in the theme configuration.
|
||||
You can configure the TOC heading levels either per document or in the theme configuration.
|
||||
|
||||
The headers are well-spaced so that the hierarchy is clear.
|
||||
|
||||
|
|
@ -98,9 +98,9 @@ Read more about [importing partial pages](../markdown-features/markdown-features
|
|||
|
||||
## Doc tags {#doc-tags}
|
||||
|
||||
Optionally, you can add tags to your doc pages, which introduces another dimension of categorization in addition to the [docs sidebar](./sidebar.md). Tags are passed in the front matter as a list of labels:
|
||||
Optionally, you can add tags to your doc pages, which introduces another dimension of categorization in addition to the [docs sidebar](./sidebar/index.md). Tags are passed in the front matter as a list of labels:
|
||||
|
||||
```yml "your-doc-page.md"
|
||||
```md "your-doc-page.md"
|
||||
---
|
||||
id: doc-with-tags
|
||||
title: A doc with tags
|
||||
|
|
@ -27,22 +27,24 @@ website # Root directory of your site
|
|||
└── hello.md
|
||||
```
|
||||
|
||||
However, the **last part** of the `id` can be defined by user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
|
||||
However, the **last part** of the `id` can be defined by the user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
id: part1
|
||||
---
|
||||
|
||||
Lorem ipsum
|
||||
```
|
||||
|
||||
If you want more control over the last part of the document URL, it is possible to add a `slug` (defaults to the `id`).
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
id: part1
|
||||
slug: part1.html
|
||||
---
|
||||
|
||||
Lorem ipsum
|
||||
```
|
||||
|
||||
|
|
@ -57,13 +59,14 @@ It is possible to use:
|
|||
|
||||
## Home page docs {#home-page-docs}
|
||||
|
||||
If you want a document to be available at the root, and have a path like `https://docusaurus.io/docs/`, you can use the slug frontmatter:
|
||||
If you want a document to be available at the root, and have a path like `https://docusaurus.io/docs/`, you can use the slug front matter:
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
id: my-home-doc
|
||||
slug: /
|
||||
---
|
||||
|
||||
Lorem ipsum
|
||||
```
|
||||
|
||||
|
|
@ -83,7 +86,7 @@ example.com/blog/2021/08/01/mdx-blog-post -> generated from `blog/2021-08-01-m
|
|||
...
|
||||
```
|
||||
|
||||
All docs will be served under the subroute `docs/`. But what if **your site only has docs**, or you want to prioritize your docs by putting it at the root?
|
||||
All docs will be served under the subroute `docs/`. But what if **your site only has docs**, or you want to prioritize your docs by putting them at the root?
|
||||
|
||||
Assume that you have the following in your configuration:
|
||||
|
||||
|
|
@ -126,15 +129,16 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
Note that you **don't necessarily have to give up on using blog** or other plugins; all that `routeBasePath: '/'` does is that instead of serving the docs through `https://example.com/docs/some-doc`, they are now at the site root: `https://example.com/some-doc`. The blog, if enabled, can still be accessed through the `blog/` subroute.
|
||||
Note that you **don't necessarily have to give up on using the blog** or other plugins; all that `routeBasePath: '/'` does is that instead of serving the docs through `https://example.com/docs/some-doc`, they are now at the site root: `https://example.com/some-doc`. The blog, if enabled, can still be accessed through the `blog/` subroute.
|
||||
|
||||
Don't forget to put some page at the root (`https://example.com/`) through adding the front matter:
|
||||
|
||||
```yml title="docs/intro.md"
|
||||
```md title="docs/intro.md"
|
||||
---
|
||||
# highlight-next-line
|
||||
slug: /
|
||||
---
|
||||
|
||||
This page will be the home page when users visit https://example.com/.
|
||||
```
|
||||
|
||||
|
|
@ -5,11 +5,11 @@ description: Docusaurus Markdown features that are specific to the docs plugin
|
|||
slug: /docs-markdown-features
|
||||
---
|
||||
|
||||
Docs can use any [Markdown feature](../markdown-features/markdown-features-intro.mdx), and have a few additional docs-specific Markdown features.
|
||||
Docs can use any [Markdown feature](../markdown-features/markdown-features-intro.mdx) and have a few additional docs-specific Markdown features.
|
||||
|
||||
## Markdown frontmatter {#markdown-frontmatter}
|
||||
## Markdown front matter {#markdown-front-matter}
|
||||
|
||||
Markdown docs have their own [Markdown frontmatter](../../api/plugins/plugin-content-docs.md#markdown-frontmatter)
|
||||
Markdown docs have their own [Markdown front matter API](../../api/plugins/plugin-content-docs.md#markdown-front-matter).
|
||||
|
||||
## Referencing other documents {#referencing-other-documents}
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ Reference to another [document in a subfolder](subfolder/doc3.md).
|
|||
|
||||
:::tip
|
||||
|
||||
It is better to use relative file paths links instead of relative links:
|
||||
Using relative _file_ paths (with `.md` extensions) instead of relative _URL_ links provides the following benefits:
|
||||
|
||||
- links will keep working on the GitHub interface
|
||||
- you can customize the document slugs without having to update all the links
|
||||
|
|
@ -9,7 +9,7 @@ The `@docusaurus/plugin-content-docs` plugin can support [multi-instance](../../
|
|||
|
||||
:::note
|
||||
|
||||
This feature is only useful for [versioned documentations](./versioning.md). It is recommended to be familiar with docs versioning before reading this page.
|
||||
This feature is only useful for [versioned documentation](./versioning.md). It is recommended to be familiar with docs versioning before reading this page. If you just want [multiple sidebars](./sidebar/multiple-sidebars.md), you can do so within one plugin.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ If you build a cross-platform mobile SDK, you may have 2 documentations:
|
|||
- Android SDK documentation (`v1.0`, `v1.1`)
|
||||
- iOS SDK documentation (`v1.0`, `v2.0`)
|
||||
|
||||
In such case, you can use a distinct docs plugin instance per mobile SDK documentation.
|
||||
In this case, you can use a distinct docs plugin instance per mobile SDK documentation.
|
||||
|
||||
:::caution
|
||||
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
---
|
||||
slug: /sidebar/autogenerated
|
||||
---
|
||||
|
||||
# Autogenerated
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
Docusaurus can **create a sidebar automatically** from your **filesystem structure**: each folder creates a sidebar category, and each file creates a doc link.
|
||||
|
||||
```ts
|
||||
type SidebarItemAutogenerated = {
|
||||
type: 'autogenerated';
|
||||
dirName: string; // Source folder to generate the sidebar slice from (relative to docs)
|
||||
};
|
||||
```
|
||||
|
||||
Docusaurus can generate a full sidebar from your docs folder:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
myAutogeneratedSidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: '.', // '.' means the current docs folder
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
An `autogenerated` item is converted by Docusaurus to a **sidebar slice** (also discussed in [category shorthands](items.md#category-shorthand)): a list of items of type `doc` or `category`, so you can splice **multiple `autogenerated` items** from multiple directories, interleaving them with regular sidebar items, in one sidebar level.
|
||||
|
||||
<details>
|
||||
<summary>A real-world example</summary>
|
||||
Consider this file structure:
|
||||
|
||||
```bash
|
||||
docs
|
||||
├── api
|
||||
│ ├── product1-api
|
||||
│ │ └── api.md
|
||||
│ └── product2-api
|
||||
│ ├── basic-api.md
|
||||
│ └── pro-api.md
|
||||
├── intro.md
|
||||
└── tutorials
|
||||
├── advanced
|
||||
│ ├── advanced1.md
|
||||
│ ├── advanced2.md
|
||||
│ └── read-more
|
||||
│ ├── resource1.md
|
||||
│ └── resource2.md
|
||||
├── easy
|
||||
│ ├── easy1.md
|
||||
│ └── easy2.md
|
||||
├── tutorial-end.md
|
||||
├── tutorial-intro.md
|
||||
└── tutorial-medium.md
|
||||
```
|
||||
|
||||
And assume every doc's ID is just its file name. If you define an autogenerated sidebar like this:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
'intro',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorials',
|
||||
items: [
|
||||
'tutorial-intro',
|
||||
// highlight-start
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'tutorials/easy', // Generate sidebar slice from docs/tutorials/easy
|
||||
},
|
||||
// highlight-end
|
||||
'tutorial-medium',
|
||||
// highlight-start
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'tutorials/advanced', // Generate sidebar slice from docs/tutorials/hard
|
||||
},
|
||||
// highlight-end
|
||||
'tutorial-end',
|
||||
],
|
||||
},
|
||||
// highlight-start
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'api', // Generate sidebar slice from docs/api
|
||||
},
|
||||
// highlight-end
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Community',
|
||||
items: ['team', 'chat'],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
It would be resolved as:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
'intro',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorials',
|
||||
items: [
|
||||
'tutorial-intro',
|
||||
// highlight-start
|
||||
// Two files in docs/tutorials/easy
|
||||
'easy1',
|
||||
'easy2',
|
||||
// highlight-end
|
||||
'tutorial-medium',
|
||||
// highlight-start
|
||||
// Two files and a folder in docs/tutorials/hard
|
||||
'advanced1',
|
||||
'advanced2',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'read-more',
|
||||
items: ['resource1', 'resource2'],
|
||||
},
|
||||
// highlight-end
|
||||
'tutorial-end',
|
||||
],
|
||||
},
|
||||
// highlight-start
|
||||
// Two folders in docs/api
|
||||
{
|
||||
type: 'category',
|
||||
label: 'product1-api',
|
||||
items: ['api'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'product2-api',
|
||||
items: ['basic-api', 'pro-api'],
|
||||
},
|
||||
// highlight-end
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Community',
|
||||
items: ['team', 'chat'],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Note how the autogenerate source directories themselves don't become categories: only the items they contain do. This is what we mean by "sidebar slice".
|
||||
|
||||
</details>
|
||||
|
||||
## Category index convention {#category-index-convention}
|
||||
|
||||
Docusaurus can automatically link a category to its index document.
|
||||
|
||||
A category index document is a document following one of those filename conventions:
|
||||
|
||||
- Named as `index` (case-insensitive): `docs/Guides/index.md`
|
||||
- Named as `README` (case-insensitive): `docs/Guides/README.mdx`
|
||||
- Same name as parent folder: `docs/Guides/Guides.md`
|
||||
|
||||
This is equivalent to using a category with a [doc link](items.md#category-doc-link):
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
link: {type: 'doc', id: 'Guides/index'},
|
||||
items: [],
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Naming your introductory document `README.md` makes it show up when browsing the folder using the GitHub interface, while using `index.md` makes the behavior more in line with how HTML files are served.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
If a folder only has one index page, it will be turned into a link instead of a category. This is useful for **asset collocation**:
|
||||
|
||||
```
|
||||
some-doc
|
||||
├── index.md
|
||||
├── img1.png
|
||||
└── img2.png
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Customizing category index matching</summary>
|
||||
|
||||
It is possible to opt out any of the category index conventions, or define even more conventions. You can inject your own `isCategoryIndex` matcher through the [`sidebarItemsGenerator`](#customize-the-sidebar-items-generator) callback. For example, you can also pick `intro` as another file name eligible for automatically becoming the category index.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
{
|
||||
async sidebarItemsGenerator({
|
||||
...args,
|
||||
isCategoryIndex: defaultCategoryIndexMatcher, // The default matcher implementation, given below
|
||||
defaultSidebarItemsGenerator,
|
||||
}) {
|
||||
return defaultSidebarItemsGenerator({
|
||||
...args,
|
||||
// highlight-start
|
||||
isCategoryIndex(doc) {
|
||||
return (
|
||||
// Also pick intro.md in addition to the default ones
|
||||
doc.fileName.toLowerCase() === 'intro' ||
|
||||
defaultCategoryIndexMatcher(doc)
|
||||
);
|
||||
},
|
||||
// highlight-end
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Or choose to not have any category index convention.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
{
|
||||
async sidebarItemsGenerator({
|
||||
...args,
|
||||
isCategoryIndex: defaultCategoryIndexMatcher, // The default matcher implementation, given below
|
||||
defaultSidebarItemsGenerator,
|
||||
}) {
|
||||
return defaultSidebarItemsGenerator({
|
||||
...args,
|
||||
// highlight-start
|
||||
isCategoryIndex() {
|
||||
// No doc will be automatically picked as category index
|
||||
return false;
|
||||
},
|
||||
// highlight-end
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The `isCategoryIndex` matcher will be provided with three fields:
|
||||
|
||||
- `fileName`, the file's name without extension and with casing preserved
|
||||
- `directories`, the list of directory names _from the lowest level to the highest level_, relative to the docs root directory
|
||||
- `extension`, the file's extension, with a leading dot.
|
||||
|
||||
For example, for a doc file at `guides/sidebar/autogenerated.md`, the props the matcher receives are
|
||||
|
||||
```js
|
||||
const props = {
|
||||
fileName: 'autogenerated',
|
||||
directories: ['sidebar', 'guides'],
|
||||
extension: '.md',
|
||||
};
|
||||
```
|
||||
|
||||
The default implementation is:
|
||||
|
||||
```js
|
||||
function isCategoryIndex({fileName, directories}) {
|
||||
const eligibleDocIndexNames = [
|
||||
'index',
|
||||
'readme',
|
||||
directories[0].toLowerCase(),
|
||||
];
|
||||
return eligibleDocIndexNames.includes(fileName.toLowerCase());
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Autogenerated sidebar metadata {#autogenerated-sidebar-metadata}
|
||||
|
||||
For handwritten sidebar definitions, you would provide metadata to sidebar items through `sidebars.js`; for autogenerated, Docusaurus would read them from the item's respective file. In addition, you may want to adjust the relative position of each item because, by default, items within a sidebar slice will be generated in **alphabetical order** (using file and folder names).
|
||||
|
||||
**For docs**: use additional front matter. The `label`, `className`, and `customProps` attributes are declared in front matter as `sidebar_label`, `sidebar_class_name`, and `sidebar_custom_props`, respectively. Position can be specified in the same way, via `sidebar_position` front matter.
|
||||
|
||||
```md title="docs/tutorials/tutorial-easy.md"
|
||||
---
|
||||
# highlight-start
|
||||
sidebar_position: 2
|
||||
sidebar_label: Easy
|
||||
sidebar_class_name: green
|
||||
# highlight-end
|
||||
---
|
||||
|
||||
# Easy Tutorial
|
||||
|
||||
This is the easy tutorial!
|
||||
```
|
||||
|
||||
**For categories**: add a `_category_.json` or `_category_.yml` file in the respective folder. You can specify any category metadata and also the `position` metadata.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="JSON">
|
||||
|
||||
```json title="docs/tutorials/_category_.json"
|
||||
{
|
||||
"position": 2.5,
|
||||
"label": "Tutorial",
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"className": "red",
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"title": "Tutorial overview"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="YAML">
|
||||
|
||||
```yml title="docs/tutorials/_category_.yml"
|
||||
position: 2.5 # float position is supported
|
||||
label: 'Tutorial'
|
||||
collapsible: true # make the category collapsible
|
||||
collapsed: false # keep the category open by default
|
||||
className: red
|
||||
link:
|
||||
type: generated-index
|
||||
title: Tutorial overview
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info
|
||||
|
||||
If the `link` is explicitly specified, Docusaurus will not apply any [default conventions](items.md#category-index-convention).
|
||||
|
||||
The doc links can be specified relatively, e.g. if the category is generated with the `guides` directory, `"link": {"type": "doc", "id": "intro"}` will be resolved to the ID `guides/intro`, only falling back to `intro` if a doc with the former ID doesn't exist.
|
||||
|
||||
You can also use `link: null` to opt out of default conventions and not generate any category index page.
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
The position metadata is only used **within a sidebar slice**: Docusaurus does not re-order other items of your sidebar.
|
||||
|
||||
:::
|
||||
|
||||
## Using number prefixes {#using-number-prefixes}
|
||||
|
||||
A simple way to order an autogenerated sidebar is to prefix docs and folders by number prefixes, which also makes them appear in the file system in the same order when sorted by file name:
|
||||
|
||||
```bash
|
||||
docs
|
||||
├── 01-Intro.md
|
||||
├── 02-Tutorial Easy
|
||||
│ ├── 01-First Part.md
|
||||
│ ├── 02-Second Part.md
|
||||
│ └── 03-End.md
|
||||
├── 03-Tutorial Hard
|
||||
│ ├── 01-First Part.md
|
||||
│ ├── 02-Second Part.md
|
||||
│ ├── 03-Third Part.md
|
||||
│ └── 04-End.md
|
||||
└── 04-End.md
|
||||
```
|
||||
|
||||
To make it **easier to adopt**, Docusaurus supports **multiple number prefix patterns**.
|
||||
|
||||
By default, Docusaurus will **remove the number prefix** from the doc id, title, label, and URL paths.
|
||||
|
||||
:::caution
|
||||
|
||||
**Prefer using [additional metadata](#autogenerated-sidebar-metadata)**.
|
||||
|
||||
Updating a number prefix can be annoying, as it can require **updating multiple existing markdown links**:
|
||||
|
||||
```diff title="docs/02-Tutorial Easy/01-First Part.md"
|
||||
- Check the [Tutorial End](../04-End.md);
|
||||
+ Check the [Tutorial End](../05-End.md);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Customize the sidebar items generator {#customize-the-sidebar-items-generator}
|
||||
|
||||
You can provide a custom `sidebarItemsGenerator` function in the docs plugin (or preset) config:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
{
|
||||
// highlight-start
|
||||
async sidebarItemsGenerator({
|
||||
defaultSidebarItemsGenerator,
|
||||
numberPrefixParser,
|
||||
item,
|
||||
version,
|
||||
docs,
|
||||
categoriesMetadata,
|
||||
isCategoryIndex,
|
||||
}) {
|
||||
// Example: return an hardcoded list of static sidebar items
|
||||
return [
|
||||
{type: 'doc', id: 'doc1'},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
];
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
**Re-use and enhance the default generator** instead of writing a generator from scratch: [the default generator we provide](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts) is 250 lines long.
|
||||
|
||||
**Add, update, filter, re-order** the sidebar items according to your use case:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-start
|
||||
// Reverse the sidebar items ordering (including nested category items)
|
||||
function reverseSidebarItems(items) {
|
||||
// Reverse items in categories
|
||||
const result = items.map((item) => {
|
||||
if (item.type === 'category') {
|
||||
return {...item, items: reverseSidebarItems(item.items)};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
// Reverse items at current level
|
||||
result.reverse();
|
||||
return result;
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-content-docs',
|
||||
{
|
||||
// highlight-start
|
||||
async sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) {
|
||||
const sidebarItems = await defaultSidebarItemsGenerator(args);
|
||||
return reverseSidebarItems(sidebarItems);
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
slug: /sidebar
|
||||
---
|
||||
|
||||
# Sidebar
|
||||
|
||||
Creating a sidebar is useful to:
|
||||
|
||||
- Group multiple **related documents**
|
||||
- **Display a sidebar** on each of those documents
|
||||
- Provide **paginated navigation**, with next/previous button
|
||||
|
||||
To use sidebars on your Docusaurus site:
|
||||
|
||||
1. Define a file that exports a dictionary of [sidebar objects](#sidebar-object).
|
||||
2. Pass this object into the `@docusaurus/plugin-docs` plugin directly or via `@docusaurus/preset-classic`.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
This section serves as an overview of miscellaneous features of the doc sidebar. In the following sections, we will more systematically introduce the following concepts:
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
|
||||
## Default sidebar {#default-sidebar}
|
||||
|
||||
If the `sidebarPath` is unspecified, Docusaurus [automatically generates a sidebar](autogenerated.md) for you, by using the filesystem structure of the `docs` folder:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: '.', // generate sidebar from the docs folder (or versioned_docs/<version>)
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
You can also define your sidebars explicitly.
|
||||
|
||||
## Sidebar object {#sidebar-object}
|
||||
|
||||
A sidebar at its crux is a hierarchy of categories, doc links, and other hyperlinks.
|
||||
|
||||
```ts
|
||||
type Sidebar =
|
||||
// Normal syntax
|
||||
| SidebarItem[]
|
||||
// Shorthand syntax
|
||||
| {[categoryLabel: string]: SidebarItem[]};
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Getting Started',
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docusaurus',
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc2',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc3',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Learn more',
|
||||
href: 'https://example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
This is a sidebars file that exports one sidebar, called `mySidebar`. It has three top-level items: two categories and one external link. Within each category, there are a few doc links.
|
||||
|
||||
A sidebars file can contain [**multiple sidebar objects**](multiple-sidebars.md), identified by their object keys.
|
||||
|
||||
```ts
|
||||
type SidebarsFile = {
|
||||
[sidebarID: string]: Sidebar;
|
||||
};
|
||||
```
|
||||
|
||||
## Theme configuration {#theme-configuration}
|
||||
|
||||
### Hideable sidebar {#hideable-sidebar}
|
||||
|
||||
By enabling the `themeConfig.hideableSidebar` option, you can make the entire sidebar hideable, allowing users to better focus on the content. This is especially useful when content is consumed on medium-sized screens (e.g. tablets).
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
// highlight-start
|
||||
hideableSidebar: true,
|
||||
// highlight-end
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Auto-collapse sidebar categories {#auto-collapse-sidebar-categories}
|
||||
|
||||
The `themeConfig.autoCollapseSidebarCategories` option would collapse all sibling categories when expanding one category. This saves the user from having too many categories open and helps them focus on the selected section.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
// highlight-next-line
|
||||
autoCollapseSidebarCategories: true,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Passing custom props {#passing-custom-props}
|
||||
|
||||
To pass in custom props to a swizzled sidebar item, add the optional `customProps` object to any of the items:
|
||||
|
||||
```js
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc1',
|
||||
customProps: {
|
||||
/* props */
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Sidebar Breadcrumbs {#sidebar-breadcrumbs}
|
||||
|
||||
By default, breadcrumbs are rendered at the top, using the "sidebar path" of the current page.
|
||||
|
||||
This behavior can be disabled with plugin options:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
breadcrumbs: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Complex sidebars example {#complex-sidebars-example}
|
||||
|
||||
A real-world example from the Docusaurus site:
|
||||
|
||||
```mdx-code-block
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
<CodeBlock className="language-js" title="sidebars.js">
|
||||
{require('!!raw-loader!@site/sidebars.js')
|
||||
.default
|
||||
.split('\n')
|
||||
// remove comments
|
||||
.map((line) => !['//','/*','*'].some(commentPattern => line.trim().startsWith(commentPattern)) && line)
|
||||
.filter(Boolean)
|
||||
.join('\n')}
|
||||
</CodeBlock>
|
||||
```
|
||||
|
|
@ -0,0 +1,591 @@
|
|||
---
|
||||
toc_max_heading_level: 4
|
||||
slug: /sidebar/items
|
||||
---
|
||||
|
||||
# Sidebar items
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
We have introduced three types of item types in the example in the previous section: `doc`, `category`, and `link`, whose usages are fairly intuitive. We will formally introduce their APIs. There's also a fourth type: `autogenerated`, which we will explain in detail later.
|
||||
|
||||
- **[Doc](#sidebar-item-doc)**: link to a doc page, associating it with the sidebar
|
||||
- **[Link](#sidebar-item-link)**: link to any internal or external page
|
||||
- **[Category](#sidebar-item-category)**: creates a dropdown of sidebar items
|
||||
- **[Autogenerated](autogenerated.md)**: generate a sidebar slice automatically
|
||||
- **[HTML](#sidebar-item-html)**: renders pure HTML in the item's position
|
||||
- **[\*Ref](multiple-sidebars.md#sidebar-item-ref)**: link to a doc page, without making the item take part in navigation generation
|
||||
|
||||
## Doc: link to a doc {#sidebar-item-doc}
|
||||
|
||||
Use the `doc` type to link to a doc page and assign that doc to a sidebar:
|
||||
|
||||
```ts
|
||||
type SidebarItemDoc =
|
||||
// Normal syntax
|
||||
| {
|
||||
type: 'doc';
|
||||
id: string;
|
||||
label: string; // Sidebar label text
|
||||
className?: string; // Class name for sidebar label
|
||||
customProps?: Record<string, unknown>; // Custom props
|
||||
}
|
||||
|
||||
// Shorthand syntax
|
||||
| string; // docId shortcut
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
// Normal syntax:
|
||||
// highlight-start
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc1', // document ID
|
||||
label: 'Getting started', // sidebar label
|
||||
},
|
||||
// highlight-end
|
||||
|
||||
// Shorthand syntax:
|
||||
// highlight-start
|
||||
'doc2', // document ID
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
If you use the doc shorthand or [autogenerated](#sidebar-item-autogenerated) sidebar, you would lose the ability to customize the sidebar label through item definition. You can, however, use the `sidebar_label` markdown front matter within that doc, which has higher precedence over the `label` key in the sidebar item. Similarly, you can use `sidebar_custom_props` to declare custom metadata for a doc page.
|
||||
|
||||
:::note
|
||||
|
||||
A `doc` item sets an [implicit sidebar association](#sidebar-association). Don't assign the same doc to multiple sidebars: change the type to `ref` instead.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Sidebar custom props is a useful way to propagate arbitrary doc metadata to the client side, so you can get additional information when using any doc-related hook that fetches a doc object.
|
||||
|
||||
:::
|
||||
|
||||
## Link: link to any page {#sidebar-item-link}
|
||||
|
||||
Use the `link` type to link to any page (internal or external) that is not a doc.
|
||||
|
||||
```ts
|
||||
type SidebarItemLink = {
|
||||
type: 'link';
|
||||
label: string;
|
||||
href: string;
|
||||
className?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
myLinksSidebar: [
|
||||
// highlight-start
|
||||
// External link
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Facebook', // The link label
|
||||
href: 'https://facebook.com', // The external URL
|
||||
},
|
||||
// highlight-end
|
||||
|
||||
// highlight-start
|
||||
// Internal link
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Home', // The link label
|
||||
href: '/', // The internal path
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## HTML: render custom markup {#sidebar-item-html}
|
||||
|
||||
Use the `html` type to render custom HTML within the item's `<li>` tag.
|
||||
|
||||
This can be useful for inserting custom items such as dividers, section titles, ads, and images.
|
||||
|
||||
```ts
|
||||
type SidebarItemHtml = {
|
||||
type: 'html';
|
||||
value: string;
|
||||
defaultStyle?: boolean; // Use default menu item styles
|
||||
className?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
myHtmlSidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'html',
|
||||
value: '<img src="sponsor.png" alt="Sponsor" />', // The HTML to be rendered
|
||||
defaultStyle: true, // Use the default menu item styling
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
The menu item is already wrapped in an `<li>` tag, so if your custom item is simple, such as a title, just supply a string as the value and use the `className` property to style it:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
myHtmlSidebar: [
|
||||
{
|
||||
type: 'html',
|
||||
value: 'Core concepts',
|
||||
className: 'sidebar-title',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Category: create a hierarchy {#sidebar-item-category}
|
||||
|
||||
Use the `category` type to create a hierarchy of sidebar items.
|
||||
|
||||
```ts
|
||||
type SidebarItemCategory = {
|
||||
type: 'category';
|
||||
label: string; // Sidebar label text.
|
||||
items: SidebarItem[]; // Array of sidebar items.
|
||||
className?: string;
|
||||
|
||||
// Category options:
|
||||
collapsible: boolean; // Set the category to be collapsible
|
||||
collapsed: boolean; // Set the category to be initially collapsed or open by default
|
||||
link: SidebarItemCategoryLinkDoc | SidebarItemCategoryLinkGeneratedIndex;
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
collapsible: true,
|
||||
collapsed: false,
|
||||
items: [
|
||||
'creating-pages',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docs',
|
||||
items: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Use the [**shorthand syntax**](#category-shorthand) when you don't need customizations:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: {
|
||||
Guides: [
|
||||
'creating-pages',
|
||||
{
|
||||
Docs: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Category links {#category-link}
|
||||
|
||||
With category links, clicking on a category can navigate you to another page.
|
||||
|
||||
:::tip
|
||||
|
||||
Use category links to introduce a category of documents.
|
||||
|
||||
:::
|
||||
|
||||
#### Doc link {#category-doc-link}
|
||||
|
||||
A category can link to an existing document.
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
// highlight-start
|
||||
link: {type: 'doc', id: 'introduction'},
|
||||
// highlight-end
|
||||
items: ['pages', 'docs', 'blog', 'search'],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
See it in action on the [i18n introduction page](../../../i18n/i18n-introduction.md).
|
||||
|
||||
#### Generated index page {#generated-index-page}
|
||||
|
||||
You can auto-generate an index page that displays all the direct children of this category. The `slug` allows you to customize the generated page's route, which defaults to `/category/[categoryName]`.
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
// highlight-start
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
title: 'Docusaurus Guides',
|
||||
description: 'Learn about the most important Docusaurus concepts!',
|
||||
slug: '/category/docusaurus-guides',
|
||||
keywords: ['guides'],
|
||||
image: '/img/docusaurus.png',
|
||||
},
|
||||
// highlight-end
|
||||
items: ['pages', 'docs', 'blog', 'search'],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
See it in action on the [Docusaurus Guides page](/docs/category/guides).
|
||||
|
||||
:::tip
|
||||
|
||||
Use `generated-index` links as a quick way to get an introductory document.
|
||||
|
||||
:::
|
||||
|
||||
#### Embedding generated index in doc page {#embedding-generated-index-in-doc-page}
|
||||
|
||||
You can embed the generated cards list in a normal doc page as well, as long as the doc is used as a category index page. To do so, you need to use the `DocCardList` component, paired with the `useCurrentSidebarCategory` hook.
|
||||
|
||||
```jsx title="a-category-index-page.md"
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
In this section, we will introduce the following concepts:
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
|
||||
See this in action on the [sidebar guides page](index.md).
|
||||
|
||||
### Collapsible categories {#collapsible-categories}
|
||||
|
||||
We support the option to expand/collapse categories. Categories are collapsible by default, but you can disable collapsing with `collapsible: false`.
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
items: [
|
||||
'creating-pages',
|
||||
{
|
||||
type: 'category',
|
||||
// highlight-next-line
|
||||
collapsible: false,
|
||||
label: 'Docs',
|
||||
items: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
To make all categories non-collapsible by default, set the `sidebarCollapsible` option in `plugin-content-docs` to `false`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
sidebarCollapsible: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
The option in `sidebars.js` takes precedence over plugin configuration, so it is possible to make certain categories collapsible when `sidebarCollapsible` is set to `false` globally.
|
||||
|
||||
:::
|
||||
|
||||
### Expanded categories by default {#expanded-categories-by-default}
|
||||
|
||||
Collapsible categories are collapsed by default. If you want them to be expanded on the first render, you can set `collapsed` to `false`:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: {
|
||||
Guides: [
|
||||
'creating-pages',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docs',
|
||||
// highlight-next-line
|
||||
collapsed: false,
|
||||
items: ['markdown-features', 'sidebar', 'versioning'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Similar to `collapsible`, you can also set the global configuration `options.sidebarCollapsed` to `false`. Individual `collapsed` options in `sidebars.js` will still take precedence over this configuration.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
sidebarCollapsed: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
When a category has `collapsed: true` but `collapsible: false` (either through `sidebars.js` or through plugin configuration), the latter takes precedence and the category is still rendered as expanded.
|
||||
|
||||
:::
|
||||
|
||||
## Using shorthands {#using-shorthands}
|
||||
|
||||
You can express typical sidebar items without much customization more concisely with **shorthand syntaxes**. There are two parts to this: [**doc shorthand**](#doc-shorthand) and [**category shorthand**](#category-shorthand).
|
||||
|
||||
### Doc shorthand {#doc-shorthand}
|
||||
|
||||
An item with type `doc` can be simply a string representing its ID:
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Longhand">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'myDoc',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Shorthand">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: [
|
||||
// highlight-start
|
||||
'myDoc',
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
So it's possible to simplify the example above to:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Getting Started',
|
||||
items: [
|
||||
// highlight-next-line
|
||||
'doc1',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docusaurus',
|
||||
items: [
|
||||
// highlight-start
|
||||
'doc2',
|
||||
'doc3',
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Learn more',
|
||||
href: 'https://example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Category shorthand {#category-shorthand}
|
||||
|
||||
A category item can be represented by an object whose key is its label, and the value is an array of subitems.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Longhand">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Getting started',
|
||||
items: ['doc1', 'doc2'],
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Shorthand">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
'Getting started': ['doc1', 'doc2'],
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This permits us to simplify that example to:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
'Getting started': ['doc1'],
|
||||
},
|
||||
{
|
||||
Docusaurus: ['doc2', 'doc3'],
|
||||
},
|
||||
// highlight-end
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Learn more',
|
||||
href: 'https://example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Each shorthand object after this transformation will contain exactly one entry. Now consider the further simplified example below:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
mySidebar: [
|
||||
// highlight-start
|
||||
{
|
||||
'Getting started': ['doc1'],
|
||||
Docusaurus: ['doc2', 'doc3'],
|
||||
},
|
||||
// highlight-end
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Learn more',
|
||||
href: 'https://example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Note how the two consecutive category shorthands are compressed into one object with two entries. This syntax generates a **sidebar slice**: you shouldn't see that object as one bulk item—this object is unwrapped, with each entry becoming a separate item, and they spliced together with the rest of the items (in this case, the "Learn more" link) to form the final sidebar level. Sidebar slices are also important when discussing [autogenerated sidebars](autogenerated.md).
|
||||
|
||||
Wherever you have an array of items that is reduced to one category shorthand, you can omit that enclosing array as well.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Before">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: [
|
||||
{
|
||||
'Getting started': ['doc1'],
|
||||
Docusaurus: [
|
||||
{
|
||||
'Basic guides': ['doc2', 'doc3'],
|
||||
'Advanced guides': ['doc4', 'doc5'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="After">
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
sidebar: {
|
||||
'Getting started': ['doc1'],
|
||||
Docusaurus: {
|
||||
'Basic guides': ['doc2', 'doc3'],
|
||||
'Advanced guides': ['doc4', 'doc5'],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
---
|
||||
slug: /sidebar/multiple-sidebars
|
||||
---
|
||||
|
||||
# Using multiple sidebars
|
||||
|
||||
You can create a sidebar for each **set of Markdown files** that you want to **group together**.
|
||||
|
||||
:::tip
|
||||
|
||||
The Docusaurus site is a good example of using multiple sidebars:
|
||||
|
||||
- [Docs](../../../introduction.md)
|
||||
- [API](../../../cli.md)
|
||||
|
||||
:::
|
||||
|
||||
Consider this example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: {
|
||||
'Category A': ['doc1', 'doc2'],
|
||||
},
|
||||
apiSidebar: ['doc3', 'doc4'],
|
||||
};
|
||||
```
|
||||
|
||||
When browsing `doc1` or `doc2`, the `tutorialSidebar` will be displayed; when browsing `doc3` or `doc4`, the `apiSidebar` will be displayed.
|
||||
|
||||
## Understanding sidebar association {#sidebar-association}
|
||||
|
||||
Following the example above, if a `commonDoc` is included in both sidebars:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: {
|
||||
'Category A': ['doc1', 'doc2', 'commonDoc'],
|
||||
},
|
||||
apiSidebar: ['doc3', 'doc4', 'commonDoc'],
|
||||
};
|
||||
```
|
||||
|
||||
How does Docusaurus know which sidebar to display when browsing `commonDoc`? Answer: it doesn't, and we don't guarantee which sidebar it will pick.
|
||||
|
||||
When you add doc Y to sidebar X, it creates a two-way binding: sidebar X contains a link to doc Y, and when browsing doc Y, sidebar X will be displayed. But sometimes, we want to break either implicit binding:
|
||||
|
||||
1. _How do I generate a link to doc Y in sidebar X without making sidebar X displayed on Y?_ For example, when I include doc Y in multiple sidebars as in the example above, and I want to explicitly tell Docusaurus to display one sidebar?
|
||||
2. _How do I make sidebar X displayed when browsing doc Y, but sidebar X shouldn't contain the link to Y?_ For example, when Y is a "doc home page" and the sidebar is purely used for navigation?
|
||||
|
||||
Front matter option `displayed_sidebar` will forcibly set the sidebar association. For the same example, you can still use doc shorthands without any special configuration:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: {
|
||||
'Category A': ['doc1', 'doc2'],
|
||||
},
|
||||
apiSidebar: ['doc3', 'doc4'],
|
||||
};
|
||||
```
|
||||
|
||||
And then add a front matter:
|
||||
|
||||
```md title="commonDoc.md"
|
||||
---
|
||||
displayed_sidebar: apiSidebar
|
||||
---
|
||||
```
|
||||
|
||||
Which explicitly tells Docusaurus to display `apiSidebar` when browsing `commonDoc`. Using the same method, you can make sidebar X which doesn't contain doc Y appear on doc Y:
|
||||
|
||||
```md title="home.md"
|
||||
---
|
||||
displayed_sidebar: tutorialSidebar
|
||||
---
|
||||
```
|
||||
|
||||
Even when `tutorialSidebar` doesn't contain a link to `home`, it will still be displayed when viewing `home`.
|
||||
|
||||
If you set `displayed_sidebar: null`, no sidebar will be displayed whatsoever on this page, and subsequently, no pagination either.
|
||||
|
||||
## Generating pagination {#generating-pagination}
|
||||
|
||||
Docusaurus uses the sidebar to generate the "next" and "previous" pagination links at the bottom of each doc page. It strictly uses the sidebar that is displayed: if no sidebar is associated, it doesn't generate pagination either. However, the docs linked as "next" and "previous" are not guaranteed to display the same sidebar: they are included in this sidebar, but in their front matter, they may have a different `displayed_sidebar`.
|
||||
|
||||
If a sidebar is displayed by setting `displayed_sidebar` front matter, and this sidebar doesn't contain the doc itself, no pagination is displayed.
|
||||
|
||||
You can customize pagination with front matter `pagination_next` and `pagination_prev`. Consider this sidebar:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorial: [
|
||||
'introduction',
|
||||
{
|
||||
installation: ['windows', 'linux', 'macos'],
|
||||
},
|
||||
'getting-started',
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The pagination next link on "windows" points to "linux", but that doesn't make sense: you would want readers to proceed to "getting started" after installation. In this case, you can set the pagination manually:
|
||||
|
||||
```md title="windows.md"
|
||||
---
|
||||
# highlight-next-line
|
||||
pagination_next: getting-started
|
||||
---
|
||||
|
||||
# Installation on Windows
|
||||
```
|
||||
|
||||
You can also disable displaying a pagination link with `pagination_next: null` or `pagination_prev: null`.
|
||||
|
||||
The pagination label by default is the sidebar label. You can use the front matter `pagination_label` to customize how this doc appears in the pagination.
|
||||
|
||||
## The `ref` item {#sidebar-item-ref}
|
||||
|
||||
The `ref` type is identical to the [`doc` type](#sidebar-item-doc) in every way, except that it doesn't participate in generating navigation metadata. It only registers itself as a link. When [generating pagination](#generating-pagination) and [displaying sidebar](#sidebar-association), `ref` items are completely ignored.
|
||||
|
||||
Consider this example:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: {
|
||||
'Category A': [
|
||||
'doc1',
|
||||
'doc2',
|
||||
// highlight-next-line
|
||||
{type: 'ref', id: 'commonDoc'},
|
||||
'doc5',
|
||||
],
|
||||
},
|
||||
apiSidebar: ['doc3', 'doc4', 'commonDoc'],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
You can think of the `ref` type as the equivalent to doing the following:
|
||||
|
||||
- Setting `displayed_sidebar: tutorialSidebar` for `commonDoc` (`ref` is ignored in sidebar association)
|
||||
- Setting `pagination_next: doc5` for `doc2` and setting `pagination_prev: doc2` for `doc5` (`ref` is ignored in pagination generation)
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
---
|
||||
id: versioning
|
||||
title: Versioning
|
||||
slug: /versioning
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
You can use the version script to create a new documentation version based on the latest content in the `docs` directory. That specific set of documentation will then be preserved and accessible even as the documentation in the `docs` directory changes moving forward.
|
||||
|
||||
:::caution
|
||||
|
||||
Think about it before starting to version your documentation - it can become difficult for contributors to help improve it!
|
||||
|
||||
:::
|
||||
|
||||
Most of the time, you don't need versioning as it will just increase your build time, and introduce complexity to your codebase. Versioning is **best suited for websites with high-traffic and rapid changes to documentation between versions**. If your documentation rarely changes, don't add versioning to your documentation.
|
||||
|
||||
To better understand how versioning works and see if it suits your needs, you can read on below.
|
||||
|
||||
## Overview {#overview}
|
||||
|
||||
A typical versioned doc site looks like below:
|
||||
|
||||
```bash
|
||||
website
|
||||
├── sidebars.json # sidebar for the current docs version
|
||||
├── docs # docs directory for the current docs version
|
||||
│ ├── foo
|
||||
│ │ └── bar.md # https://mysite.com/docs/next/foo/bar
|
||||
│ └── hello.md # https://mysite.com/docs/next/hello
|
||||
├── versions.json # file to indicate what versions are available
|
||||
├── versioned_docs
|
||||
│ ├── version-1.1.0
|
||||
│ │ ├── foo
|
||||
│ │ │ └── bar.md # https://mysite.com/docs/foo/bar
|
||||
│ │ └── hello.md
|
||||
│ └── version-1.0.0
|
||||
│ ├── foo
|
||||
│ │ └── bar.md # https://mysite.com/docs/1.0.0/foo/bar
|
||||
│ └── hello.md
|
||||
├── versioned_sidebars
|
||||
│ ├── version-1.1.0-sidebars.json
|
||||
│ └── version-1.0.0-sidebars.json
|
||||
├── docusaurus.config.js
|
||||
└── package.json
|
||||
```
|
||||
|
||||
The `versions.json` file is a list of version names, ordered from newest to oldest.
|
||||
|
||||
The table below explains how a versioned file maps to its version and the generated URL.
|
||||
|
||||
| Path | Version | URL |
|
||||
| --------------------------------------- | -------------- | ----------------- |
|
||||
| `versioned_docs/version-1.0.0/hello.md` | 1.0.0 | /docs/1.0.0/hello |
|
||||
| `versioned_docs/version-1.1.0/hello.md` | 1.1.0 (latest) | /docs/hello |
|
||||
| `docs/hello.md` | current | /docs/next/hello |
|
||||
|
||||
:::tip
|
||||
|
||||
The files in the `docs` directory belong to the `current` docs version.
|
||||
|
||||
By default, the `current` docs version is labeled as `Next` and hosted under `/docs/next/*`, but it is entirely configurable to fit your project's release lifecycle.
|
||||
|
||||
:::
|
||||
|
||||
### Terminology {#terminology}
|
||||
|
||||
Note the terminology we use here.
|
||||
|
||||
<dl>
|
||||
<dt><b>Current version</b></dt>
|
||||
<dd>The version placed in the <code>./docs</code> folder.</dd>
|
||||
<dt><b>Latest version / last version</b></dt>
|
||||
<dd>The version served by default for docs navbar items. Usually has path <code>/docs</code>.</dd>
|
||||
</dl>
|
||||
|
||||
Current version is defined by the **file system location**, while latest version is defined by the **the navigation behavior**. They may or may not be the same version! (And the default configuration, as shown in the table above, would treat them as different: current version at `/docs/next` and latest at `/docs`.)
|
||||
|
||||
## Tutorials {#tutorials}
|
||||
|
||||
### Tagging a new version {#tagging-a-new-version}
|
||||
|
||||
1. First, make sure the current docs version (the `./docs` directory) is ready to be frozen.
|
||||
2. Enter a new version number.
|
||||
|
||||
```bash npm2yarn
|
||||
npm run docusaurus docs:version 1.1.0
|
||||
```
|
||||
|
||||
When tagging a new version, the document versioning mechanism will:
|
||||
|
||||
- Copy the full `docs/` folder contents into a new `versioned_docs/version-[versionName]/` folder.
|
||||
- Create a versioned sidebars file based from your current [sidebar](docs-introduction.md#sidebar) configuration (if it exists) - saved as `versioned_sidebars/version-[versionName]-sidebars.json`.
|
||||
- Append the new version number to `versions.json`.
|
||||
|
||||
### Creating new docs {#creating-new-docs}
|
||||
|
||||
1. Place the new file into the corresponding version folder.
|
||||
2. Include the reference to the new file in the corresponding sidebar file according to the version number.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Current version structure">
|
||||
|
||||
```bash
|
||||
# The new file.
|
||||
docs/new.md
|
||||
|
||||
# Edit the corresponding sidebar file.
|
||||
sidebar.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Older version structure">
|
||||
|
||||
```bash
|
||||
# The new file.
|
||||
versioned_docs/version-1.0.0/new.md
|
||||
|
||||
# Edit the corresponding sidebar file.
|
||||
versioned_sidebars/version-1.0.0-sidebars.json
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Updating an existing version {#updating-an-existing-version}
|
||||
|
||||
You can update multiple docs versions at the same time because each directory in `versioned_docs/` represents specific routes when published.
|
||||
|
||||
1. Edit any file.
|
||||
2. Commit and push changes.
|
||||
3. It will be published to the version.
|
||||
|
||||
Example: When you change any file in `versioned_docs/version-2.6/`, it will only affect the docs for version `2.6`.
|
||||
|
||||
### Deleting an existing version {#deleting-an-existing-version}
|
||||
|
||||
You can delete/remove versions as well.
|
||||
|
||||
1. Remove the version from `versions.json`.
|
||||
|
||||
Example:
|
||||
|
||||
```diff
|
||||
[
|
||||
"2.0.0",
|
||||
"1.9.0",
|
||||
// highlight-next-line
|
||||
- "1.8.0"
|
||||
]
|
||||
```
|
||||
|
||||
2. Delete the versioned docs directory. Example: `versioned_docs/version-1.8.0`.
|
||||
3. Delete the versioned sidebars file. Example: `versioned_sidebars/version-1.8.0-sidebars.json`.
|
||||
|
||||
## Configuring versioning behavior {#configuring-versioning-behavior}
|
||||
|
||||
The "current" version is the version name for the `./docs` folder. There are different ways to manage versioning, but two very common patterns are:
|
||||
|
||||
- You release v1, and start immediately working on v2 (including its docs). In this case, the **current version** is v2, which is in the `./docs` folder, while the **latest version** is v1, which is the version hosted at `example.com/docs` and is browsed by most of your users.
|
||||
- You release v1, and will maintain it for some time before thinking about v2. In this case, the **current version** and **latest version** will both be point to v1, since the v2 docs doesn't even exist yet!
|
||||
|
||||
Docusaurus defaults work great for the first use case. We will label the current version as "next" and you can even choose not to publish it.
|
||||
|
||||
**For the 2nd use case**: if you release v1 and don't plan to work on v2 anytime soon, instead of versioning v1 and having to maintain the docs in 2 folders (`./docs` + `./versioned_docs/version-1.0.0`), you may consider "pretending" that the current version is a cut version by giving it a path and a label:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@docusaurus/preset-classic',
|
||||
docs: {
|
||||
// highlight-start
|
||||
lastVersion: 'current',
|
||||
versions: {
|
||||
current: {
|
||||
label: '1.0.0',
|
||||
path: '1.0.0',
|
||||
},
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The docs in `./docs` will be served at `/docs/1.0.0` instead of `/docs/next`, and `1.0.0` will become the default version we link to in the navbar dropdown, and you will only need to maintain a single `./docs` folder.
|
||||
|
||||
We offer these plugin options to customize versioning behavior:
|
||||
|
||||
- `disableVersioning`: Explicitly disable versioning even with versions. This will make the site only include the current version.
|
||||
- `includeCurrentVersion`: Include the current version (the `./docs` folder) of your docs.
|
||||
- **Tip**: turn it off if the current version is a work-in-progress, not ready to be published.
|
||||
- `lastVersion`: Sets which version "latest version" (the `/docs` route) refers to.
|
||||
- **Tip**: `lastVersion: 'current'` makes sense if your current version refers to a major version that's constantly patched and released. The actual route base path and label of the latest version are configurable.
|
||||
- `onlyIncludeVersions`: Defines a subset of versions from `versions.json` to be deployed.
|
||||
- **Tip**: limit to 2 or 3 versions in dev and deploy previews to improve startup and build time.
|
||||
- `versions`: A dictionary of version metadata. For each version, you can customize the following:
|
||||
- `label`: the label displayed in the versions dropdown and banner.
|
||||
- `path`: the route base path of this version. By default, latest version has `/` and current version has `/next`.
|
||||
- `banner`: one of `'none'`, `'unreleased'`, and `'unmaintained'`. Determines what's displayed at the top of every doc page. Any version above the latest version would be "unreleased", and any version below would be "unmaintained".
|
||||
- `badge`: show a badge with the version name at the top of a doc of that version.
|
||||
- `className`: add a custom `className` to the `<html>` element of doc pages of that version.
|
||||
|
||||
See [docs plugin configuration](../../api/plugins/plugin-content-docs.md#configuration) for more details.
|
||||
|
||||
## Navbar items {#navbar-items}
|
||||
|
||||
We offer several navbar items to help you quickly set up navigation without worrying about versioned routes.
|
||||
|
||||
- [`doc`](../../api/themes/theme-configuration.md#navbar-doc-link): a link to a doc.
|
||||
- [`docSidebar`](../../api/themes/theme-configuration.md#navbar-doc-sidebar): a link to the first item in a sidebar.
|
||||
- [`docsVersion`](../../api/themes/theme-configuration.md#navbar-docs-version): a link to the main doc of the currently viewed version.
|
||||
- [`docsVersionDropdown`](../../api/themes/theme-configuration.md#navbar-docs-version-dropdown): a dropdown containing all the versions available.
|
||||
|
||||
These links would all look for an appropriate version to link to, in the following order:
|
||||
|
||||
1. **Active version**: the version that the user is currently browsing, if she is on a page provided by this doc plugin. If she's not on a doc page, fall back to...
|
||||
2. **Preferred version**: the version that the user last viewed. If there's no history, fall back to...
|
||||
3. **Latest version**: the default version that we navigate to, configured by the `lastVersion` option.
|
||||
|
||||
## Recommended practices {#recommended-practices}
|
||||
|
||||
### Version your documentation only when needed {#version-your-documentation-only-when-needed}
|
||||
|
||||
For example, you are building documentation for your npm package `foo` and you are currently in version 1.0.0. You then release a patch version for a minor bug fix and it's now 1.0.1.
|
||||
|
||||
Should you cut a new documentation version 1.0.1? **You probably shouldn't**. 1.0.1 and 1.0.0 docs shouldn't differ according to semver because there are no new features!. Cutting a new version for it will only just create unnecessary duplicated files.
|
||||
|
||||
### Keep the number of versions small {#keep-the-number-of-versions-small}
|
||||
|
||||
As a good rule of thumb, try to keep the number of your versions below 10. You will **very likely** to have a lot of obsolete versioned documentation that nobody even reads anymore. For example, [Jest](https://jestjs.io/versions) is currently in version `27.4`, and only maintains several latest documentation versions with the lowest being `25.X`. Keep it small 😊
|
||||
|
||||
:::tip archive older versions
|
||||
|
||||
If you deploy your site on a Jamstack provider (e.g. [Netlify](../../deployment.mdx)), the provider will save each production build as a snapshot under an immutable URL. You can include archived versions that will never be rebuilt as external links to these immutable URLs. The Jest website and the Docusaurus website both use such pattern to keep the number of actively built versions low.
|
||||
|
||||
:::
|
||||
|
||||
### Use absolute import within the docs {#use-absolute-import-within-the-docs}
|
||||
|
||||
Don't use relative paths import within the docs. Because when we cut a version the paths no longer work (the nesting level is different, among other reasons). You can utilize the `@site` alias provided by Docusaurus that points to the `website` directory. Example:
|
||||
|
||||
```diff
|
||||
- import Foo from '../src/components/Foo';
|
||||
+ import Foo from '@site/src/components/Foo';
|
||||
```
|
||||
|
||||
### Link docs by file paths {#link-docs-by-file-paths}
|
||||
|
||||
Refer to other docs by relative file paths with the `.md` extension, so that Docusaurus can rewrite them to actual URL paths during building. Files will be linked to the correct corresponding version.
|
||||
|
||||
```md
|
||||
The [@hello](hello.md#paginate) document is great!
|
||||
|
||||
See the [Tutorial](../getting-started/tutorial.md) for more info.
|
||||
```
|
||||
|
||||
### Global or versioned collocated assets {#global-or-versioned-collocated-assets}
|
||||
|
||||
You should decide if assets like images and files are per-version or shared between versions.
|
||||
|
||||
If your assets should be versioned, put them in the docs version, and use relative paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[download this file](./file.pdf)
|
||||
```
|
||||
|
||||
If your assets are global, put them in `/static` and use absolute paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[download this file](/file.pdf)
|
||||
```
|
||||
|
|
@ -5,39 +5,48 @@ description: Handling admonitions/callouts in Docusaurus Markdown
|
|||
slug: /markdown-features/admonitions
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Admonition from '@theme/Admonition';
|
||||
|
||||
In addition to the basic Markdown syntax, we use [remark-admonitions](https://github.com/elviswolcott/remark-admonitions) alongside MDX to add support for admonitions. Admonitions are wrapped by a set of 3 colons.
|
||||
|
||||
Example:
|
||||
|
||||
:::note
|
||||
```md
|
||||
:::note
|
||||
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
:::tip
|
||||
:::tip
|
||||
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
:::info
|
||||
:::info
|
||||
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
:::caution
|
||||
:::caution
|
||||
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
:::danger
|
||||
:::danger
|
||||
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
:::
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
:::note
|
||||
|
||||
|
|
@ -69,9 +78,11 @@ Some **content** with _markdown_ `syntax`. Check [this `api`](#).
|
|||
|
||||
:::
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Usage with Prettier {#usage-with-prettier}
|
||||
|
||||
If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might autoformat your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content.
|
||||
If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```md
|
||||
|
|
@ -95,11 +106,15 @@ Hello world
|
|||
|
||||
You may also specify an optional title
|
||||
|
||||
:::note Your Title
|
||||
```md
|
||||
:::note Your Title
|
||||
|
||||
Some **content** with _markdown_ `syntax`.
|
||||
Some **content** with _markdown_ `syntax`.
|
||||
|
||||
:::
|
||||
:::
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
:::note Your Title
|
||||
|
||||
|
|
@ -107,7 +122,9 @@ Some **content** with _markdown_ `syntax`.
|
|||
|
||||
:::
|
||||
|
||||
## Admonitions with MDX
|
||||
</BrowserWindow>
|
||||
|
||||
## Admonitions with MDX {#admonitions-with-mdx}
|
||||
|
||||
You can use MDX inside admonitions too!
|
||||
|
||||
|
|
@ -127,10 +144,7 @@ import TabItem from '@theme/TabItem';
|
|||
:::
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
<BrowserWindow>
|
||||
|
||||
:::tip Use tabs in admonitions
|
||||
|
||||
|
|
@ -144,7 +158,9 @@ import TabItem from '@theme/TabItem';
|
|||
|
||||
:::
|
||||
|
||||
## Usage in JSX
|
||||
</BrowserWindow>
|
||||
|
||||
## Usage in JSX {#usage-in-jsx}
|
||||
|
||||
Outside of Markdown, you can use the `@theme/Admonition` component to get the same output.
|
||||
|
||||
|
|
@ -173,13 +189,11 @@ The types that are accepted are the same as above: `note`, `tip`, `danger`, `inf
|
|||
</Admonition>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import Admonition from '@theme/Admonition';
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
<BrowserWindow>
|
||||
<Admonition type="tip" icon="💡" title="Did you know...">
|
||||
<p>Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project.</p>
|
||||
</Admonition>
|
||||
<Admonition type="tip" icon="💡" title="Did you know...">
|
||||
<p>
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX
|
||||
elements in your project.
|
||||
</p>
|
||||
</Admonition>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
|
@ -5,6 +5,8 @@ description: Handling assets in Docusaurus Markdown
|
|||
slug: /markdown-features/assets
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Sometimes you want to link to assets (e.g. docx files, images...) directly from Markdown files, and it is convenient to co-locate the asset next to the Markdown file using it.
|
||||
|
||||
Let's imagine the following file structure:
|
||||
|
|
@ -20,17 +22,17 @@ Let's imagine the following file structure:
|
|||
|
||||
## Images {#images}
|
||||
|
||||
You can display images in three different ways: Markdown syntax, JSX require or ES imports syntax.
|
||||
You can display images in three different ways: Markdown syntax, CJS require, or ES imports syntax.
|
||||
|
||||
Display images using simple Markdown syntax:
|
||||
|
||||
```mdx
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
Display images using inline CommonJS `require` in JSX image tag:
|
||||
|
||||
```mdx
|
||||
```jsx
|
||||
<img
|
||||
src={require('./assets/docusaurus-asset-example-banner.png').default}
|
||||
alt="Example banner"
|
||||
|
|
@ -39,16 +41,20 @@ Display images using inline CommonJS `require` in JSX image tag:
|
|||
|
||||
Display images using ES `import` syntax and JSX image tag:
|
||||
|
||||
```mdx
|
||||
```jsx
|
||||
import myImageUrl from './assets/docusaurus-asset-example-banner.png';
|
||||
|
||||
<img src={myImageUrl} alt="Example banner" />
|
||||
<img src={myImageUrl} alt="Example banner" />;
|
||||
```
|
||||
|
||||
This results in displaying the image:
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::note
|
||||
|
||||
If you are using [@docusaurus/plugin-ideal-image](../../api/plugins/plugin-ideal-image.md), you need to use the dedicated image component, as documented.
|
||||
|
|
@ -57,22 +63,20 @@ If you are using [@docusaurus/plugin-ideal-image](../../api/plugins/plugin-ideal
|
|||
|
||||
## Files {#files}
|
||||
|
||||
In the same way, you can link to existing assets by requiring them and using the returned url in videos, links etc.
|
||||
In the same way, you can link to existing assets by requiring them and using the returned url in videos, links, etc.
|
||||
|
||||
```mdx
|
||||
```md
|
||||
# My Markdown page
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href={require('./assets/docusaurus-asset-example.docx').default}>
|
||||
Download this docx
|
||||
</a>
|
||||
<a target="\_blank" href={require('./assets/docusaurus-asset-example.docx').default}> Download this docx </a>
|
||||
|
||||
or
|
||||
|
||||
[Download this docx using Markdown](./assets/docusaurus-asset-example.docx)
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href={require('../../assets/docusaurus-asset-example.docx').default}>
|
||||
|
|
@ -81,6 +85,14 @@ or
|
|||
|
||||
[Download this docx using Markdown](../../assets/docusaurus-asset-example.docx)
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::info markdown links are always file paths
|
||||
|
||||
If you use the Markdown image or link syntax, all asset paths will be resolved as file paths by Docusaurus and automatically converted to `require()` calls. You don't need to use `require()` in Markdown unless you use the JSX syntax.
|
||||
|
||||
:::
|
||||
|
||||
## Inline SVGs {#inline-svgs}
|
||||
|
||||
Docusaurus supports inlining SVGs out of the box.
|
||||
|
|
@ -91,11 +103,15 @@ import DocusaurusSvg from './docusaurus.svg';
|
|||
<DocusaurusSvg />;
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
import DocusaurusSvg from '@site/static/img/docusaurus.svg';
|
||||
|
||||
<DocusaurusSvg />
|
||||
|
||||
This can be useful, if you want to alter the part of the SVG image via CSS. For example, you can change one of the SVG colors based on the current theme.
|
||||
</BrowserWindow>
|
||||
|
||||
This can be useful if you want to alter the part of the SVG image via CSS. For example, you can change one of the SVG colors based on the current theme.
|
||||
|
||||
```jsx
|
||||
import DocusaurusSvg from './docusaurus.svg';
|
||||
|
|
@ -104,30 +120,34 @@ import DocusaurusSvg from './docusaurus.svg';
|
|||
```
|
||||
|
||||
```css
|
||||
html[data-theme='light'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
[data-theme='light'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
fill: greenyellow;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
[data-theme='dark'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
fill: seagreen;
|
||||
}
|
||||
```
|
||||
|
||||
<DocusaurusSvg className="themedDocusaurus" />
|
||||
<BrowserWindow>
|
||||
<DocusaurusSvg className="themedDocusaurus" />
|
||||
</BrowserWindow>
|
||||
|
||||
## Themed Images {#themed-images}
|
||||
|
||||
Docusaurus supports themed images: the `ThemedImage` component (included in the themes) allows you to switch the image source based on the current theme.
|
||||
|
||||
```jsx {5-8}
|
||||
```jsx
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
// highlight-start
|
||||
sources={{
|
||||
light: useBaseUrl('/img/docusaurus_light.svg'),
|
||||
dark: useBaseUrl('/img/docusaurus_dark.svg'),
|
||||
}}
|
||||
// highlight-end
|
||||
/>;
|
||||
```
|
||||
|
||||
|
|
@ -135,6 +155,7 @@ import ThemedImage from '@theme/ThemedImage';
|
|||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<BrowserWindow>
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
|
|
@ -142,8 +163,32 @@ import ThemedImage from '@theme/ThemedImage';
|
|||
dark: useBaseUrl('/img/docusaurus_speed.svg'),
|
||||
}}
|
||||
/>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### GitHub-style themed images {#github-style-themed-images}
|
||||
|
||||
GitHub uses its own [image theming approach](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) with path fragments, which you can easily implement yourself.
|
||||
|
||||
To toggle the visibility of an image using the path fragment (for GitHub, it's `#gh-dark-mode-only` and `#gh-light-mode-only`), add the following to your custom CSS (you can also use your own suffix if you don't want to be coupled to GitHub):
|
||||
|
||||
```css title="src/css/custom.css"
|
||||
[data-theme='light'] img[src$='#gh-dark-mode-only'],
|
||||
[data-theme='dark'] img[src$='#gh-light-mode-only'] {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Static assets {#static-assets}
|
||||
|
||||
If a Markdown link or image has an absolute path, the path will be seen as a file path and will be resolved from the static directories. For example, if you have configured [static directories](../../static-assets.md) to be `['public', 'static']`, then for the following image:
|
||||
|
|
@ -152,7 +197,15 @@ If a Markdown link or image has an absolute path, the path will be seen as a fil
|
|||

|
||||
```
|
||||
|
||||
Docusaurus will try to look for it in both `static/img/docusaurus.png` and `public/img/docusaurus.png`. The link will then be converted to a `require` call instead of staying as a URL. This is desirable in two regards:
|
||||
Docusaurus will try to look for it in both `static/img/docusaurus.png` and `public/img/docusaurus.png`. The link will then be converted to a `require()` call instead of staying as a URL. This is desirable in two regards:
|
||||
|
||||
1. You don't have to worry about base URL, which Docusaurus will take care of when serving the asset;
|
||||
1. You don't have to worry about the base URL, which Docusaurus will take care of when serving the asset;
|
||||
2. The image enters Webpack's build pipeline and its name will be appended by a hash, which enables browsers to aggressively cache the image and improves your site's performance.
|
||||
|
||||
If you intend to write URLs, you can use the `pathname://` protocol to disable automatic asset linking.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
This link will be generated as `<img src="/img/docusaurus-asset-example-banner.png" alt="banner" />`, without any processing or file existence checking.
|
||||
|
|
@ -5,11 +5,14 @@ description: Handling code blocks in Docusaurus Markdown
|
|||
slug: /markdown-features/code-blocks
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
Code blocks within documentation are super-powered 💪.
|
||||
|
||||
## Code title {#code-title}
|
||||
|
||||
You can add a title to the code block by adding `title` key after the language (leave a space between them).
|
||||
You can add a title to the code block by adding a `title` key after the language (leave a space between them).
|
||||
|
||||
```jsx title="/src/components/HelloCodeTitle.js"
|
||||
function HelloCodeTitle(props) {
|
||||
|
|
@ -17,44 +20,53 @@ You can add a title to the code block by adding `title` key after the language (
|
|||
}
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
```jsx title="/src/components/HelloCodeTitle.js"
|
||||
function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Syntax highlighting {#syntax-highlighting}
|
||||
|
||||
Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for specifications of MDX.
|
||||
Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for the specifications of MDX.
|
||||
|
||||
```jsx
|
||||
```js
|
||||
console.log('Every repo must come with a mascot.');
|
||||
```
|
||||
|
||||
<!-- TODO: We need to allow users to pick syntax highlighting themes (maybe other than swizzling) -->
|
||||
|
||||
Use the matching language meta string for your code block, and Docusaurus will pick up syntax highlighting automatically, powered by [Prism React Renderer](https://github.com/FormidableLabs/prism-react-renderer).
|
||||
|
||||
```jsx
|
||||
<BrowserWindow>
|
||||
|
||||
```js
|
||||
console.log('Every repo must come with a mascot.');
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
### Theming {#theming}
|
||||
|
||||
By default, the Prism [syntax highlighting theme](https://github.com/FormidableLabs/prism-react-renderer#theming) we use is [Palenight](https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/themes/palenight.js). You can change this to another theme by passing `theme` field in `prism` as `themeConfig` in your docusaurus.config.js.
|
||||
|
||||
For example, if you prefer to use the `dracula` highlighting theme:
|
||||
|
||||
```js {4} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
prism: {
|
||||
// highlight-next-line
|
||||
theme: require('prism-react-renderer/themes/dracula'),
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Because a Prism theme is just a JS object, you can also write your own theme if you are not satisfied with the default. Docusaurus enhances the `github` and `vsDark` themes to provide richer highlight, and you can check our implementations for the [light](https://github.com/facebook/docusaurus/blob/main/website/src/utils/prismLight.mjs) and [dark](https://github.com/facebook/docusaurus/blob/main/website/src/utils/prismDark.mjs) code block themes.
|
||||
|
||||
### Supported Languages {#supported-languages}
|
||||
|
||||
By default, Docusaurus comes with a subset of [commonly used languages](https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/vendor/prism/includeLangs.js).
|
||||
|
|
@ -65,15 +77,16 @@ Some popular languages like Java, C#, or PHP are not enabled by default.
|
|||
|
||||
:::
|
||||
|
||||
To add syntax highlighting for any of the other [Prism supported languages](https://prismjs.com/#supported-languages), define it in an array of additional languages.
|
||||
To add syntax highlighting for any of the other [Prism-supported languages](https://prismjs.com/#supported-languages), define it in an array of additional languages.
|
||||
|
||||
For example, if you want to add highlighting for the `powershell` language:
|
||||
For example, if you want to add highlighting for the PowerShell language:
|
||||
|
||||
```js {5} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
prism: {
|
||||
// highlight-next-line
|
||||
additionalLanguages: ['powershell'],
|
||||
},
|
||||
// ...
|
||||
|
|
@ -91,14 +104,15 @@ npm run swizzle @docusaurus/theme-classic prism-include-languages
|
|||
|
||||
It will produce `prism-include-languages.js` in your `src/theme` folder. You can add highlighting support for custom languages by editing `prism-include-languages.js`:
|
||||
|
||||
```js {8} title="src/theme/prism-include-languages.js"
|
||||
```js title="src/theme/prism-include-languages.js"
|
||||
const prismIncludeLanguages = (Prism) => {
|
||||
// ...
|
||||
|
||||
additionalLanguages.forEach((lang) => {
|
||||
require(`prismjs/components/prism-${lang}`); // eslint-disable-line
|
||||
require(`prismjs/components/prism-${lang}`);
|
||||
});
|
||||
|
||||
// highlight-next-line
|
||||
require('/path/to/your/prism-language-definition');
|
||||
|
||||
// ...
|
||||
|
|
@ -109,82 +123,11 @@ You can refer to [Prism's official language definitions](https://github.com/Pris
|
|||
|
||||
## Line highlighting {#line-highlighting}
|
||||
|
||||
You can bring emphasis to certain lines of code by specifying line ranges after the language meta string (leave a space after the language).
|
||||
|
||||
```jsx {3}
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
|
||||
```jsx {3}
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
|
||||
To accomplish this, Docusaurus adds the `docusaurus-highlight-code-line` class to the highlighted lines. You will need to define your own styling for this CSS, possibly in your `src/css/custom.css` with a custom background color which is dependent on your selected syntax highlighting theme. The color given below works for the default highlighting theme (Palenight), so if you are using another theme, you will have to tweak the color accordingly.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
.docusaurus-highlight-code-line {
|
||||
background-color: rgb(72, 77, 91);
|
||||
display: block;
|
||||
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
/* If you have a different syntax highlighting theme for dark mode. */
|
||||
html[data-theme='dark'] .docusaurus-highlight-code-line {
|
||||
/* Color which works with dark mode syntax highlighting theme */
|
||||
background-color: rgb(100, 100, 100);
|
||||
}
|
||||
```
|
||||
|
||||
### Multiple line highlighting {#multiple-line-highlighting}
|
||||
|
||||
To highlight multiple lines, separate the line numbers by commas or use the range syntax to select a chunk of lines. This feature uses the `parse-number-range` library and you can find [more syntax](https://www.npmjs.com/package/parse-numeric-range) on their project details.
|
||||
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
### Highlighting with comments {#highlighting-with-comments}
|
||||
|
||||
You can also use comments with `highlight-next-line`, `highlight-start`, and `highlight-end` to select which lines are highlighted.
|
||||
You can use comments with `highlight-next-line`, `highlight-start`, and `highlight-end` to select which lines are highlighted.
|
||||
|
||||
```jsx
|
||||
```js
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
// highlight-next-line
|
||||
|
|
@ -205,7 +148,10 @@ You can also use comments with `highlight-next-line`, `highlight-start`, and `hi
|
|||
}
|
||||
```
|
||||
|
||||
```jsx
|
||||
````mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
```js
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
// highlight-next-line
|
||||
|
|
@ -226,6 +172,9 @@ function HighlightMoreText(highlight) {
|
|||
}
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
````
|
||||
|
||||
Supported commenting syntax:
|
||||
|
||||
| Language | Syntax |
|
||||
|
|
@ -237,6 +186,81 @@ Supported commenting syntax:
|
|||
|
||||
If there's a syntax that is not currently supported, we are open to adding them! Pull requests welcome.
|
||||
|
||||
To accomplish this, Docusaurus adds the `docusaurus-highlight-code-line` class to the highlighted lines. You will need to define your own styling for this CSS, possibly in your `src/css/custom.css` with a custom background color which is dependent on your selected syntax highlighting theme. The color given below works for the default highlighting theme (Palenight), so if you are using another theme, you will have to tweak the color accordingly.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
.docusaurus-highlight-code-line {
|
||||
background-color: rgb(72, 77, 91);
|
||||
display: block;
|
||||
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
/* If you have a different syntax highlighting theme for dark mode. */
|
||||
[data-theme='dark'] .docusaurus-highlight-code-line {
|
||||
/* Color which works with dark mode syntax highlighting theme */
|
||||
background-color: rgb(100, 100, 100);
|
||||
}
|
||||
```
|
||||
|
||||
### Highlighting with metadata string {#highlighting-with-metadata-string}
|
||||
|
||||
You can also specify highlighted line ranges within the language meta string (leave a space after the language). To highlight multiple lines, separate the line numbers by commas or use the range syntax to select a chunk of lines. This feature uses the `parse-number-range` library and you can find [more syntax](https://www.npmjs.com/package/parse-numeric-range) on their project details.
|
||||
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::tip prefer comments
|
||||
|
||||
Prefer highlighting with comments where you can. By inlining highlight in the code, you don't have to manually count the lines if your code block becomes long. If you add/remove lines, you also don't have to offset your line ranges.
|
||||
|
||||
````diff
|
||||
- ```jsx {3}
|
||||
+ ```jsx {4}
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
+ console.log('Highlighted text found');
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
In the future, we may extend the magic comment system and let you define custom directives and their functionalities. The magic comments would only be parsed if a highlight metastring is not present.
|
||||
|
||||
:::
|
||||
|
||||
## Interactive code editor {#interactive-code-editor}
|
||||
|
||||
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
|
||||
|
|
@ -286,6 +310,8 @@ To use the plugin, create a code block with `live` attached to the language meta
|
|||
|
||||
The code block will be rendered as an interactive editor. Changes to the code will reflect on the result panel live.
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
```jsx live
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
|
|
@ -309,6 +335,8 @@ function Clock(props) {
|
|||
}
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
### Imports {#imports}
|
||||
|
||||
:::caution react-live and imports
|
||||
|
|
@ -323,14 +351,16 @@ By default, all React imports are available. If you need more imports available,
|
|||
npm run swizzle @docusaurus/theme-live-codeblock ReactLiveScope
|
||||
```
|
||||
|
||||
```jsx {3-15,21} title="src/theme/ReactLiveScope/index.js"
|
||||
```jsx title="src/theme/ReactLiveScope/index.js"
|
||||
import React from 'react';
|
||||
|
||||
// highlight-start
|
||||
const ButtonExample = (props) => (
|
||||
<button
|
||||
{...props}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
color: 'black',
|
||||
border: 'solid red',
|
||||
borderRadius: 20,
|
||||
padding: 10,
|
||||
|
|
@ -339,11 +369,13 @@ const ButtonExample = (props) => (
|
|||
}}
|
||||
/>
|
||||
);
|
||||
// highlight-end
|
||||
|
||||
// Add react-live imports you need here
|
||||
const ReactLiveScope = {
|
||||
React,
|
||||
...React,
|
||||
// highlight-next-line
|
||||
ButtonExample,
|
||||
};
|
||||
|
||||
|
|
@ -352,6 +384,8 @@ export default ReactLiveScope;
|
|||
|
||||
The `ButtonExample` component is now available to use:
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
```jsx live
|
||||
function MyPlayground(props) {
|
||||
return (
|
||||
|
|
@ -362,13 +396,58 @@ function MyPlayground(props) {
|
|||
}
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Using JSX markup in code blocks {#using-jsx-markup}
|
||||
|
||||
Code block in Markdown always preserves its content as plain text, meaning you can't do something like:
|
||||
|
||||
```ts
|
||||
type EditUrlFunction = (params: {
|
||||
// This doesn't turn into a link (for good reason!)
|
||||
version: <a href="/docs/versioning">Version</a>;
|
||||
versionDocsDirPath: string;
|
||||
docPath: string;
|
||||
permalink: string;
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
```
|
||||
|
||||
If you want to embed HTML markup such as anchor links or bold type, you can use the `<pre>` tag, `<code>` tag, or `<CodeBlock>` component.
|
||||
|
||||
```jsx
|
||||
<pre>
|
||||
<b>Input: </b>1 2 3 4{'\n'}
|
||||
<b>Output: </b>"366300745"{'\n'}
|
||||
</pre>
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
<pre>
|
||||
<b>Input: </b>1 2 3 4{'\n'}
|
||||
<b>Output: </b>"366300745"{'\n'}
|
||||
</pre>
|
||||
</BrowserWindow>
|
||||
|
||||
:::caution MDX is whitespace insensitive
|
||||
|
||||
MDX is in line with JSX behavior: line break characters, even when inside `<pre>`, are turned into spaces. You have to explicitly write the new line character for it to be printed out.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Syntax highlighting only works on plain strings. Docusaurus will not attempt to parse code block content containing JSX children.
|
||||
|
||||
:::
|
||||
|
||||
## Multi-language support code blocks {#multi-language-support-code-blocks}
|
||||
|
||||
With MDX, you can easily create interactive components within your documentation, for example, to display code in multiple programming languages and switching between them using a tabs component.
|
||||
With MDX, you can easily create interactive components within your documentation, for example, to display code in multiple programming languages and switch between them using a tabs component.
|
||||
|
||||
Instead of implementing a dedicated component for multi-language support code blocks, we've implemented a generic Tabs component in the classic theme so that you can use it for other non-code scenarios as well.
|
||||
|
||||
The following example is how you can have multi-language code tabs in your docs. Note that the empty lines above and below each language block is **intentional**. This is a current limitation of MDX, you have to leave empty lines around Markdown syntax for the MDX parser to know that it's Markdown syntax and not JSX.
|
||||
The following example is how you can have multi-language code tabs in your docs. Note that the empty lines above and below each language block are **intentional**. This is a current limitation of MDX: you have to leave empty lines around Markdown syntax for the MDX parser to know that it's Markdown syntax and not JSX.
|
||||
|
||||
````jsx
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
|
@ -409,6 +488,7 @@ class HelloWorld {
|
|||
And you will get the following:
|
||||
|
||||
````mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs>
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
|
|
@ -439,6 +519,7 @@ class HelloWorld {
|
|||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
````
|
||||
|
||||
If you have multiple of these multi-language code tabs, and you want to sync the selection across the tab instances, refer to the [Syncing tab choices section](markdown-features-tabs.mdx#syncing-tab-choices).
|
||||
|
|
@ -489,3 +570,39 @@ npm install @docusaurus/remark-plugin-npm2yarn
|
|||
````
|
||||
|
||||
Using the `{sync: true}` option would make all tab choices synced. Because the choice is stored under the same namespace `npm2yarn`, different `npm2yarn` plugin instances would also sync their choices.
|
||||
|
||||
## Usage in JSX {#usage-in-jsx}
|
||||
|
||||
Outside of Markdown, you can use the `@theme/CodeBlock` component to get the same output.
|
||||
|
||||
```jsx
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export default function MyReactPage() {
|
||||
return (
|
||||
<div>
|
||||
{/* highlight-start */}
|
||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
||||
{`function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}`}
|
||||
</CodeBlock>
|
||||
{/* highlight-end */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
||||
{`function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}`}
|
||||
</CodeBlock>
|
||||
</BrowserWindow>
|
||||
|
||||
The props accepted are `language` and `title`, in the same way as you write Markdown code blocks.
|
||||
|
||||
Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js"'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments).
|
||||
|
||||
As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.
|
||||
|
|
@ -48,7 +48,7 @@ My text
|
|||
|
||||
This `<head>` declaration has been added to the current Markdown doc, as a demo.
|
||||
|
||||
Open your browser DevTools and check how this page's metadata have been affected.
|
||||
Open your browser DevTools and check how this page's metadata has been affected.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -17,11 +17,11 @@ You can use regular Markdown headings.
|
|||
#### Level 4 title
|
||||
```
|
||||
|
||||
Markdown headings appear as a table-of-contents entry.
|
||||
Markdown headings appear as a table of contents entry.
|
||||
|
||||
## Heading ids {#heading-ids}
|
||||
|
||||
Each heading has an id that can be automatically generated, or explicitly specified.
|
||||
Each heading has an id that can be automatically generated or explicitly specified.
|
||||
|
||||
Heading ids allow you to link to a specific document heading in Markdown or JSX:
|
||||
|
||||
|
|
@ -35,9 +35,7 @@ Heading ids allow you to link to a specific document heading in Markdown or JSX:
|
|||
|
||||
### Generated ids {#generated-ids}
|
||||
|
||||
By default, Docusaurus will generate heading ids for you, based on the heading text.
|
||||
|
||||
`### Hello World` will have id `hello-world`.
|
||||
By default, Docusaurus will generate heading ids for you, based on the heading text. For example, `### Hello World` will have id `hello-world`.
|
||||
|
||||
Generated ids have **some limits**:
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ But it is also possible to display an inline table of contents directly inside a
|
|||
|
||||
## Full table of contents {#full-table-of-contents}
|
||||
|
||||
The `toc` variable is available in any MDX document, and contains all the headings of a MDX document.
|
||||
The `toc` variable is available in any MDX document and contains all the headings of an MDX document.
|
||||
|
||||
By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel`.
|
||||
|
||||
|
|
@ -35,35 +35,38 @@ import TOCInline from '@theme/TOCInline';
|
|||
|
||||
## Custom table of contents {#custom-table-of-contents}
|
||||
|
||||
The `toc` props is just a list of table of contents items:
|
||||
The `toc` prop is just a list of heading items:
|
||||
|
||||
```ts
|
||||
type TOCItem = {
|
||||
value: string;
|
||||
id: string;
|
||||
children: TOCItem[];
|
||||
level: number;
|
||||
};
|
||||
```
|
||||
|
||||
You can create this TOC tree manually, or derive a new TOC tree from the `toc` variable:
|
||||
Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree.
|
||||
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<TOCInline
|
||||
toc={
|
||||
// Only show 3th and 5th top-level heading
|
||||
[toc[2], toc[4]]
|
||||
}
|
||||
// Only show h2 and h4 headings
|
||||
toc={toc.filter((node) => node.level === 2 || node.level === 4)}
|
||||
/>;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<TOCInline toc={toc.filter((node) => node.level === 2 || node.level === 4)} />
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
:::caution
|
||||
|
||||
The underlying content is just an example to have more table-of-contents items available in current page.
|
||||
Below is just some dummy content to have more table of contents items available on the current page.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -75,14 +78,32 @@ Lorem ipsum
|
|||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 a I
|
||||
|
||||
#### Example subsubsection 1 a II
|
||||
|
||||
#### Example subsubsection 1 a III
|
||||
|
||||
### Example Subsection 1 b {#example-subsection-1-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 b I
|
||||
|
||||
#### Example subsubsection 1 b II
|
||||
|
||||
#### Example subsubsection 1 b III
|
||||
|
||||
### Example Subsection 1 c {#example-subsection-1-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 c I
|
||||
|
||||
#### Example subsubsection 1 c II
|
||||
|
||||
#### Example subsubsection 1 c III
|
||||
|
||||
## Example Section 2 {#example-section-2}
|
||||
|
||||
Lorem ipsum
|
||||
|
|
@ -91,14 +112,32 @@ Lorem ipsum
|
|||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 a I
|
||||
|
||||
#### Example subsubsection 2 a II
|
||||
|
||||
#### Example subsubsection 2 a III
|
||||
|
||||
### Example Subsection 2 b {#example-subsection-2-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 b I
|
||||
|
||||
#### Example subsubsection 2 b II
|
||||
|
||||
#### Example subsubsection 2 b III
|
||||
|
||||
### Example Subsection 2 c {#example-subsection-2-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 c I
|
||||
|
||||
#### Example subsubsection 2 c II
|
||||
|
||||
#### Example subsubsection 2 c III
|
||||
|
||||
## Example Section 3 {#example-section-3}
|
||||
|
||||
Lorem ipsum
|
||||
|
|
@ -107,10 +146,28 @@ Lorem ipsum
|
|||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 a I
|
||||
|
||||
#### Example subsubsection 3 a II
|
||||
|
||||
#### Example subsubsection 3 a III
|
||||
|
||||
### Example Subsection 3 b {#example-subsection-3-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 b I
|
||||
|
||||
#### Example subsubsection 3 b II
|
||||
|
||||
#### Example subsubsection 3 b III
|
||||
|
||||
### Example Subsection 3 c {#example-subsection-3-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 c I
|
||||
|
||||
#### Example subsubsection 3 c II
|
||||
|
||||
#### Example subsubsection 3 c III
|
||||
|
|
@ -6,15 +6,11 @@ description: Docusaurus uses GitHub Flavored Markdown (GFM). Find out more about
|
|||
slug: /markdown-features
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
```
|
||||
|
||||
Documentation is one of your product's interfaces with your users. A well-written and well-organized set of docs helps your users understand your product quickly. Our aligned goal here is to help your users find and understand the information they need, as quickly as possible.
|
||||
|
||||
Docusaurus 2 uses modern tooling to help you compose your interactive documentations with ease. You may embed React components, or build live coding blocks where your users may play with the code on the spot. Start sharing your eureka moments with the code your audience cannot walk away from. It is perhaps the most effective way of attracting potential users.
|
||||
|
||||
In this section, we'd like to introduce you to the tools we've picked that we believe will help you build a powerful documentation. Let us walk you through with an example.
|
||||
Docusaurus 2 uses modern tooling to help you compose your interactive documentation with ease. You may embed React components, or build live coding blocks where your users may play with the code on the spot. Start sharing your eureka moments with the code your audience cannot walk away from. It is perhaps the most effective way of attracting potential users.
|
||||
|
||||
:::important
|
||||
|
||||
|
|
@ -22,7 +18,7 @@ This section assumes you are using the official Docusaurus content plugins.
|
|||
|
||||
:::
|
||||
|
||||
## Standard features
|
||||
## Standard features {#standard-features}
|
||||
|
||||
Markdown is a syntax that enables you to write formatted content in a readable syntax.
|
||||
|
||||
|
|
@ -31,7 +27,7 @@ The [standard Markdown syntax](https://daringfireball.net/projects/markdown/synt
|
|||
```md
|
||||
### My Doc Section
|
||||
|
||||
Hello world message with some **bold** text, some _italic_ text and a [link](/)
|
||||
Hello world message with some **bold** text, some _italic_ text, and a [link](/)
|
||||
|
||||

|
||||
```
|
||||
|
|
@ -48,17 +44,25 @@ Hello world message with some **bold** text, some _italic_ text and a [link](/)
|
|||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Quotes
|
||||
## Quotes {#quotes}
|
||||
|
||||
Markdown quotes are beautifully styled:
|
||||
|
||||
```md
|
||||
> This is a quote
|
||||
> Easy to maintain open source documentation websites.
|
||||
>
|
||||
> — Docusaurus
|
||||
```
|
||||
|
||||
> This is a quote
|
||||
<BrowserWindow>
|
||||
|
||||
## Details
|
||||
> Easy to maintain open source documentation websites.
|
||||
>
|
||||
> — Docusaurus
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Details {#details}
|
||||
|
||||
Markdown can embed HTML elements, and [`details`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) HTML elements are beautifully styled:
|
||||
|
||||
|
|
@ -104,8 +108,6 @@ Markdown can embed HTML elements, and [`details`](https://developer.mozilla.org/
|
|||
</details>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
<br/>
|
||||
```
|
||||
|
||||
:::note
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
---
|
||||
id: math-equations
|
||||
title: Math Equations
|
||||
description: Writing LaTeX Math Equations
|
||||
slug: /markdown-features/math-equations
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Mathematical equations can be rendered using [KaTeX](https://katex.org).
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
Please read [KaTeX](https://katex.org) documentation for more details.
|
||||
|
||||
### Inline {#inline}
|
||||
|
||||
Write inline math equations by wrapping LaTeX equations between `$`:
|
||||
|
||||
```mdx
|
||||
Let $f\colon[a,b] \to \R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be $F(x)=
|
||||
\int_{a}^{x} f(t)\,dt$. Then $$F$$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
Let $f\colon[a,b] \to \R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be $F(x)=
|
||||
\int_{a}^{x} f(t)\,dt$. Then $F$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
### Blocks {#blocks}
|
||||
|
||||
For equation block or display mode, use line breaks and `$$`:
|
||||
|
||||
```mdx
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x)\,dx
|
||||
$$
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x)\,dx
|
||||
$$
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save remark-math@3 rehype-katex@5 hast-util-is-element@1.1.0
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
Use the exact same versions. The latest versions are incompatible with Docusaurus 2.
|
||||
|
||||
:::
|
||||
|
||||
Import the plugins in `docusaurus.config.js`:
|
||||
|
||||
```js
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
```
|
||||
|
||||
Add them to your content plugin or preset options (usually `@docusaurus/preset-classic` docs options):
|
||||
|
||||
```js
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
```
|
||||
|
||||
Include the KaTeX CSS in your config under `stylesheets`:
|
||||
|
||||
```js
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Overall the changes look like:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-start
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
// highlight-end
|
||||
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// highlight-start
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
## Self-hosting KaTeX assets {#self-hosting-katex-assets}
|
||||
|
||||
Loading stylesheets, fonts, and javascript libraries from CDN sources is a good practice for popular libraries and assets, since it reduces the amount of assets you have to host. In case you prefer to self-host the `katex.min.css` (along with required KaTeX fonts), you can download the latest version from [KaTeX GitHub releases](https://github.com/KaTeX/KaTeX/releases), extract and copy `katex.min.css` and `fonts` directory (only `.woff2` font types should be enough) to your site's `static` directory, and in `docusaurus.config.js`, replace the stylesheet's `href` from the CDN url to your local path (say, `/katex/katex.min.css`).
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
stylesheets: [
|
||||
{
|
||||
href: '/katex/katex.min.css',
|
||||
type: 'text/css',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Upgrading rehype-katex beyond recommended version {#upgrading-rehype-katex-beyond-recommended-version}
|
||||
|
||||
:::tip
|
||||
|
||||
Only use the latest version if you actually need the bleeding-edge features of $\KaTeX$. Most users should find the older versions work just as well.
|
||||
|
||||
:::
|
||||
|
||||
The latest versions of `rehype-katex` (starting from `v6.0.0`) has moved to ES Modules, a new module system of JavaScript, which Docusaurus doesn't officially support yet. However, it is possible to import `rehype-katex` dynamically, using an async config creator. Docusaurus will call this creator function and wait for it to return the config object.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
async function createConfig() {
|
||||
// ES Modules are imported with `import()` instead of `require()`, and are imported asynchronously
|
||||
// highlight-next-line
|
||||
const katex = (await import('rehype-katex')).default;
|
||||
return {
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In this case, the overall configuration changes will look like:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-next-line
|
||||
const math = require('remark-math');
|
||||
|
||||
async function createConfig() {
|
||||
// highlight-next-line
|
||||
const katex = (await import('rehype-katex')).default;
|
||||
return {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// highlight-start
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = createConfig;
|
||||
```
|
||||
|
|
@ -8,7 +8,7 @@ slug: /markdown-features/plugins
|
|||
Sometimes, you may want to extend or tweak your Markdown syntax. For example:
|
||||
|
||||
- How do I embed youtube videos using the image syntax (``)?
|
||||
- How do I style links that are on its own line differently, e.g., like a social card?
|
||||
- How do I style links that are on their own lines differently, e.g., as a social card?
|
||||
- How do I make every page start with a copyright notice?
|
||||
|
||||
And the answer is: create an MDX plugin! MDX has a built-in [plugin system](https://mdxjs.com/advanced/plugins/) that can be used to customize how the Markdown files will be parsed and transformed to JSX. There are three typical use-cases of MDX plugins:
|
||||
|
|
@ -24,7 +24,7 @@ If you play with the [MDX playground](https://mdx-git-renovate-babel-monorepo-md
|
|||
|
||||
:::tip
|
||||
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project. The [admonition](./markdown-features-admonitions.mdx) syntax that we offer is also generated by a [Remark plugin](https://github.com/elviswolcott/remark-admonitions), and you could do the same for your own use-case.
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project. The [admonition](./markdown-features-admonitions.mdx) syntax that we offer is also generated by a [Remark plugin](https://github.com/elviswolcott/remark-admonitions), and you could do the same for your own use case.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ These are all typical use-cases of Remark plugins, which can also be a source of
|
|||
|
||||
## Installing plugins {#installing-plugins}
|
||||
|
||||
An MDX plugin is usually a npm package, so you install them like other npm packages using npm. Take the [math plugins](./markdown-features-math-equations.mdx) as example.
|
||||
An MDX plugin is usually an npm package, so you install them like other npm packages using npm. Take the [math plugins](./markdown-features-math-equations.mdx) as an example.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save remark-math@3 rehype-katex@4
|
||||
|
|
@ -49,16 +49,16 @@ npm install --save remark-math@3 rehype-katex@4
|
|||
|
||||
:::note
|
||||
|
||||
There's recently a trend in the Remark/Rehype ecosystem to migrate to ES Modules, which Docusaurus doesn't support yet. Please make sure your installed plugin version is CommonJS-compatible before we officially support ESM.
|
||||
There's recently a trend in the Remark/Rehype ecosystem to migrate to ES Modules, a new JavaScript module system, which Docusaurus doesn't support yet. Please make sure your installed plugin version is CommonJS-compatible before we officially support ESM. Alternatively, you can read about using dynamic `import()` as a workaround in the tutorial of installing [`rehype-katex`](./markdown-features-math-equations.mdx#upgrading-rehype-katex-beyond-recommended-version).
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
<summary>How are <code>remark-math</code> and <code>rehype-katex</code> different?</summary>
|
||||
|
||||
In case you are wondering how Remark and Rehype are different, here is a good example. `remark-math` operates on the Markdown AST, where it sees text like `$...$`, and all it does is transforms that to the JSX `<span class="math math-inline">...</span>` without doing too much with the content. This decouples the extraction of math formulae from their rendering, which means you can swap $\KaTeX$ out with other math renderers, like MathJax (with [`rehype-mathjax`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-mathjax)), just by replacing the Rehype plugin.
|
||||
In case you are wondering how Remark and Rehype are different, here is a good example. `remark-math` operates on the Markdown AST, where it sees text like `$...$`, and all it does is transform that to the JSX `<span class="math math-inline">...</span>` without doing too much with the content. This decouples the extraction of math formulae from their rendering, which means you can swap $\KaTeX$ out with other math renderers, like MathJax (with [`rehype-mathjax`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-mathjax)), just by replacing the Rehype plugin.
|
||||
|
||||
Next, the `rehype-katex` operates on the Hypertext AST where everything has been converted to HTML-like tags already. It traverses all the elements with `math` class, and uses $\KaTeX$ to parse and render the content to actual HTML.
|
||||
Next, the `rehype-katex` operates on the Hypertext AST where everything has been converted to HTML-like tags already. It traverses all the elements with `math` class and uses $\KaTeX$ to parse and render the content to actual HTML.
|
||||
|
||||
</details>
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ module.exports = {
|
|||
|
||||
Some plugins can be configured and accept their own options. In that case, use the `[plugin, pluginOptions]` syntax, like this:
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
|
|
@ -112,9 +112,9 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
You should check your plugin's documentation for options it supports.
|
||||
You should check your plugin's documentation for the options it supports.
|
||||
|
||||
## Creating new rehype/remark plugins
|
||||
## Creating new rehype/remark plugins {#creating-new-rehyperemark-plugins}
|
||||
|
||||
If there isn't an existing package that satisfies your customization need, you can create your own MDX plugin.
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ The writeup below is **not** meant to be a comprehensive guide to creating a plu
|
|||
|
||||
:::
|
||||
|
||||
For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate NPM package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` which operates on the AST.
|
||||
For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate NPM package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST.
|
||||
|
||||
```js "src/remark/section-prefix.js"
|
||||
const visit = require('unist-util-visit');
|
||||
|
|
@ -134,14 +134,10 @@ const plugin = (options) => {
|
|||
let number = 1;
|
||||
visit(ast, 'heading', (node) => {
|
||||
if (node.depth === 2 && node.children.length > 0) {
|
||||
if (node.children[0].type === 'text') {
|
||||
node.children[0].value = `Section ${number}. ${node.children[0].value}`;
|
||||
} else {
|
||||
node.children.unshift({
|
||||
type: 'text',
|
||||
value: `Section ${number}. `,
|
||||
});
|
||||
}
|
||||
node.children.unshift({
|
||||
type: 'text',
|
||||
value: `Section ${number}. `,
|
||||
});
|
||||
number++;
|
||||
}
|
||||
});
|
||||
|
|
@ -154,7 +150,7 @@ module.exports = plugin;
|
|||
|
||||
You can now import your plugin in `docusaurus.config.js` and use it just like an installed plugin!
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-next-line
|
||||
const sectionPrefix = require('./src/remark/section-prefix');
|
||||
|
||||
|
|
@ -173,11 +169,31 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
The `transformer` has a second parameter [`vfile`](https://github.com/vfile/vfile) which is useful if you need to access the current Markdown file's path.
|
||||
|
||||
```js
|
||||
const plugin = (options) => {
|
||||
const transformer = async (ast, vfile) => {
|
||||
ast.children.unshift({
|
||||
type: 'text',
|
||||
value: `The current file path is ${vfile.path}`,
|
||||
});
|
||||
};
|
||||
return transformer;
|
||||
};
|
||||
```
|
||||
|
||||
Our `transformImage` plugin uses this parameter, for example, to transform relative image references to `require()` calls.
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
The default plugins of Docusaurus would operate before the custom remark plugins, and that means the images or links have been converted to JSX with `require()` calls already. For example, in the example above, the table of contents generated is still the same even when all `h2` headings are now prefixed by `Section X.`, because the TOC-generating plugin is called before our custom plugin. If you need to process the MDAST before the default plugins do, use the `beforeDefaultRemarkPlugins` and `beforeDefaultRehypePlugins`.
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
|
|
@ -0,0 +1,465 @@
|
|||
---
|
||||
id: react
|
||||
title: MDX and React
|
||||
description: Using the power of React in Docusaurus Markdown documents, thanks to MDX
|
||||
slug: /markdown-features/react
|
||||
---
|
||||
|
||||
# MDX and React
|
||||
|
||||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import styles from './markdown-features-react.module.css';
|
||||
```
|
||||
|
||||
## Using JSX in Markdown {#using-jsx-in-markdown}
|
||||
|
||||
Docusaurus has built-in support for [MDX v1](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components.
|
||||
|
||||
:::note
|
||||
|
||||
While Docusaurus parses both `.md` and `.mdx` files using MDX, some of the syntaxes are treated slightly differently by third-party tools. For the most accurate parsing and better editor support, we recommend using the `.mdx` extension for files containing MDX syntax.
|
||||
|
||||
:::
|
||||
|
||||
To define any custom component within an MDX file, you have to export it.
|
||||
|
||||
```jsx
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
```
|
||||
|
||||
Notice how it renders both the markup from your React component and the Markdown syntax:
|
||||
|
||||
```mdx-code-block
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<BrowserWindow minHeight={240}>
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight>
|
||||
{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::caution MDX is JSX
|
||||
|
||||
Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
/* Instead of this: */
|
||||
<span style="background-color: red">Foo</span>
|
||||
/* Use this: */
|
||||
<span style={{backgroundColor: 'red'}}>Foo</span>
|
||||
```
|
||||
|
||||
This behavior is different from Docusaurus 1. See also [Migrating from v1 to v2](../../migration/migration-manual.md#convert-style-attributes-to-style-objects-in-mdx).
|
||||
|
||||
In addition, MDX is not [100% compatible with CommonMark](https://github.com/facebook/docusaurus/issues/3018). Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.
|
||||
|
||||
:::
|
||||
|
||||
### Importing components {#importing-components}
|
||||
|
||||
You can also import your own components defined in other files or third-party components installed via npm.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```md
|
||||
<!-- Docusaurus theme component -->
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
<!-- External component -->
|
||||
import Button from '@mui/material/Button';
|
||||
<!-- Custom component -->
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
The `@site` alias points to your website's directory, usually where the `docusaurus.config.js` file is. Using an alias instead of relative paths (`'../../src/components/BrowserWindow'`) saves you from updating import paths when moving files around, or when [versioning docs](../docs/versioning.md) and [translating](../../i18n/i18n-tutorial.md).
|
||||
|
||||
:::
|
||||
|
||||
While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate `.js` file when your component involves complex JS logic:
|
||||
|
||||
```jsx title="src/components/Highlight.js"
|
||||
export default function Highlight({children, color}) {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```md title="markdown-file.mdx"
|
||||
import Highlight from '@site/src/components/Highlight';
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight>
|
||||
```
|
||||
|
||||
Check out the [MDX docs](https://mdxjs.com/) to see what other fancy stuff you can do with MDX.
|
||||
|
||||
### Markdown and JSX interoperability {#markdown-and-jsx-interoperability}
|
||||
|
||||
Docusaurus v2 is using MDX v1, which has a lot of known cases where the content fails to be correctly parsed as Markdown. Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.
|
||||
|
||||
````mdx-code-block
|
||||
<details>
|
||||
|
||||
<summary>Samples of parsing failures</summary>
|
||||
|
||||
**A paragraph starting with a JSX tag will be seen entirely as a JSX string:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Use JSX for the rest of the line, or prefix the line with some plain text:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
|
||||
|
||||
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
|
||||
|
||||
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Markdown within a JSX tag never works:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>**Bold doesn't work**</span>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>**Bold doesn't work**</span>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Use JSX within JSX tag, or move the Markdown to the outer layer:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}><b>Bold now works</b></span>
|
||||
|
||||
**<span style={{color: 'red'}}>Bold now works</span>**
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}><b>Bold now works</b></span>
|
||||
|
||||
**<span style={{color: 'red'}}>Bold now works</span>**
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Text immediately below a JSX tag will be seen as JSX text:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
**Bold still doesn't work**
|
||||
</div>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<div style={{color: 'red'}}>
|
||||
**Bold still doesn't work**
|
||||
</div>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Add an empty new line:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
**Bold now works**
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
**Bold now works**
|
||||
|
||||
</div>
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Markdown text indented by four spaces will be seen as a code block:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
You may think I'm just some text...
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
You may think I'm just some text...
|
||||
|
||||
</div>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Don't indent:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
Now I'm actually just text
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
Now I'm actually just text
|
||||
|
||||
</div>
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</details>
|
||||
````
|
||||
|
||||
## Importing code snippets {#importing-code-snippets}
|
||||
|
||||
You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/). In order to use `raw-loader`, you first need to install it in your project:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save raw-loader
|
||||
```
|
||||
|
||||
Now you can import code snippets from another file as it is:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!./myComponent';
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```mdx-code-block
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponent';
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
<br />
|
||||
```
|
||||
|
||||
See [using code blocks in JSX](./markdown-features-code-blocks.mdx#usage-in-jsx) for more details of the `<CodeBlock>` component.
|
||||
|
||||
:::note
|
||||
|
||||
You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
This feature is experimental and might be subject to breaking API changes in the future.
|
||||
|
||||
:::
|
||||
|
||||
## Importing Markdown {#importing-markdown}
|
||||
|
||||
You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages.
|
||||
|
||||
By convention, using the **`_` filename prefix** will not create any doc page and means the markdown file is a **"partial"**, to be imported by other files.
|
||||
|
||||
```md title="_markdown-partial-example.mdx"
|
||||
<span>Hello {props.name}</span>
|
||||
|
||||
This is text some content from `_markdown-partial-example.mdx`.
|
||||
```
|
||||
|
||||
```jsx title="someOtherDoc.mdx"
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<PartialExample name="Sebastien" />;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<BrowserWindow>
|
||||
<PartialExample name="Sebastien" />
|
||||
</BrowserWindow>
|
||||
|
||||
<br />
|
||||
```
|
||||
|
||||
This way, you can reuse content among multiple pages and avoid duplicating materials.
|
||||
|
||||
:::caution
|
||||
|
||||
The table of contents does not currently contain the imported Markdown headings. This is a technical limitation that we are trying to solve ([issue](https://github.com/facebook/docusaurus/issues/3915)).
|
||||
|
||||
:::
|
||||
|
||||
## Available exports {#available-exports}
|
||||
|
||||
Within the MDX page, the following variables are available as globals:
|
||||
|
||||
- `frontMatter`: the front matter as a record of string keys and values;
|
||||
- `toc`: the table of contents, as a tree of headings. See also [Inline TOC](./markdown-features-inline-toc.mdx) for a more concrete use-case.
|
||||
- `contentTitle`: the Markdown title, which is the first `h1` heading in the Markdown text. It's `undefined` if there isn't one (e.g. title specified in the front matter).
|
||||
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.wrappingBlock {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wrappingBlock code[class^='codeBlockLines'] {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
|
@ -128,15 +128,15 @@ It is possible to only render the default tab with `<Tabs lazy />`.
|
|||
|
||||
:::
|
||||
|
||||
## Displaying a default tab
|
||||
## Displaying a default tab {#displaying-a-default-tab}
|
||||
|
||||
The first tab is displayed by default, and to override this behavior, you can specify a default tab by adding `default` to one of the tab items. You can also set the `defaultValue` prop of the `Tabs` component to the label value of your choice. For example, in the example above, either setting `default` for the `value="apple"` tab or setting `defaultValue="apple"` for the tabs forces the "Apple" tab to be open by default.
|
||||
|
||||
Docusaurus will throw an error if a `defaultValue` is provided for the `Tabs` but it refers to an non-existing value. If you want none of the tabs to be shown by default, use `defaultValue={null}`.
|
||||
Docusaurus will throw an error if a `defaultValue` is provided for the `Tabs` but it refers to a non-existing value. If you want none of the tabs to be shown by default, use `defaultValue={null}`.
|
||||
|
||||
## Syncing tab choices {#syncing-tab-choices}
|
||||
|
||||
You may want choices of the same kind of tabs to sync with each other. For example, you might want to provide different instructions for users on Windows vs users on macOS, and you want to changing all OS-specific instructions tabs in one click. To achieve that, you can give all related tabs the same `groupId` prop. Note that doing this will persist the choice in `localStorage` and all `<Tab>` instances with the same `groupId` will update automatically when the value of one of them is changed. Note that `groupID` are globally-namespaced.
|
||||
You may want choices of the same kind of tabs to sync with each other. For example, you might want to provide different instructions for users on Windows vs users on macOS, and you want to change all OS-specific instructions tabs in one click. To achieve that, you can give all related tabs the same `groupId` prop. Note that doing this will persist the choice in `localStorage` and all `<Tab>` instances with the same `groupId` will update automatically when the value of one of them is changed. Note that group IDs are globally namespaced.
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
|
|
@ -167,7 +167,7 @@ You may want choices of the same kind of tabs to sync with each other. For examp
|
|||
<br/>
|
||||
```
|
||||
|
||||
For all tab groups that have the same `groupId`, the possible values do not need to be the same. If one tab group with chooses an value that does not exist in another tab group with the same `groupId`, the tab group with the missing value won't change its tab. You can see that from the following example. Try to select Linux, and the above tab groups doesn't change.
|
||||
For all tab groups that have the same `groupId`, the possible values do not need to be the same. If one tab group is chosen a value that does not exist in another tab group with the same `groupId`, the tab group with the missing value won't change its tab. You can see that from the following example. Try to select Linux, and the above tab groups don't change.
|
||||
|
||||
```jsx
|
||||
<Tabs groupId="operating-systems">
|
||||
|
|
@ -195,7 +195,7 @@ For all tab groups that have the same `groupId`, the possible values do not need
|
|||
|
||||
---
|
||||
|
||||
Tab choices with different `groupId`s will not interfere with each other:
|
||||
Tab choices with different group IDs will not interfere with each other:
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
|
|
@ -227,7 +227,7 @@ Tab choices with different `groupId`s will not interfere with each other:
|
|||
|
||||
## Customizing tabs {#customizing-tabs}
|
||||
|
||||
You might want to customize the appearance of certain set of tabs. To do that you can pass the string in `className` prop and the specified CSS class will be added to the `Tabs` component:
|
||||
You might want to customize the appearance of a certain set of tabs. You can pass the string in `className` prop, and the specified CSS class will be added to the `Tabs` component:
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
|
|
@ -248,7 +248,7 @@ You might want to customize the appearance of certain set of tabs. To do that yo
|
|||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### Customizing tab headings
|
||||
### Customizing tab headings {#customizing-tab-headings}
|
||||
|
||||
You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`.
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# What's next?
|
||||
|
||||
Congratulations! You have understood most core features of Docusaurus now. You have:
|
||||
|
||||
- [Used the pages plugin](./creating-pages.md) to create a standalone React / Markdown page
|
||||
- [Used the docs plugin](./docs/docs-introduction.md) to create documentation pages. This includes [configuring the sidebar](./docs/sidebar/index.md), and even [versioning](./docs/versioning.md)
|
||||
- [Used the blog plugin](../blog.mdx) to create a fully featured blog
|
||||
- Tried your hands on [a range of Markdown features](./markdown-features/markdown-features-intro.mdx), which are useful for all content plugins
|
||||
- [Used stylesheets](../styling-layout.md) to customize your site's appearance
|
||||
- [Put images and other assets](../static-assets.md) in your pages
|
||||
- [Added search](../search.md) to your site
|
||||
- Understood how [browser support](../browser-support.md) and [SEO](../seo.md) are done through standard Docusaurus APIs
|
||||
- Learned about how [individual plugins](../using-plugins.md) are installed and configured
|
||||
- [Deployed](../deployment.mdx) your site to a content host
|
||||
- [Internationalized](../i18n/i18n-tutorial.md) your site to include multiple languages
|
||||
|
||||
At this point, you probably have a big `docusaurus.config.js` already😄 However, you haven't written much code yet! Most of the features are implemented through calling encapsulated Docusaurus APIs. As you continue your journey, you can take three paths:
|
||||
|
||||
- Learn more advanced Docusaurus concepts. This will help you gain a deeper understand of what the APIs do.
|
||||
- Read about [all existing APIs](../docusaurus-core.md). Many of them have not been covered in the Guides!
|
||||
- Learn to [develop a plugin](../api/plugin-methods/README.md) to extend the functionality of your site.
|
||||
|
|
@ -13,7 +13,7 @@ We document the usage of [Crowdin](https://crowdin.com/), as **one** possible **
|
|||
|
||||
:::caution
|
||||
|
||||
This is **not an endorsement of Crowdin** as the unique choice to translate a Docusaurus site, but it is successfully used by Facebook to translate documentation projects such as [Jest](https://jestjs.io/), [Docusaurus](https://docusaurus.io/) and [ReasonML](https://reasonml.github.io/).
|
||||
This is **not an endorsement of Crowdin** as the unique choice to translate a Docusaurus site, but it is successfully used by Facebook to translate documentation projects such as [Jest](https://jestjs.io/), [Docusaurus](https://docusaurus.io/), and [ReasonML](https://reasonml.github.io/).
|
||||
|
||||
Refer to the **[Crowdin documentation](https://support.crowdin.com/)** and **[Crowdin support](mailto:support@crowdin.com)** for help.
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ Refer to the **[Crowdin documentation](https://support.crowdin.com/)** and **[Cr
|
|||
|
||||
:::tip
|
||||
|
||||
Use this **[community-driven GitHub issue](https://github.com/facebook/docusaurus/discussions/4052)** to discuss anything related to Docusaurus + Crowdin.
|
||||
Use this **[community-driven GitHub discussion](https://github.com/facebook/docusaurus/discussions/4052)** to discuss anything related to Docusaurus + Crowdin.
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ export default function Home() {
|
|||
|
||||
Sign up on [Crowdin](https://crowdin.com/), and create a project.
|
||||
|
||||
Use English as source language, and French as target language.
|
||||
Use English as the source language, and French as the target language.
|
||||
|
||||

|
||||
|
||||
|
|
@ -120,25 +120,18 @@ Create `crowdin.yml` in `website`:
|
|||
|
||||
```yml title="crowdin.yml"
|
||||
project_id: '123456'
|
||||
api_token_env: 'CROWDIN_PERSONAL_TOKEN'
|
||||
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||
preserve_hierarchy: true
|
||||
files: [
|
||||
# JSON translation files
|
||||
{
|
||||
source: '/i18n/en/**/*',
|
||||
translation: '/i18n/%two_letters_code%/**/%original_file_name%',
|
||||
},
|
||||
# Docs Markdown files
|
||||
{
|
||||
source: '/docs/**/*',
|
||||
translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%',
|
||||
},
|
||||
# Blog Markdown files
|
||||
{
|
||||
source: '/blog/**/*',
|
||||
translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%',
|
||||
},
|
||||
]
|
||||
files:
|
||||
# JSON translation files
|
||||
- source: /i18n/en/**/*
|
||||
translation: /i18n/%two_letters_code%/**/%original_file_name%
|
||||
# Docs Markdown files
|
||||
- source: /docs/**/*
|
||||
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
|
||||
# Blog Markdown files
|
||||
- source: /blog/**/*
|
||||
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%
|
||||
```
|
||||
|
||||
Crowdin has its own syntax for declaring source/translation paths:
|
||||
|
|
@ -187,9 +180,9 @@ You should **not commit** it, and it may be a good idea to create a dedicated **
|
|||
|
||||
### Install the Crowdin CLI {#install-the-crowdin-cli}
|
||||
|
||||
This tutorial use the CLI in version `3.5.2`, but we expect `3.x` releases to keep working.
|
||||
This tutorial uses the CLI version `3.5.2`, but we expect `3.x` releases to keep working.
|
||||
|
||||
Install the Crowdin CLI as a NPM package to your Docusaurus site:
|
||||
Install the Crowdin CLI as an NPM package to your Docusaurus site:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @crowdin/cli@3
|
||||
|
|
@ -253,7 +246,7 @@ Translate some Markdown files.
|
|||
|
||||
Use `Hide String` to make sure translators **don't translate things that should not be**:
|
||||
|
||||
- Frontmatter: `id`, `slug`, `tags` ...
|
||||
- Front matter: `id`, `slug`, `tags` ...
|
||||
- Admonitions: `:::`, `:::note`, `:::tip` ...
|
||||
|
||||

|
||||
|
|
@ -298,13 +291,13 @@ Make sure that your website is now translated in French at `http://localhost:300
|
|||
|
||||
### Automate with CI {#automate-with-ci}
|
||||
|
||||
We will configure the CI to **download the Crowdin translations at build time**, and keep them outside of Git.
|
||||
We will configure the CI to **download the Crowdin translations at build time** and keep them outside of Git.
|
||||
|
||||
Add `website/i18n` to `.gitignore`.
|
||||
|
||||
Set the `CROWDIN_PERSONAL_TOKEN` env variable on your CI.
|
||||
|
||||
Create a npm script to `sync` Crowdin (extract sources, upload sources, download translations):
|
||||
Create an npm script to `sync` Crowdin (extract sources, upload sources, download translations):
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
|
|
@ -342,17 +335,13 @@ Crowdin **does not support officially MDX**, but they added **support for the `.
|
|||
|
||||
#### MDX problems {#mdx-problems}
|
||||
|
||||
Crowdin thinks the JSX syntax is embedded HTML, and can mess-up with the JSX markup when you download the translations, leading to a site that fails to build due to invalid JSX.
|
||||
Crowdin thinks that the JSX syntax is embedded HTML and can mess up with the JSX markup when you download the translations, leading to a site that fails to build due to invalid JSX.
|
||||
|
||||
Simple JSX fragments using simple string props like `<Username name="Sebastien"/>` will work fine.
|
||||
|
||||
More complex JSX fragments using object/array props like `<User person={{name: "Sebastien"}}/>` are more likely to fail due to a syntax that does not look like HTML.
|
||||
Simple JSX fragments using simple string props like `<Username name="Sebastien"/>` will work fine; more complex JSX fragments using object/array props like `<User person={{name: "Sebastien"}}/>` are more likely to fail due to a syntax that does not look like HTML.
|
||||
|
||||
#### MDX solutions {#mdx-solutions}
|
||||
|
||||
We recommend moving the complex embedded JSX code as separate standalone components.
|
||||
|
||||
We also added a `mdx-code-block` escape hatch syntax:
|
||||
We recommend extracting the complex embedded JSX code as separate standalone components. We also added an `mdx-code-block` escape hatch syntax:
|
||||
|
||||
`````text
|
||||
# How to deploy Docusaurus
|
||||
|
|
@ -430,7 +419,7 @@ When your sources are refactored, you should use the Crowdin UI to **update your
|
|||
|
||||
Crowdin has multiple VCS integrations for [GitHub](https://support.crowdin.com/github-integration/), GitLab, Bitbucket.
|
||||
|
||||
:::warning
|
||||
:::warning TL;DR
|
||||
|
||||
We recommend avoiding them.
|
||||
|
||||
|
|
@ -454,15 +443,15 @@ Crowdin has an [In-Context localization](https://support.crowdin.com/in-context-
|
|||
|
||||
Unfortunately, it does not work yet for technical reasons, but we have good hope it can be solved.
|
||||
|
||||
Crowdin replaces markdown strings with technical ids such as `crowdin:id12345`, but it does so too aggressively, including hidden strings, and mess-up with the frontmatter, admonitions, jsx...
|
||||
Crowdin replaces markdown strings with technical ids such as `crowdin:id12345`, but it does so too aggressively, including hidden strings, and messes up with front matter, admonitions, JSX...
|
||||
|
||||
:::
|
||||
|
||||
### Localize edit urls {#localize-edit-urls}
|
||||
### Localize edit URLs {#localize-edit-urls}
|
||||
|
||||
When the user is browsing a page at `/fr/doc1`, the edit button will link by default to the unlocalized doc at `website/docs/doc1.md`.
|
||||
|
||||
You may prefer the edit button to link to the Crowdin interface instead, and can use the `editUrl` function to customize the edit urls on a per-locale basis.
|
||||
You may prefer the edit button to link to the Crowdin interface instead by using the `editUrl` function to customize the edit URLs on a per-locale basis.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
const DefaultLocale = 'en';
|
||||
|
|
@ -4,22 +4,22 @@ title: i18n - Using git
|
|||
slug: /i18n/git
|
||||
---
|
||||
|
||||
A **possible translation strategy** is to **version control the translation files** to Git (or any other [VCS](https://en.wikipedia.org/wiki/Version_control)).
|
||||
A **possible translation strategy** is to **version control the translation files** with Git (or any other [VCS](https://en.wikipedia.org/wiki/Version_control)).
|
||||
|
||||
## Tradeoffs {#tradeoffs}
|
||||
|
||||
This strategy has advantages:
|
||||
|
||||
- **Easy to get started**: just add the `i18n` folder to Git
|
||||
- **Easy to get started**: just commit the `i18n` folder to Git
|
||||
- **Easy for developers**: Git, GitHub and pull requests are mainstream developer tools
|
||||
- **Free** (or without any additional cost, assuming you already use Git)
|
||||
- **Low friction**: does not require signing-up to an external tool
|
||||
- **Low friction**: does not require signing up to an external tool
|
||||
- **Rewarding**: contributors are happy to have a nice contribution history
|
||||
|
||||
Using Git also present some shortcomings:
|
||||
|
||||
- **Hard for non-developers**: they do not master Git and pull-requests
|
||||
- **Hard for professional translations**: they are used to SaaS translation softwares and advanced features
|
||||
- **Hard for professional translators**: they are used to SaaS translation softwares and advanced features
|
||||
- **Hard to maintain**: you have to keep the translated files **in sync** with the untranslated files
|
||||
|
||||
:::note
|
||||
|
|
@ -30,7 +30,7 @@ Refer to the [Docusaurus i18n RFC](https://github.com/facebook/docusaurus/issues
|
|||
|
||||
:::
|
||||
|
||||
## Git tutorial {#git-tutorial}
|
||||
## Initialization {#initialization}
|
||||
|
||||
This is a walk-through of using Git to translate a newly initialized English Docusaurus website into French, and assume you already followed the [i18n tutorial](./i18n-tutorial.md).
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ Use the `--messagePrefix '(fr) '` option to make the untranslated strings stand
|
|||
|
||||
Copy your untranslated Markdown files to the French folder:
|
||||
|
||||
```
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current
|
||||
cp -r docs/** i18n/fr/docusaurus-plugin-content-docs/current
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ npm run build -- --locale fr
|
|||
|
||||
Follow the same process for each locale you need to support.
|
||||
|
||||
## Maintain the translations {#maintain-the-translations}
|
||||
## Maintenance {#maintenance}
|
||||
|
||||
Keeping translated files **consistent** with the originals **can be challenging**, in particular for Markdown documents.
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ To help you maintain the JSON translation files, it is possible to run again the
|
|||
npm run write-translations -- --locale fr
|
||||
```
|
||||
|
||||
New translation will be appended, and existing ones will not be overridden.
|
||||
New translations will be appended, and existing ones will not be overridden.
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ Reset your translations with the `--override` option.
|
|||
|
||||
:::
|
||||
|
||||
### Localize edit urls {#localize-edit-urls}
|
||||
### Localize edit URLs {#localize-edit-urls}
|
||||
|
||||
When the user is browsing a page at `/fr/doc1`, the edit button will link by default to the unlocalized doc at `website/docs/doc1.md`.
|
||||
|
||||
|
|
@ -20,11 +20,11 @@ The goals of the Docusaurus i18n system are:
|
|||
- **Flexible translation workflows**: use Git (monorepo, forks, or submodules), SaaS software, FTP
|
||||
- **Flexible deployment options**: single, multiple domains, or hybrid
|
||||
- **Modular**: allow plugin authors to provide i18n support
|
||||
- **Low-overhead runtime**: documentation is mostly static and does not require a heavy JS library or polyfills
|
||||
- **Low-overhead runtime**: documentation is mostly static and does not require heavy JS libraries or polyfills
|
||||
- **Scalable build-times**: allow building and deploying localized sites independently
|
||||
- **Localize assets**: an image of your site might contain text that should be translated
|
||||
- **No coupling**: not forced to use any SaaS, yet integrations are possible
|
||||
- **Easy to use with [Crowdin](https://crowdin.com/)**: multiple Docusaurus v1 sites use Crowdin, and should be able to migrate to v2
|
||||
- **Easy to use with [Crowdin](https://crowdin.com/)**: a lot of Docusaurus v1 sites use Crowdin and should be able to migrate to v2
|
||||
- **Good SEO defaults**: we set useful SEO headers like [`hreflang`](https://developers.google.com/search/docs/advanced/crawling/localized-versions) for you
|
||||
- **RTL support**: locales reading right-to-left (Arabic, Hebrew, etc.) are supported and easy to implement
|
||||
- **Default translations**: classic theme labels are translated for you in [many languages](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-translations/locales)
|
||||
|
|
@ -33,7 +33,7 @@ The goals of the Docusaurus i18n system are:
|
|||
|
||||
We don't provide support for:
|
||||
|
||||
- **Automatic locale detection**: opinionated, and best done on the [server](../deployment.mdx)
|
||||
- **Automatic locale detection**: opinionated, and best done on the [server (your hosting provider)](../deployment.mdx)
|
||||
- **Translation SaaS software**: you are responsible to understand the external tools of your choice
|
||||
- **Translation of slugs**: technically complicated, little SEO value
|
||||
|
||||
|
|
@ -44,12 +44,12 @@ We don't provide support for:
|
|||
Overview of the workflow to create a translated Docusaurus website:
|
||||
|
||||
1. **Configure**: declare the default locale and alternative locales in `docusaurus.config.js`
|
||||
1. **Translate**: put the translation files at the correct filesystem location
|
||||
1. **Deploy**: build and deploy your site using a single or multi-domain strategy
|
||||
2. **Translate**: put the translation files at the correct filesystem location
|
||||
3. **Deploy**: build and deploy your site using a single or multi-domain strategy
|
||||
|
||||
### Translation files {#translation-files}
|
||||
|
||||
You will have to work with 2 kind of translation files.
|
||||
You will work with three kinds of translation files.
|
||||
|
||||
#### Markdown files {#markdown-files}
|
||||
|
||||
|
|
@ -61,9 +61,9 @@ Markdown and MDX documents are translated as a whole, to fully preserve the tran
|
|||
|
||||
JSON is used to translate:
|
||||
|
||||
- your React code: using the `<Translate>` component
|
||||
- your theme: the navbar, footer
|
||||
- your plugins: the docs sidebar category labels
|
||||
- Your React code: standalone React pages in `src/pages`, or other components
|
||||
- Layout labels provided through `themeConfig`: navbar, footer
|
||||
- Layout labels provided through plugin options: docs sidebar category labels, blog sidebar title...
|
||||
|
||||
The JSON format used is called **Chrome i18n**:
|
||||
|
||||
|
|
@ -83,7 +83,11 @@ The JSON format used is called **Chrome i18n**:
|
|||
The choice was made for 2 reasons:
|
||||
|
||||
- **Description attribute**: to help translators with additional context
|
||||
- **Widely supported**: [Chrome extensions](https://developer.chrome.com/docs/extensions/mv2/i18n-messages/), [Crowdin](https://support.crowdin.com/file-formats/chrome-json/), [Transifex](https://docs.transifex.com/formats/chrome-json), [Phrase](https://help.phrase.com/help/chrome-json-messages), [Applanga](https://www.applanga.com/docs/formats/chrome_i18n_json)
|
||||
- **Widely supported**: [Chrome extensions](https://developer.chrome.com/docs/extensions/mv2/i18n-messages/), [Crowdin](https://support.crowdin.com/file-formats/chrome-json/), [Transifex](https://docs.transifex.com/formats/chrome-json), [Phrase](https://help.phrase.com/help/chrome-json-messages), [Applanga](https://www.applanga.com/docs/formats/chrome_i18n_json), etc.
|
||||
|
||||
#### Data files {#data-files}
|
||||
|
||||
Some plugins may read from external data files that are localized as a whole. For example, the blog plugin uses an [`authors.yml`](../blog.mdx#global-authors) file that can be translated by creating a copy under `i18n/[locale]/docusaurus-plugin-content-blog/authors.yml`.
|
||||
|
||||
### Translation files location {#translation-files-location}
|
||||
|
||||
|
|
@ -106,33 +110,25 @@ Translating a very simple Docusaurus site in French would lead to the following
|
|||
```bash
|
||||
website/i18n
|
||||
└── fr
|
||||
├── code.json
|
||||
├── code.json # Any text label present in the React code
|
||||
│ # Includes text labels from the themes' code
|
||||
├── docusaurus-plugin-content-blog # translation data the blog plugin needs
|
||||
│ └── 2020-01-01-hello.md
|
||||
│
|
||||
├── docusaurus-plugin-content-blog
|
||||
│ └── 2020-01-01-hello.md
|
||||
├── docusaurus-plugin-content-docs # translation data the docs plugin needs
|
||||
│ ├── current
|
||||
│ │ ├── doc1.md
|
||||
│ │ └── doc2.mdx
|
||||
│ └── current.json
|
||||
│
|
||||
├── docusaurus-plugin-content-docs
|
||||
│ ├── current #
|
||||
│ │ ├── doc1.md
|
||||
│ │ └── doc2.mdx
|
||||
│ └── current.json
|
||||
│
|
||||
└── docusaurus-theme-classic
|
||||
├── footer.json
|
||||
└── navbar.json
|
||||
└── docusaurus-theme-classic # translation data the classic theme needs
|
||||
├── footer.json # Text labels in your footer theme config
|
||||
└── navbar.json # Text labels in your navbar theme config
|
||||
```
|
||||
|
||||
The JSON files are initialized with the [`docusaurus write-translations`](../cli.md#docusaurus-write-translations-sitedir) CLI command.
|
||||
The JSON files are initialized with the [`docusaurus write-translations`](../cli.md#docusaurus-write-translations-sitedir) CLI command. Each plugin sources its own translated content under the corresponding folder, while the `code.json` file defines all text labels used in the React code.
|
||||
|
||||
The `code.json` file is extracted from React components using the `<Translate>` API.
|
||||
|
||||
:::info
|
||||
|
||||
Notice that the `docusaurus-plugin-content-docs` plugin has a `current` subfolder and a `current.json` file, useful for the **docs versioning feature**.
|
||||
|
||||
:::
|
||||
|
||||
Each content plugin or theme is different, and **define its own translation files location**:
|
||||
Each content plugin or theme is different, and **defines its own translation files location**:
|
||||
|
||||
- [Docs i18n](../api/plugins/plugin-content-docs.md#i18n)
|
||||
- [Blog i18n](../api/plugins/plugin-content-blog.md#i18n)
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
---
|
||||
id: tutorial
|
||||
title: i18n - Tutorial
|
||||
slug: /i18n/tutorial
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
This tutorial will walk you through the basics of the **Docusaurus i18n system**.
|
||||
|
||||
We will add **French** translations to a **newly initialized English Docusaurus website**.
|
||||
|
||||
Initialize a new site with `npx create-docusaurus@latest website classic` (like [this one](https://github.com/facebook/docusaurus/tree/main/examples/classic)).
|
||||
|
||||
## Configure your site {#configure-your-site}
|
||||
|
||||
Modify `docusaurus.config.js` to add the i18n support for the French language.
|
||||
|
||||
### Site configuration {#site-configuration}
|
||||
|
||||
Use the [site i18n configuration](./../api/docusaurus.config.js.md#i18n) to declare the i18n locales:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'fr', 'fa'],
|
||||
localeConfigs: {
|
||||
en: {
|
||||
htmlLang: 'en-GB',
|
||||
},
|
||||
// You can omit a locale (e.g. fr) if you don't need to override the defaults
|
||||
fa: {
|
||||
direction: 'rtl',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
The locale names are used for the translation files' locations, as well as your translated locales' base URL. When building all locales, only the default locale will have its name omitted in the base URL.
|
||||
|
||||
Docusaurus uses the locale names to provide **sensible defaults**: the `<html lang="...">` attribute, locale label, calendar format, etc. You can customize these defaults with the `localeConfigs`.
|
||||
|
||||
### Theme configuration {#theme-configuration}
|
||||
|
||||
Add a **navbar item** of type `localeDropdown` so that users can select the locale they want:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'localeDropdown',
|
||||
position: 'left',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Start your site {#start-your-site}
|
||||
|
||||
Start your localized site in dev mode, using the locale of your choice:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run start -- --locale fr
|
||||
```
|
||||
|
||||
Your site is accessible at **`http://localhost:3000/fr/`**.
|
||||
|
||||
We haven't provided any translation yet, so the site is mostly untranslated.
|
||||
|
||||
:::tip
|
||||
|
||||
Docusaurus provides **default translations** for generic theme labels, such as "Next" and "Previous" for the pagination.
|
||||
|
||||
Please help us complete those **[default translations](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-translations/locales)**.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Each locale is a **distinct standalone single-page application**: it is not possible to start the Docusaurus sites in all locales at the same time.
|
||||
|
||||
:::
|
||||
|
||||
## Translate your site {#translate-your-site}
|
||||
|
||||
All translation data for the French locale is stored in `website/i18n/fr`. Each plugin sources its own translated content under the corresponding folder, while the `code.json` file defines all text labels used in the React code.
|
||||
|
||||
:::note
|
||||
|
||||
After copying files around, restart your site with `npm run start -- --locale fr`. Hot-reload will work better when editing existing files.
|
||||
|
||||
:::
|
||||
|
||||
### Translate your React code {#translate-your-react-code}
|
||||
|
||||
For any React code you've written yourself: React pages, React components, etc., you will use the [**translation APIs**](../docusaurus-core.md#translate).
|
||||
|
||||
Locate all text labels in your React code that will be visible to your users, and mark them with the translation APIs. There are two kinds of APIs:
|
||||
|
||||
- The `<Translate>` component wraps a string as a JSX component;
|
||||
- The `translate()` callback takes a message and returns a string.
|
||||
|
||||
Use the one that better fits the context semantically. For example, the `<Translate>` can be used as React children, while for props that expect a string, the callback can be used.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="Before">
|
||||
|
||||
```jsx title="src/pages/index.js"
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout>
|
||||
{/* highlight-next-line */}
|
||||
<h1>Welcome to my website</h1>
|
||||
<main>
|
||||
{/* highlight-start */}
|
||||
You can also visit my
|
||||
<Link to="https://docusaurus.io/blog">blog</Link>
|
||||
{/* highlight-end */}
|
||||
<img
|
||||
src="/img/home.png"
|
||||
// highlight-next-line
|
||||
alt="Home icon"
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="After">
|
||||
|
||||
```jsx title="src/pages/index.js"
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
// highlight-next-line
|
||||
import Translate, {translate} from '@docusaurus/Translate';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>
|
||||
{/* highlight-next-line */}
|
||||
<Translate>Welcome to my website</Translate>
|
||||
</h1>
|
||||
<main>
|
||||
{/* highlight-start */}
|
||||
<Translate
|
||||
id="homepage.visitMyBlog"
|
||||
description="The homepage message to ask the user to visit my blog"
|
||||
values={{
|
||||
blogLink: (
|
||||
<Link to="https://docusaurus.io/blog">
|
||||
<Translate
|
||||
id="homepage.visitMyBlog.linkLabel"
|
||||
description="The label for the link to my blog">
|
||||
blog
|
||||
</Translate>
|
||||
</Link>
|
||||
),
|
||||
}}>
|
||||
{'You can also visit my {blogLink}'}
|
||||
</Translate>
|
||||
{/* highlight-end */}
|
||||
|
||||
<img
|
||||
src="/img/home.png"
|
||||
alt={
|
||||
// highlight-start
|
||||
translate({
|
||||
message: 'Home icon',
|
||||
description: 'The homepage icon alt message',
|
||||
})
|
||||
// highlight-end
|
||||
}
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info
|
||||
|
||||
Docusaurus provides a **very small and lightweight translation runtime** on purpose, and only supports basic [placeholders interpolation](../docusaurus-core.md#interpolate), using a subset of the [ICU Message Format](https://formatjs.io/docs/core-concepts/icu-syntax/).
|
||||
|
||||
Most documentation websites are generally **static** and don't need advanced i18n features (**plurals**, **genders**, etc.). Use a library like [react-intl](https://www.npmjs.com/package/react-intl) for more advanced use-cases.
|
||||
|
||||
:::
|
||||
|
||||
The `docusaurus write-translations` command will statically analyze all React code files used in your site, extract calls to these APIs, and aggregate them in the `code.json` file. The translation files will be stored as maps from IDs to translation message objects (including the translated label and the description of the label). In your calls to the translation APIs (`<Translate>` or `translate()`), you need to specify either the default untranslated message or the ID, in order for Docusaurus to correctly correlate each translation entry to the API call.
|
||||
|
||||
:::caution text labels must be static
|
||||
|
||||
The `docusaurus write-translations` command only does **static analysis** of your code. It doesn't actually run your site. Therefore, dynamic messages can't be extracted, as the message is an _expression_, not a _string_:
|
||||
|
||||
```tsx
|
||||
const items = [
|
||||
{id: 1, title: 'Hello'},
|
||||
{id: 2, title: 'World'},
|
||||
]
|
||||
|
||||
function ItemsList() {
|
||||
return (
|
||||
<ul>
|
||||
{/* DON'T DO THIS: doesn't work with the write-translations command */}
|
||||
{items.map((item) => (
|
||||
<li key={item.id}>
|
||||
<Translate>{item.title}</Translate>
|
||||
</li>
|
||||
))}
|
||||
<ul>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
This still behaves correctly at runtime. However, in the future, we may provide a "no-runtime" mechanism, allowing the translations to be directly inlined in the React code through Babel transformations, instead of calling the APIs at runtime. Therefore, to be future-proof, you should always prefer statically analyzable messages. For example, we can refactor the code above to:
|
||||
|
||||
```tsx
|
||||
const items = [
|
||||
{id: 1, title: <Translate>Hello</Translate>},
|
||||
{id: 2, title: <Translate>World</Translate>},
|
||||
]
|
||||
|
||||
function ItemsList() {
|
||||
return (
|
||||
<ul>
|
||||
{/* The titles are now already translated when rendering! */}
|
||||
{items.map((item) => (
|
||||
<li key={item.id}>{item.title}</li>
|
||||
))}
|
||||
<ul>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
You can see the calls to the translation APIs as purely _markers_ that tell Docusaurus that "here's a text label to be replaced with a translated message".
|
||||
|
||||
:::
|
||||
|
||||
### Translate plugin data {#translate-plugin-data}
|
||||
|
||||
JSON translation files are used for everything that is interspersed in your code:
|
||||
|
||||
- React code, including the translated labels you have marked above
|
||||
- Navbar and footer labels in theme config
|
||||
- Docs sidebar category labels in `sidebars.js`
|
||||
- Blog sidebar title in plugin options
|
||||
- ...
|
||||
|
||||
Run the [write-translations](../cli.md#docusaurus-write-translations-sitedir) command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run write-translations -- --locale fr
|
||||
```
|
||||
|
||||
It will extract and initialize the JSON translation files that you need to translate. The `code.json` file at the root includes all translation API calls extracted from the source code, which could either be written by you or provided by the themes, some of which may already be translated by default.
|
||||
|
||||
```json title="i18n/fr/code.json"
|
||||
{
|
||||
// No ID for the <Translate> component: the default message is used as ID
|
||||
"Welcome to my website": {
|
||||
"message": "Welcome to my website"
|
||||
},
|
||||
"home.visitMyBlog": {
|
||||
"message": "You can also visit my {blog}",
|
||||
"description": "The homepage message to ask the user to visit my blog"
|
||||
},
|
||||
"homepage.visitMyBlog.linkLabel": {
|
||||
"message": "Blog",
|
||||
"description": "The label for the link to my blog"
|
||||
},
|
||||
"Home icon": {
|
||||
"message": "Home icon",
|
||||
"description": "The homepage icon alt message"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Plugins and themes will also write their own JSON translation files, such as:
|
||||
|
||||
```json title="i18n/fr/docusaurus-theme-classic/navbar.json"
|
||||
{
|
||||
"title": {
|
||||
"message": "My Site",
|
||||
"description": "The title in the navbar"
|
||||
},
|
||||
"item.label.Docs": {
|
||||
"message": "Docs",
|
||||
"description": "Navbar item with label Docs"
|
||||
},
|
||||
"item.label.Blog": {
|
||||
"message": "Blog",
|
||||
"description": "Navbar item with label Blog"
|
||||
},
|
||||
"item.label.GitHub": {
|
||||
"message": "GitHub",
|
||||
"description": "Navbar item with label GitHub"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Translate the `message` attribute in the JSON files of `i18n/fr`, and your site layout and homepage should now be translated.
|
||||
|
||||
### Translate Markdown files {#translate-markdown-files}
|
||||
|
||||
Official Docusaurus content plugins extensively use Markdown/MDX files and allow you to translate them.
|
||||
|
||||
#### Translate the docs {#translate-the-docs}
|
||||
|
||||
Copy your docs Markdown files from `docs/` to `i18n/fr/docusaurus-plugin-content-docs/current`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current
|
||||
cp -r docs/** i18n/fr/docusaurus-plugin-content-docs/current
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
Notice that the `docusaurus-plugin-content-docs` plugin always divides its content by versions. The data in `./docs` folder will be translated in the `current` subfolder and `current.json` file. See [the doc versioning guide](../guides/docs/versioning.md#terminology) for more information about what "current" means.
|
||||
|
||||
:::
|
||||
|
||||
#### Translate the blog {#translate-the-blog}
|
||||
|
||||
Copy your blog Markdown files to `i18n/fr/docusaurus-plugin-content-blog`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-blog
|
||||
cp -r blog/** i18n/fr/docusaurus-plugin-content-blog
|
||||
```
|
||||
|
||||
#### Translate the pages {#translate-the-pages}
|
||||
|
||||
Copy your pages Markdown files to `i18n/fr/docusaurus-plugin-content-pages`, and translate them:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-pages
|
||||
cp -r src/pages/**.md i18n/fr/docusaurus-plugin-content-pages
|
||||
cp -r src/pages/**.mdx i18n/fr/docusaurus-plugin-content-pages
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
We only copy `.md` and `.mdx` files, as React pages are translated through JSON translation files already.
|
||||
|
||||
:::
|
||||
|
||||
:::tip Use explicit heading ids
|
||||
|
||||
By default, a Markdown heading `### Hello World` will have a generated id `hello-world`. Other documents can link it with `[link](#hello-world)`. However, after translation, the heading becomes `### Bonjour le Monde`, with id `bonjour-le-monde`.
|
||||
|
||||
Generated ids are not always a good fit for localized sites, as it requires you to localize all the anchor links:
|
||||
|
||||
```diff
|
||||
- [link](#hello-world).
|
||||
+ [link](#bonjour-le-monde)
|
||||
```
|
||||
|
||||
For localized sites, it is recommended to use **[explicit heading ids](../guides/markdown-features/markdown-features-headings.mdx#explicit-ids)**.
|
||||
|
||||
:::
|
||||
|
||||
## Deploy your site {#deploy-your-site}
|
||||
|
||||
You can choose to deploy your site under a **single domain** or use **multiple (sub)domains**.
|
||||
|
||||
### Single-domain deployment {#single-domain-deployment}
|
||||
|
||||
Run the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
```
|
||||
|
||||
Docusaurus will build **one single-page application per locale**:
|
||||
|
||||
- `website/build`: for the default, English language
|
||||
- `website/build/fr`: for the French language
|
||||
|
||||
You can now [deploy](../deployment.mdx) the `build` folder to the static hosting solution of your choice.
|
||||
|
||||
:::note
|
||||
|
||||
The Docusaurus v2 website uses this strategy:
|
||||
|
||||
- [https://docusaurus.io](https://docusaurus.io)
|
||||
- [https://docusaurus.io/fr](https://docusaurus.io/fr)
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Static hosting providers generally redirect `/unknown/url` to `/404.html` by convention, always showing an **English 404 page**.
|
||||
|
||||
**Localize your 404 pages** by configuring your host to redirect `/fr/*` to `/fr/404.html`.
|
||||
|
||||
This is not always possible, and depends on your host: GitHub Pages can't do this, [Netlify](https://docs.netlify.com/routing/redirects/redirect-options/#custom-404-page-handling) can.
|
||||
|
||||
:::
|
||||
|
||||
### Multi-domain deployment {#multi-domain-deployment}
|
||||
|
||||
You can also build your site for a single locale:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build -- --locale fr
|
||||
```
|
||||
|
||||
Docusaurus will not add the `/fr/` URL prefix.
|
||||
|
||||
On your [static hosting provider](../deployment.mdx):
|
||||
|
||||
- create one deployment per locale
|
||||
- configure the appropriate build command, using the `--locale` option
|
||||
- configure the (sub)domain of your choice for each deployment
|
||||
|
||||
:::caution
|
||||
|
||||
This strategy is **not possible** with Github Pages, as it is only possible to **have a single deployment**.
|
||||
|
||||
:::
|
||||
|
||||
### Hybrid {#hybrid}
|
||||
|
||||
It is possible to have some locales using sub-paths, and others using subdomains.
|
||||
|
||||
It is also possible to deploy each locale as a separate subdomain, assemble the subdomains in a single unified domain at the CDN level:
|
||||
|
||||
- Deploy your site as `fr.docusaurus.io`
|
||||
- Configure a CDN to serve it from `docusaurus.io/fr`
|
||||
|
||||
## Managing translations {#managing-translations}
|
||||
|
||||
Docusaurus doesn't care about how you manage your translations: all it needs is that all translation files (JSON, Markdown, or other data files) are available in the file system during building. However, as site creators, you would need to consider how translations are managed so your translation contributors could collaborate well.
|
||||
|
||||
We will share two common translation collaboration strategies: [**using git**](./i18n-git.md) and [**using Crowdin**](./i18n-crowdin.mdx).
|
||||
|
|
@ -3,6 +3,11 @@ id: installation
|
|||
title: Installation
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
```
|
||||
|
||||
Docusaurus is essentially a set of npm [packages](https://github.com/facebook/docusaurus/tree/main/packages).
|
||||
|
||||
:::tip
|
||||
|
|
@ -15,8 +20,8 @@ Use **[docusaurus.new](https://docusaurus.new)** to test Docusaurus immediately
|
|||
|
||||
## Requirements {#requirements}
|
||||
|
||||
- [Node.js](https://nodejs.org/en/download/) version >= 14 or above (which can be checked by running `node -v`). You can use [nvm](https://github.com/nvm-sh/nvm) for managing multiple Node versions on a single machine installed
|
||||
- [Yarn](https://yarnpkg.com/en/) version >= 1.5 (which can be checked by running `yarn --version`). Yarn is a performant package manager for JavaScript and replaces the `npm` client. It is not strictly necessary but highly encouraged.
|
||||
- [Node.js](https://nodejs.org/en/download/) version >= 14 or above (which can be checked by running `node -v`). You can use [nvm](https://github.com/nvm-sh/nvm) for managing multiple Node versions on a single machine installed.
|
||||
- When installing Node.js, you are recommended to check all checkboxes related to dependencies.
|
||||
|
||||
## Scaffold project website {#scaffold-project-website}
|
||||
|
||||
|
|
@ -32,21 +37,11 @@ Example:
|
|||
npx create-docusaurus@latest website classic
|
||||
```
|
||||
|
||||
If you do not specify `name` or `template`, it will prompt you for them. We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus.
|
||||
If you do not specify `name` or `template`, it will prompt you for them.
|
||||
|
||||
The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory.
|
||||
We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus.
|
||||
|
||||
**[FB-Only]:** If you are setting up a new Docusaurus website for a Facebook open source project, use the `facebook` template instead, which comes with some useful Facebook-specific defaults:
|
||||
|
||||
```bash
|
||||
npx create-docusaurus@latest my-website facebook
|
||||
```
|
||||
|
||||
If you want to skip installing dependencies, use the `--skip-install` option, like the following:
|
||||
|
||||
```bash
|
||||
npx create-docusaurus@latest my-website classic --skip-install
|
||||
```
|
||||
The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory. If it's a git repository, you can also specify a cloning strategy. Run `npx create-docusaurus@latest --help` for more information.
|
||||
|
||||
You can also use the template's TypeScript variant by passing the `--typescript` flag.
|
||||
|
||||
|
|
@ -54,11 +49,67 @@ You can also use the template's TypeScript variant by passing the `--typescript`
|
|||
npx create-docusaurus@latest my-website classic --typescript
|
||||
```
|
||||
|
||||
:::info FB-Only
|
||||
|
||||
If you are setting up a new Docusaurus website for a Facebook open source project, use the `facebook` template instead, which comes with some useful Facebook-specific defaults:
|
||||
|
||||
```bash
|
||||
npx create-docusaurus@latest my-website facebook
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
<summary>Alternative installation commands</summary>
|
||||
|
||||
You can also initialize a new project using your preferred project manager:
|
||||
|
||||
````mdx-code-block
|
||||
<Tabs>
|
||||
<TabItem value="npm v6+">
|
||||
|
||||
```bash
|
||||
npm init docusaurus website classic
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="yarn">
|
||||
|
||||
```bash
|
||||
yarn create docusaurus website classic
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm create docusaurus website classic
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
</details>
|
||||
|
||||
Docusaurus makes best efforts to select a package manager to install dependencies for you, based on the command you are using and the project you are in. You can override this behavior by using `--package-manager [npm/yarn/pnpm]`.
|
||||
|
||||
```bash
|
||||
# Use Yarn to install dependencies even when the command is npx
|
||||
npx create-docusaurus@latest my-website classic --package-manager yarn
|
||||
```
|
||||
|
||||
If you want to skip installing dependencies, use the `--skip-install` option.
|
||||
|
||||
```bash
|
||||
npx create-docusaurus@latest my-website classic --skip-install
|
||||
```
|
||||
|
||||
## Project structure {#project-structure}
|
||||
|
||||
Assuming you chose the classic template and named your site `my-website`, you will see the following files generated under a new directory `my-website/`:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
my-website
|
||||
├── blog
|
||||
│ ├── 2019-05-28-hola.md
|
||||
|
|
@ -95,6 +146,28 @@ my-website
|
|||
- `/package.json` - A Docusaurus website is a React app. You can install and use any npm packages you like in them
|
||||
- `/sidebar.js` - Used by the documentation to specify the order of documents in the sidebar
|
||||
|
||||
### Monorepos {#monorepos}
|
||||
|
||||
If you are using Docusaurus for documentation of an existing project, a monorepo may be the solution for you. Monorepos allow you to share dependencies between similar projects. For example, your website may use your local packages to showcase the latest features, instead of depending on a released version; your contributors can also conveniently update the docs as they implement features. An example monorepo folder structure is below:
|
||||
|
||||
```bash
|
||||
my-monorepo
|
||||
├── package-a # Another package, your actual project
|
||||
│ ├── src
|
||||
│ └── package.json # Package A's dependencies
|
||||
├── website # Docusaurus root
|
||||
│ ├── docs
|
||||
│ ├── src
|
||||
│ └── package.json # Docusaurus' dependencies
|
||||
├── package.json # Monorepo's shared dependencies
|
||||
```
|
||||
|
||||
In this case, you should run `npx create-docusaurus` within the `./my-monorepo` folder.
|
||||
|
||||
If you're using a hosting provider such as Netlify or Vercel, you will need to change the `Base directory` of the site to where your Docusaurus root is. In this case, that would be `./website`. Read more about configuring ignore commands in the [deployment docs](./deployment.mdx#deploying-to-netlify).
|
||||
|
||||
Read more about monorepos in the [Yarn documentation](https://yarnpkg.com/features/workspaces) (Yarn is not the only way to set up a monorepo, but it's a common solution), or checkout [Docusaurus](https://github.com/facebook/docusaurus) and [Jest](https://github.com/facebook/jest) for some real-world examples.
|
||||
|
||||
## Running the development server {#running-the-development-server}
|
||||
|
||||
To preview your changes as you edit the files, you can run a local development server that will serve your website and reflect the latest changes.
|
||||
|
|
@ -154,4 +227,4 @@ Use new unreleased features of Docusaurus with the [`@canary` npm dist tag](/com
|
|||
|
||||
## Problems? {#problems}
|
||||
|
||||
Ask for help on [Stack Overflow](https://stackoverflow.com/questions/tagged/docusaurus), on our [GitHub repository](https://github.com/facebook/docusaurus) or [Twitter](https://twitter.com/docusaurus).
|
||||
Ask for help on [Stack Overflow](https://stackoverflow.com/questions/tagged/docusaurus), on our [GitHub repository](https://github.com/facebook/docusaurus), our [Discord server](https://discordapp.com/invite/docusaurus), or [Twitter](https://twitter.com/docusaurus).
|
||||
|
|
@ -13,7 +13,7 @@ slug: /
|
|||
|
||||
💅 Check the **[best Docusaurus sites](/showcase?tags=favorite)** for inspiration and read some **[testimonials](https://twitter.com/sebastienlorber/timelines/1392048416872706049)**.
|
||||
|
||||
🧐 Docusaurus is a **static-site generator**. It builds a **single-page application** with a fast client-side navigation, leveraging the full power of **React** to make your site interactive. It provides out-of-the-box **documentation features**, but can be used to create **any kind of site** (personal website, product, blog, marketing landing pages, etc).
|
||||
🧐 Docusaurus is a **static-site generator**. It builds a **single-page application** with fast client-side navigation, leveraging the full power of **React** to make your site interactive. It provides out-of-the-box **documentation features** but can be used to create **any kind of site** (personal website, product, blog, marketing landing pages, etc).
|
||||
|
||||

|
||||
|
||||
|
|
@ -46,6 +46,22 @@ Or read the **[5-minute tutorial](https://tutorial.docusaurus.io)** online.
|
|||
|
||||
:::
|
||||
|
||||
## Docusaurus: Documentation Made Easy
|
||||
|
||||
In this presentation at [Algolia Community Event](https://www.algolia.com/), [Meta Open Source team](https://opensource.facebook.com/) shared a brief walk-through of Docusaurus. They covered how to get started with the project, enable plugins, and set up functionalities like documentation and blogging.
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube.com/embed/Yhyx7otSksg"
|
||||
title="Docusaurus: Documentation Made Easy"
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
/>
|
||||
</div>
|
||||
|
||||
## Disclaimer {#disclaimer}
|
||||
|
||||
Docusaurus v2 is **beta** but already quite stable and widely used.
|
||||
|
|
@ -70,45 +86,45 @@ A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://ww
|
|||
|
||||
Docusaurus is built with high attention to the developer and contributor experience.
|
||||
|
||||
- ⚛️ **Built with 💚 and React**
|
||||
- ⚛️ **Built with 💚 and React**:
|
||||
- Extend and customize with React
|
||||
- Gain full control of your site's browsing experience by providing your own React components
|
||||
- **Pluggable**
|
||||
- **Pluggable**:
|
||||
- Bootstrap your site with a basic template, then use advanced features and plugins
|
||||
- Open source your plugins to share with the community
|
||||
- ✂️ **Developer experience**
|
||||
- ✂️ **Developer experience**:
|
||||
- Start writing your docs right now
|
||||
- Universal configuration entry point to make it more maintainable by contributors
|
||||
- Hot reloading with lightning fast incremental build on changes
|
||||
- Hot reloading with lightning-fast incremental build on changes
|
||||
- Route-based code and data splitting
|
||||
- Publish to GitHub Pages, Netlify, Vercel and other deployment services with ease
|
||||
- Publish to GitHub Pages, Netlify, Vercel, and other deployment services with ease
|
||||
|
||||
Our shared goal — to help your users find what they need fast, and understand your products better. We share with you our best practices helping you build your doc site right and well.
|
||||
Our shared goal—to help your users quickly find what they need and understand your products better. We share our best practices to help you build your docs site right and well.
|
||||
|
||||
- 🎯 **SEO friendly**
|
||||
- HTML files are statically generated for every possible path
|
||||
- page-specific SEO to help your users land on your official docs directly relating their problems at hand
|
||||
- 📝 **Powered by MDX**
|
||||
- Write interactive components via JSX and React embedded in markdown
|
||||
- Share your code in live editors to get your users love your products on the spot
|
||||
- 🔍 **Search** - Your full site is searchable
|
||||
- 💾 **Document Versioning** - Helps you keep documentation in sync with project releases.
|
||||
- 🌍 **i18n** - Translate your site in multiple locales
|
||||
- 🎯 **SEO friendly**:
|
||||
- HTML files are statically generated for every possible path.
|
||||
- Page-specific SEO to help your users land on your official docs directly relating their problems at hand.
|
||||
- 📝 **Powered by MDX**:
|
||||
- Write interactive components via JSX and React embedded in markdown.
|
||||
- Share your code in live editors to get your users to love your products on the spot.
|
||||
- 🔍 **Search**: Your full site is searchable.
|
||||
- 💾 **Document Versioning**: Helps you keep documentation in sync with project releases.
|
||||
- 🌍 **Internationalization (i18n)**: Translate your site in multiple locales.
|
||||
|
||||
Docusaurus 2 is born to be compassionately accessible to all your users, and lightning fast.
|
||||
Docusaurus 2 is born to be compassionately accessible to all your users, and lightning-fast.
|
||||
|
||||
- ⚡️ **Lightning fast** - Docusaurus 2 follows the [PRPL Pattern](https://developers.google.com/web/fundamentals/performance/prpl-pattern/) that makes sure your content loads blazing fast
|
||||
- 🦖 **Accessible** - Attention to accessibility, making your site equally accessible to all users
|
||||
- ⚡️ **Lightning-fast**. Docusaurus 2 follows the [PRPL Pattern](https://developers.google.com/web/fundamentals/performance/prpl-pattern/) that makes sure your content loads blazing fast.
|
||||
- 🦖 **Accessible**. Attention to accessibility, making your site equally accessible to all users.
|
||||
|
||||
## Design principles {#design-principles}
|
||||
|
||||
- **Little to learn** - Docusaurus should be easy to learn and use as the API is quite small. Most things will still be achievable by users, even if it takes them more code and more time to write. Not having abstractions is better than having the wrong abstractions, and we don't want users to have to hack around the wrong abstractions. Mandatory talk - [Minimal API Surface Area](https://www.youtube.com/watch?v=4anAwXYqLG8).
|
||||
- **Intuitive** - Users will not feel overwhelmed when looking at the project directory of a Docusaurus project or adding new features. It should look intuitive and easy to build on top of, using approaches they are familiar with.
|
||||
- **Layered architecture** - The separations of concerns between each layer of our stack (content/theming/styling) should be clear - well-abstracted and modular.
|
||||
- **Sensible defaults** - Common and popular performance optimizations and configurations will be done for users but they are given the option to override them.
|
||||
- **No vendor-lock in** - Users are not required to use the default plugins or CSS, although they are highly encouraged to. Certain core lower-level infra level pieces like React Loadable, React Router cannot be swapped because we do default performance optimization on them. But not higher level ones, such as choice of Markdown engines, CSS frameworks, CSS methodology will be entirely up to users.
|
||||
- **Little to learn**. Docusaurus should be easy to learn and use as the API is quite small. Most things will still be achievable by users, even if it takes them more code and more time to write. Not having abstractions is better than having the wrong abstractions, and we don't want users to have to hack around the wrong abstractions. Mandatory talk—[Minimal API Surface Area](https://www.youtube.com/watch?v=4anAwXYqLG8).
|
||||
- **Intuitive**. Users will not feel overwhelmed when looking at the project directory of a Docusaurus project or adding new features. It should look intuitive and easy to build on top of, using approaches they are familiar with.
|
||||
- **Layered architecture**. The separations of concerns between each layer of our stack (content/theming/styling) should be clear—well-abstracted and modular.
|
||||
- **Sensible defaults**. Common and popular performance optimizations and configurations will be done for users but they are given the option to override them.
|
||||
- **No vendor lock-in**. Users are not required to use the default plugins or CSS, although they are highly encouraged to. Certain core infrastructures like React Loadable and React Router cannot be swapped because we do default performance optimization on them, but not higher-level ones. Choice of Markdown engines, CSS frameworks, CSS methodology, and other architectures will be entirely up to users.
|
||||
|
||||
We believe that as developers, knowing how a library works is helpful in allowing us to become better at using it. Hence we're dedicating effort into explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it.
|
||||
We believe that, as developers, knowing how a library works helps us become better at using it. Hence we're dedicating effort to explaining the architecture and various components of Docusaurus with the hope that users reading it will gain a deeper understanding of the tool and be even more proficient in using it.
|
||||
|
||||
<!--
|
||||
|
||||
|
|
@ -126,23 +142,23 @@ References
|
|||
|
||||
Across all static site generators, Docusaurus has a unique focus on documentation sites and has many out-of-the-box features.
|
||||
|
||||
We've also studied other main static site generators and would like to share our insights on the comparison, hopefully to help you navigate through the prismatic choices out there.
|
||||
We've also studied other main static site generators and would like to share our insights on the comparison, hopefully helping you navigate through the prismatic choices out there.
|
||||
|
||||
### Gatsby {#gatsby}
|
||||
|
||||
[Gatsby](https://www.gatsbyjs.com/) is packed with a lot of features, has a rich ecosystem of plugins and is capable of doing everything that Docusaurus does. Naturally, that comes at a cost of a higher learning curve. Gatsby does many things well and is suitable for building many types of websites. On the other hand, Docusaurus tries to do one thing super well - be the best tool for writing and publishing content.
|
||||
[Gatsby](https://www.gatsbyjs.com/) is packed with a lot of features, has a rich ecosystem of plugins, and is capable of doing everything that Docusaurus does. Naturally, that comes at a cost of a higher learning curve. Gatsby does many things well and is suitable for building many types of websites. On the other hand, Docusaurus tries to do one thing super well - be the best tool for writing and publishing content.
|
||||
|
||||
GraphQL is also pretty core to Gatsby, although you don't necessarily need GraphQL to build a Gatsby site. In most cases when building static websites, you won't need the flexibility that GraphQL provides.
|
||||
|
||||
Many aspects of Docusaurus 2 were inspired by the best things about Gatsby and it's a great alternative.
|
||||
|
||||
[Docz](https://github.com/pedronauck/docz) is a Gatsby theme to build documentation website. It is currently less featured than Docusaurus.
|
||||
[Docz](https://github.com/pedronauck/docz) is a Gatsby theme to build documentation websites. It is currently less featured than Docusaurus.
|
||||
|
||||
### Next.js {#nextjs}
|
||||
|
||||
[Next.js](https://nextjs.org/) is another very popular hybrid React framework. It can help you build a good documentation website, but it is not opinionated toward the documentation use-case, and it will require a lot more work to implement what Docusaurus provides out-of-the-box.
|
||||
|
||||
[Nextra](https://github.com/shuding/nextra) is an opinionated static-site-generator built on top of Next.js. It is currently less featured than Docusaurus.
|
||||
[Nextra](https://github.com/shuding/nextra) is an opinionated static site generator built on top of Next.js. It is currently less featured than Docusaurus.
|
||||
|
||||
### VuePress {#vuepress}
|
||||
|
||||
|
|
@ -150,9 +166,9 @@ Many aspects of Docusaurus 2 were inspired by the best things about Gatsby and i
|
|||
|
||||
### MkDocs {#mkdocs}
|
||||
|
||||
[MkDocs](https://www.mkdocs.org/) is a popular Python static-site-generator with value proposition similar to Docusaurus.
|
||||
[MkDocs](https://www.mkdocs.org/) is a popular Python static site generator with value propositions similar to Docusaurus.
|
||||
|
||||
It is a good option if you don't need a single-page application, and don't plan to leverage React.
|
||||
It is a good option if you don't need a single-page application and don't plan to leverage React.
|
||||
|
||||
[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) is a beautiful theme.
|
||||
|
||||
|
|
@ -162,7 +178,7 @@ It is a good option if you don't need a single-page application, and don't plan
|
|||
|
||||
### GitBook {#gitbook}
|
||||
|
||||
[GitBook](https://www.gitbook.com/) has very clean design and has been used by many open source projects. With its focus shifting towards a commercial product rather than an open-source tool, many of its requirements no longer fit the needs as an open source project's documentation site. As a result, many have turned to other products. You may read about Redux's switch to Docusaurus [here](https://github.com/reduxjs/redux/issues/3161).
|
||||
[GitBook](https://www.gitbook.com/) has a very clean design and has been used by many open source projects. With its focus shifting towards a commercial product rather than an open-source tool, many of its requirements no longer fit the needs of open source projects' documentation sites. As a result, many have turned to other products. You may read about Redux's switch to Docusaurus [here](https://github.com/reduxjs/redux/issues/3161).
|
||||
|
||||
Currently, GitBook is only free for open-source and non-profit teams. Docusaurus is free for everyone.
|
||||
|
||||
|
|
@ -170,7 +186,7 @@ Currently, GitBook is only free for open-source and non-profit teams. Docusaurus
|
|||
|
||||
[Jekyll](https://github.com/jekyll/jekyll) is one of the most mature static site generators around and has been a great tool to use — in fact, before Docusaurus, most of Facebook's Open Source websites are/were built on Jekyll! It is extremely simple to get started. We want to bring a similar developer experience as building a static site with Jekyll.
|
||||
|
||||
In comparison with statically generated HTML and interactivity added using `<script />` tags, Docusaurus sites are React apps. Using modern JavaScript ecosystem tooling, we hope to set new standards on doc sites performance, asset build pipeline and optimizations, and ease to setup.
|
||||
In comparison with statically generated HTML and interactivity added using `<script />` tags, Docusaurus sites are React apps. Using modern JavaScript ecosystem tooling, we hope to set new standards on doc sites' performance, asset building pipeline and optimizations, and ease to set up.
|
||||
|
||||
## Staying informed {#staying-informed}
|
||||
|
||||
|
|
@ -183,4 +199,4 @@ In comparison with statically generated HTML and interactivity added using `<scr
|
|||
|
||||
If you find issues with the documentation or have suggestions on how to improve the documentation or the project in general, please [file an issue](https://github.com/facebook/docusaurus) for us, or send a tweet mentioning the [@docusaurus](https://twitter.com/docusaurus) Twitter account.
|
||||
|
||||
For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
||||
For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
||||
|
|
@ -135,7 +135,7 @@ In Docusaurus 2, we split each functionality (blog, docs, pages) into plugins fo
|
|||
|
||||
Add the following preset configuration to your `docusaurus.config.js`.
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
|
|
@ -217,7 +217,7 @@ import ColorGenerator from '@site/src/components/ColorGenerator';
|
|||
|
||||
Site meta info such as assets, SEO, copyright info are now handled by themes. To customize them, use the `themeConfig` field in your `docusaurus.config.js`:
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
|
|
@ -251,7 +251,7 @@ headerLinks: [
|
|||
|
||||
Now, these two fields are both handled by the theme:
|
||||
|
||||
```jsx {6-19} title="docusaurus.config.js"
|
||||
```js {6-19} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
|
|
@ -279,7 +279,7 @@ module.exports = {
|
|||
|
||||
#### `algolia` {#algolia}
|
||||
|
||||
```jsx {4-8} title="docusaurus.config.js"
|
||||
```js {4-8} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
|
|
@ -305,7 +305,7 @@ You can contact the DocSearch team (@shortcuts, @s-pace) for support. They can u
|
|||
|
||||
Deprecated. Pass it as a blog option to `@docusaurus/preset-classic` instead:
|
||||
|
||||
```jsx {8} title="docusaurus.config.js"
|
||||
```js {8} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
|
|
@ -332,7 +332,7 @@ Deprecated. Create a `CNAME` file in your `static` folder instead with your cust
|
|||
|
||||
Deprecated. Pass it as an option to `@docusaurus/preset-classic` docs instead:
|
||||
|
||||
```jsx {8-20} title="docusaurus.config.js"
|
||||
```js {8-20} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
|
|
@ -455,7 +455,7 @@ If you had `cleanUrl: false` in v1, it's possible that people published links to
|
|||
|
||||
For SEO reasons, and avoiding breaking links, you should configure server-side redirect rules on your hosting provider.
|
||||
|
||||
As an escape hatch, you could use [@docusaurus/plugin-client-redirects](./using-plugins.md#docusaurusplugin-client-redirects) to create client-side redirects from `/installation.html` to `/installation`.
|
||||
As an escape hatch, you could use [@docusaurus/plugin-client-redirects](../api/plugins/plugin-client-redirects.md) to create client-side redirects from `/installation.html` to `/installation`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
|
|
@ -470,13 +470,13 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
If you want to keep the `.html` extension as the canonical url of a page, docs can declare a `slug: installation.html` frontmatter.
|
||||
If you want to keep the `.html` extension as the canonical url of a page, docs can declare a `slug: installation.html` front matter.
|
||||
|
||||
## Components {#components}
|
||||
|
||||
### Sidebar {#sidebar}
|
||||
|
||||
In previous version, nested sidebar category is not allowed and sidebar category can only contain doc id. However, v2 allows infinite nested sidebar and we have many types of [Sidebar Item](../guides/docs/sidebar.md#understanding-sidebar-items) other than document.
|
||||
In previous version, nested sidebar category is not allowed and sidebar category can only contain doc id. However, v2 allows infinite nested sidebar and we have many types of [Sidebar Item](../guides/docs/sidebar/items.md) other than document.
|
||||
|
||||
You'll have to migrate your sidebar if it contains category type. Rename `subcategory` to `category` and `ids` to `items`.
|
||||
|
||||
|
|
@ -492,7 +492,7 @@ You'll have to migrate your sidebar if it contains category type. Rename `subcat
|
|||
|
||||
### Footer {#footer}
|
||||
|
||||
`website/core/Footer.js` is no longer needed. If you want to modify the default footer provided by Docusaurus, [swizzle](using-themes.md#swizzling-theme-components) it:
|
||||
`website/core/Footer.js` is no longer needed. If you want to modify the default footer provided by Docusaurus, [swizzle](../swizzling.md) it:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic Footer
|
||||
|
|
@ -579,7 +579,7 @@ This feature is replaced by [inline table of content](../guides/markdown-feature
|
|||
|
||||
In Docusaurus 2, the markdown syntax has been changed to [MDX](https://mdxjs.com/). Hence there might be some broken syntax in the existing docs which you would have to update. A common example is self-closing tags like `<img>` and `<br>` which are valid in HTML would have to be explicitly closed now ( `<img/>` and `<br/>`). All tags in MDX documents have to be valid JSX.
|
||||
|
||||
Frontmatter is parsed by [gray-matter](https://github.com/jonschlinkert/gray-matter). If your frontmatter use special characters like `:`, you now need to quote it: `title: Part 1: my part1 title` -> `title: Part 1: "my part1 title"`.
|
||||
Front matter is parsed by [gray-matter](https://github.com/jonschlinkert/gray-matter). If your front matter use special characters like `:`, you now need to quote it: `title: Part 1: my part1 title` -> `title: Part 1: "my part1 title"`.
|
||||
|
||||
**Tips**: You might want to use some online tools like [HTML to JSX](https://transform.tools/html-to-jsx) to make the migration easier.
|
||||
|
||||
|
|
@ -603,7 +603,7 @@ The blog RSS feed is now hosted at `/blog/rss.xml` instead of `/blog/feed.xml`.
|
|||
|
||||
After migration, your folder structure should look like this:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
my-project
|
||||
├── docs
|
||||
└── website
|
||||
|
|
@ -8,7 +8,7 @@ This doc guides you through migrating an existing Docusaurus 1 site to Docusauru
|
|||
|
||||
We try to make this as easy as possible, and provide a migration cli.
|
||||
|
||||
## Main differences
|
||||
## Main differences {#main-differences}
|
||||
|
||||
Docusaurus 1 is a pure documentation site generator, using React as a server-side template engine, but not loading React on the browser.
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ While our main focus will still be helping you get your documentations right and
|
|||
|
||||
Your Docusaurus 1 site should have the following structure:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
├── docs
|
||||
└── website
|
||||
├── blog
|
||||
|
|
@ -110,7 +110,7 @@ Unfortunately, Crowdin does not have any "Duplicate/clone Project" feature, whic
|
|||
- Download the Crowdin translations locally
|
||||
- Try to run/build your site and see if there are any errors
|
||||
|
||||
You will likely have errors on your first-try: the pre-translation might try to translate things that it should not be translated (frontmatter, admonition, code blocks...), and the translated md files might be invalid for the MDX parser.
|
||||
You will likely have errors on your first-try: the pre-translation might try to translate things that it should not be translated (front matter, admonition, code blocks...), and the translated md files might be invalid for the MDX parser.
|
||||
|
||||
You will have to fix all the errors until your site builds. You can do that by modifying the translated md files locally, and fix your site for one locale at a time using `docusaurus build --locale fr`.
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ title: Hello, World !
|
|||
Hi, Endilie here :)
|
||||
```
|
||||
|
||||
Since we're going for snapshot and allow people to move (and edit) docs easily inside version. The `id` frontmatter is no longer altered and will remain the same. Internally, it is set as `version-${version}/${id}`.
|
||||
Since we're going for snapshot and allow people to move (and edit) docs easily inside version. The `id` front matter is no longer altered and will remain the same. Internally, it is set as `version-${version}/${id}`.
|
||||
|
||||
Essentially, here are the necessary changes in each versioned_docs file:
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ original_id: hello
|
|||
Hi, Endilie here :)
|
||||
```
|
||||
|
||||
Since we don't allow `/` in v1 & v2 for frontmatter, conflicts are less likely to occur.
|
||||
Since we don't allow `/` in v1 & v2 for front matter, conflicts are less likely to occur.
|
||||
|
||||
So v1 users need to migrate their versioned_sidebars file
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ For example, if your `versions.json` looks like this in v1
|
|||
|
||||
Docusaurus v1 creates versioned docs **if and only if the doc content is different**. Your docs structure might look like this if the only doc changed from v1.0.0 to v1.1.0 is `hello.md`.
|
||||
|
||||
```shell
|
||||
```bash
|
||||
website
|
||||
├── versioned_docs
|
||||
│ ├── version-1.1.0
|
||||
|
|
@ -139,9 +139,9 @@ website
|
|||
│ └── version-1.0.0-sidebars.json
|
||||
```
|
||||
|
||||
In v2, you have to populate the missing `versioned_docs` and `versioned_sidebars` (with the right frontmatter and id reference too).
|
||||
In v2, you have to populate the missing `versioned_docs` and `versioned_sidebars` (with the right front matter and id reference too).
|
||||
|
||||
```shell {3-5,12}
|
||||
```bash {3-5,12}
|
||||
website
|
||||
├── versioned_docs
|
||||
│ ├── version-1.1.0
|
||||
|
|
@ -25,9 +25,9 @@ There are a few options you can use to add search to your website:
|
|||
|
||||
Docusaurus has **official support** for [Algolia DocSearch](https://docsearch.algolia.com).
|
||||
|
||||
The service is **free** in most cases: just [apply to the DocSearch program](https://docsearch.algolia.com/apply).
|
||||
The service is **free** for any open-source project: just make sure to read the [checklist](https://docsearch.algolia.com/docs/who-can-apply/) and [apply to the DocSearch program](https://docsearch.algolia.com/apply).
|
||||
|
||||
It works by crawling the content of your website every 24 hours and putting all the content in an Algolia index. This content is then queried directly from your front-end using the Algolia API.
|
||||
DocSearch crawls your website once a week (the schedule is configurable from the web interface) and aggregates all the content in an Algolia index. This content is then queried directly from your front-end using the Algolia API.
|
||||
|
||||
If your website is [not eligible](https://docsearch.algolia.com/docs/who-can-apply) for the free, hosted version of DocSearch, or if your website sits behind a firewall and is not public, then you can [run your own](https://docsearch.algolia.com/docs/run-your-own/) DocSearch crawler.
|
||||
|
||||
|
|
@ -37,22 +37,19 @@ By default, the Docusaurus preset generates a [sitemap.xml](https://docusaurus.i
|
|||
|
||||
:::
|
||||
|
||||
:::info From the old docsearch?
|
||||
|
||||
You can read more about migration from the legacy DocSearch infra in [our blog post](/blog/2021/11/21/algolia-docsearch-migration) or [the DocSearch migration docs](https://docsearch.algolia.com/docs/migrating-from-legacy).
|
||||
|
||||
:::
|
||||
|
||||
### Index Configuration {#algolia-index-configuration}
|
||||
|
||||
After applying, your site's DocSearch config should be created at:
|
||||
After your application has been approved and deployed, you will receive an email with all the details for you to add DocSearch to your project. Editing and managing your crawls can be done via [the web interface](https://crawler.algolia.com/). Indices are readily available after deployment, so manual configuration usually isn't necessary.
|
||||
|
||||
```
|
||||
https://github.com/algolia/docsearch-configs/blob/master/configs/<indexName>.json
|
||||
```
|
||||
:::tip
|
||||
|
||||
This configuration file can be updated by:
|
||||
|
||||
- [**asking for help**](#algolia-support): the DocSearch team can help you maintain it
|
||||
- opening a pull-requests in [algolia/docsearch-configs](https://github.com/algolia/docsearch-configs)
|
||||
|
||||
:::caution
|
||||
|
||||
It is highly recommended using a config similar to the [**Docusaurus 2 website config**](https://github.com/algolia/docsearch-configs/blob/master/configs/docusaurus-2.json).
|
||||
It is highly recommended to use a config similar to the [**Docusaurus 2 website config**](https://docsearch.algolia.com/docs/templates/#docusaurus-v2-template).
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -86,14 +83,14 @@ module.exports = {
|
|||
|
||||
Then, add an `algolia` field in your `themeConfig`. **[Apply for DocSearch](https://docsearch.algolia.com/apply/)** to get your Algolia index and API key.
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
// ...
|
||||
// highlight-start
|
||||
algolia: {
|
||||
// If Algolia did not provide you any appId, use 'BH4D9OD16A'
|
||||
// The application ID provided by Algolia
|
||||
appId: 'YOUR_APP_ID',
|
||||
|
||||
// Public API key: it is safe to commit it
|
||||
|
|
@ -110,6 +107,9 @@ module.exports = {
|
|||
// Optional: Algolia search parameters
|
||||
searchParameters: {},
|
||||
|
||||
// Optional: path for search page that enabled by default (`false` to disable it)
|
||||
searchPagePath: 'search',
|
||||
|
||||
//... other Algolia params
|
||||
},
|
||||
// highlight-end
|
||||
|
|
@ -121,28 +121,25 @@ module.exports = {
|
|||
|
||||
The `searchParameters` option used to be named `algoliaOptions` in Docusaurus v1.
|
||||
|
||||
Refer to its [official DocSearch documentation](https://docsearch.algolia.com/docs/api#searchparameters) for possible values.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
The search feature will not work reliably until Algolia crawls your site with the **search plugin enabled**.
|
||||
The search feature will not work reliably until Algolia crawls your site.
|
||||
|
||||
If you are installing the Algolia plugin for the first time and want to ensure the search feature works before deploying it to production, you can ask the DocSearch team to trigger a crawl on a staging environment url or deploy preview.
|
||||
If search doesn't work after any significant change, please use the Algolia dashboard to **trigger a new crawl**.
|
||||
|
||||
:::
|
||||
|
||||
### Contextual search {#contextual-search}
|
||||
|
||||
Contextual search is mostly useful for versioned Docusaurus sites.
|
||||
Contextual search is **enabled by default**.
|
||||
|
||||
Let's consider you have 2 docs versions, v1 and v2. When you are browsing v2 docs, it would be odd to return search results for the v1 documentation. Sometimes v1 and v2 docs are quite similar, and you would end up with duplicate search results for the same query (one result per version).
|
||||
It ensures that search results are **relevant to the current language and version**.
|
||||
|
||||
To solve this problem, the contextual search feature understands that you are browsing a specific docs version, and will create the search query filters dynamically.
|
||||
|
||||
- browsing `/docs/v1/myDoc`, search results will only include **v1** docs (+ other unversioned pages)
|
||||
- browsing `/docs/v2/myDoc`, search results will only include **v2** docs (+ other unversioned pages)
|
||||
|
||||
```jsx title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
|
|
@ -156,9 +153,41 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
:::caution
|
||||
Let's consider you have 2 docs versions (**v1** and **v2**) and 2 languages (`en` and `fr`).
|
||||
|
||||
When using `contextualSearch: true`, the contextual facet filters will be merged with the ones provided with `algolia.searchParameters.facetFilters`.
|
||||
When browsing v2 docs, it would be odd to return search results for the v1 documentation. Sometimes v1 and v2 docs are quite similar, and you would end up with duplicate search results for the same query (one result per version).
|
||||
|
||||
Similarly, when browsing the French site, it would be odd to return search results for the English docs.
|
||||
|
||||
To solve this problem, the contextual search feature understands that you are browsing a specific docs version and language, and will create the search query filters dynamically.
|
||||
|
||||
- on `/en/docs/v1/myDoc`, search results will only include **English** results for the **v1** docs (+ other unversioned pages)
|
||||
- on `/fr/docs/v2/myDoc`, search results will only include **French** results for the **v2** docs (+ other unversioned pages)
|
||||
|
||||
:::info
|
||||
|
||||
When using `contextualSearch: true` (default), the contextual facet filters will be merged with the ones provided with `algolia.searchParameters.facetFilters` .
|
||||
|
||||
For specific needs, you can disable `contextualSearch` and define your own `facetFilters`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
// ...
|
||||
// highlight-start
|
||||
algolia: {
|
||||
contextualSearch: false,
|
||||
searchParameters: {
|
||||
facetFilters: ['language:en', ['filter1', 'filter2'], 'filter3'],
|
||||
},
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Refer to the relevant [Algolia faceting documentation](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/).
|
||||
|
||||
:::
|
||||
|
||||
|
|
@ -169,7 +198,7 @@ By default, DocSearch comes with a fine-tuned theme that was designed for access
|
|||
Still, you can reuse the [Infima CSS variables](styling-layout.md#styling-your-site-with-infima) from Docusaurus to style DocSearch by editing the `/src/css/custom.css` file.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
html[data-theme='light'] .DocSearch {
|
||||
[data-theme='light'] .DocSearch {
|
||||
/* --docsearch-primary-color: var(--ifm-color-primary); */
|
||||
/* --docsearch-text-color: var(--ifm-font-color-base); */
|
||||
--docsearch-muted-color: var(--ifm-color-secondary-darkest);
|
||||
|
|
@ -187,7 +216,7 @@ html[data-theme='light'] .DocSearch {
|
|||
--docsearch-footer-background: var(--ifm-color-white);
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .DocSearch {
|
||||
[data-theme='dark'] .DocSearch {
|
||||
--docsearch-text-color: var(--ifm-font-color-base);
|
||||
--docsearch-muted-color: var(--ifm-color-secondary-darkest);
|
||||
--docsearch-container-background: rgba(47, 55, 69, 0.7);
|
||||
|
|
@ -275,6 +304,6 @@ To use your own search, swizzle the `SearchBar` component in `@docusaurus/theme-
|
|||
npm run swizzle @docusaurus/theme-classic SearchBar
|
||||
```
|
||||
|
||||
This will create a `src/themes/SearchBar` file in your project folder. Restart your dev server and edit the component, you will see that Docusaurus uses your own `SearchBar` component now.
|
||||
This will create an `src/themes/SearchBar` file in your project folder. Restart your dev server and edit the component, you will see that Docusaurus uses your own `SearchBar` component now.
|
||||
|
||||
**Notes**: You can alternatively [swizzle from Algolia SearchBar](#editing-the-algolia-search-component) and create your own search component from there.
|
||||
|
|
@ -7,6 +7,8 @@ keywords:
|
|||
- positioning
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Docusaurus supports search engine optimization in a variety of ways.
|
||||
|
||||
## Global metadata {#global-metadata}
|
||||
|
|
@ -58,7 +60,7 @@ export default function page() {
|
|||
|
||||
Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter:
|
||||
|
||||
```yml
|
||||
```md
|
||||
---
|
||||
title: Title for search engines; can be different from the actual heading
|
||||
description: A short description of this page
|
||||
|
|
@ -83,21 +85,25 @@ Docusaurus is a static site generator—HTML files are statically generated for
|
|||
|
||||
The alt tag for an image tells the search engine what the image is about, and is used when the image can't be visually seen, e.g. when using a screen reader, or when the image is broken. Alt tags are commonly supported in Markdown.
|
||||
|
||||
You may also add a title for your image—this doesn't impact SEO much, but is displayed as tooltip when hovering above the image, usually used to provide hints.
|
||||
You may also add a title for your image—this doesn't impact SEO much but is displayed as a tooltip when hovering above the image, usually used to provide hints.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Rich search information {#rich-search-information}
|
||||
|
||||
Docusaurus blogs support [rich search results](https://search.google.com/test/rich-results) out-of-the-box to get maximum search engine experience. The information is created depending on your meta information in blog/global configuration. In order to get the benefits of the rich search information, fill in the information about the post's publish date, authors, and image, etc. Read more about the meta-information [here](./blog.mdx).
|
||||
|
||||
## Robots file {#robots-file}
|
||||
|
||||
To add a `robots.txt` file that regulates search engines' behavior about which should be displayed and which shouldn't, provide it as [static asset](./static-assets.md). The following would allow access to all sub-pages from all requests:
|
||||
A `robots.txt` file regulates search engines' behavior about which should be displayed and which shouldn't. You can provide it as [static asset](./static-assets.md). The following would allow access to all sub-pages from all requests:
|
||||
|
||||
```text title="static/robots.txt"
|
||||
User-agent: *
|
||||
|
|
@ -124,4 +130,4 @@ Docusaurus uses your file names as links, but you can always change that using s
|
|||
|
||||
Search engines rely on the HTML markup such as `<h2>`, `<table>`, etc., to understand the structure of your webpage. When Docusaurus renders your pages, semantic markup, e.g. `<aside>`, `<nav>`, `<main>`, are used to divide the different sections of the page, helping the search engine to locate parts like sidebar, navbar, and the main page content.
|
||||
|
||||
Most [CommonMark](https://spec.commonmark.org/0.30/#atx-headings) syntax have their corresponding HTML tags. By using Markdown consistently in your project, you will make it easier for search engines to understand your page content.
|
||||
Most [CommonMark](https://spec.commonmark.org/0.30/#atx-headings) syntaxes have their corresponding HTML tags. By using Markdown consistently in your project, you will make it easier for search engines to understand your page content.
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
id: static-assets
|
||||
title: Static Assets
|
||||
---
|
||||
|
||||
Every website needs assets: images, stylesheets, favicons, etc. By default, you are suggested to put these assets in the `static` folder.
|
||||
|
||||
Every file you put into **that directory will be copied** into the root of the generated `build` folder with the directory hierarchy preserved. E.g. if you add a file named `sun.jpg` to the static folder, it will be copied to `build/sun.jpg`.
|
||||
|
||||
This means that:
|
||||
|
||||
- for site `baseUrl: '/'`, the image `/static/img/docusaurus.png` will be served at `/img/docusaurus.png`.
|
||||
- for site `baseUrl: '/subpath/'`, the image `/static/img/docusaurus.png` will be served at `/subpath/img/docusaurus.png`.
|
||||
|
||||
You can customize the static directory sources in `docusaurus.config.js`. For example, we can add `public` as another possible path:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
title: 'My site',
|
||||
staticDirectories: ['public', 'static'],
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Now, all files in `public` as well as `static` will be copied to the build output.
|
||||
|
||||
## Referencing your static asset {#referencing-your-static-asset}
|
||||
|
||||
### In JSX {#in-jsx}
|
||||
|
||||
In JSX, you can reference assets from the `static` folder in your code using absolute URLs, but this is not ideal because changing the site `baseUrl` will **break those links**. For the image `<img src="/img/docusaurus.png" />` served at `https://example.com/test`, the browser will try to resolve it from the URL root, i.e. as `https://example.com/img/docusaurus.png`, which will fail because it's actually served at `https://example.com/test/img/docusaurus.png`.
|
||||
|
||||
You can `import()` or `require()` the static asset (recommended), or use the `useBaseUrl` utility function: both prepend the `baseUrl` to paths for you.
|
||||
|
||||
Examples:
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import DocusaurusImageUrl from '@site/static/img/docusaurus.png';
|
||||
|
||||
<img src={DocusaurusImageUrl} />;
|
||||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
<img src={require('@site/static/img/docusaurus.png').default} />
|
||||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<img src={useBaseUrl('/img/docusaurus.png')} />;
|
||||
```
|
||||
|
||||
You can also import SVG files: they will be transformed into React components.
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
import DocusaurusLogoWithKeytar from '@site/static/img/docusaurus_keytar.svg';
|
||||
|
||||
<DocusaurusLogoWithKeytar title="Docusaurus Logo" className="logo" />;
|
||||
```
|
||||
|
||||
### In Markdown {#in-markdown}
|
||||
|
||||
In Markdown, you can stick to using absolute paths when writing links or images **in Markdown syntax** because Docusaurus handles them as `require` calls instead of URLs when parsing the Markdown. See [Markdown static assets](./guides/markdown-features/markdown-features-assets.mdx).
|
||||
|
||||
```md
|
||||
You write a link like this: [Download this document](/files/note.docx)
|
||||
|
||||
Docusaurus changes that to: <a href={require('static/files/note.docx')}>Download this document</a>
|
||||
```
|
||||
|
||||
:::caution use markdown syntax
|
||||
|
||||
Docusaurus will only parse links that are in Markdown syntax. If your asset references are using the JSX tag `<a>` / `<img>`, nothing will be done.
|
||||
|
||||
:::
|
||||
|
||||
### In CSS {#in-css}
|
||||
|
||||
In CSS, the `url()` function is commonly used to reference assets like fonts and images. To reference a static asset, use absolute paths:
|
||||
|
||||
```css
|
||||
@font-face {
|
||||
font-family: 'Caroline';
|
||||
src: url('/font/Caroline.otf');
|
||||
}
|
||||
```
|
||||
|
||||
The `static/font/Caroline.otf` asset will be loaded by the bundler.
|
||||
|
||||
:::warning important takeaway
|
||||
|
||||
One important takeaway: **never hardcode your base URL!** The base URL is considered an implementation detail and should be easily changeable. All paths, even when they look like URL slugs, are actually file paths.
|
||||
|
||||
If you find the URL slug mental model more understandable, here's a rule of thumb:
|
||||
|
||||
- Pretend you have a base URL like `/test/` when writing JSX so you don't use an absolute URL path like `src="/img/thumbnail.png"` but instead `require` the asset.
|
||||
- Pretend it's `/` when writing Markdown or CSS so you always use absolute paths without the base URL.
|
||||
|
||||
:::
|
||||
|
||||
## Caveats {#caveats}
|
||||
|
||||
Keep in mind that:
|
||||
|
||||
- By default, none of the files in the `static` folder will be post-processed, hashed, or minified.
|
||||
- However, as we've demonstrated above, we are usually able to convert them to `require` calls for you so they do get processed. This is good for aggressive caching and better user experience.
|
||||
- Missing files referenced via hard-coded absolute paths will not be detected at compilation time and will result in a 404 error.
|
||||
- By default, GitHub Pages runs published files through [Jekyll](https://jekyllrb.com/). Since Jekyll will discard any files that begin with `_`, it is recommended that you disable Jekyll by adding an empty file named `.nojekyll` file to your `static` directory if you are using GitHub pages for hosting.
|
||||
|
|
@ -8,19 +8,19 @@ import ColorGenerator from '@site/src/components/ColorGenerator';
|
|||
|
||||
:::tip
|
||||
|
||||
This section discusses about styling through stylesheets. If you find yourself needing to update the DOM structure, you can refer to [swizzling](./using-themes.md#swizzling-theme-components).
|
||||
This section is focused on styling through stylesheets. For more advanced customizations (DOM structure, React code...), refer to the [swizzling guide](./swizzling.md).
|
||||
|
||||
:::
|
||||
|
||||
A Docusaurus site is a single-page React application. You can style it the way you style React apps.
|
||||
|
||||
There are a few approaches/frameworks which will work, depending on your preferences and the type of website you are trying to build. Websites that are highly interactive and behave more like web apps will benefit from a more modern styling approaches that co-locate styles with the components. Component styling can also be particularly useful when you wish to customize or swizzle a component.
|
||||
There are a few approaches/frameworks which will work, depending on your preferences and the type of website you are trying to build. Websites that are highly interactive and behave more like web apps will benefit from more modern styling approaches that co-locate styles with the components. Component styling can also be particularly useful when you wish to customize or swizzle a component.
|
||||
|
||||
## Global styles {#global-styles}
|
||||
|
||||
This is the most traditional way of styling that most developers (including non-front end developers) would be familiar with. It works fine for small websites that do not have much customization.
|
||||
This is the most traditional way of styling that most developers (including non-front-end developers) would be familiar with. It works fine for small websites that do not have much customization.
|
||||
|
||||
If you're using `@docusaurus/preset-classic`, you can create your own CSS files (e.g. `/src/css/custom.css`) and import them globally by passing it as an option into the preset.
|
||||
If you're using `@docusaurus/preset-classic`, you can create your own CSS files (e.g. `/src/css/custom.css`) and import them globally by passing them as an option into the preset.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
|
|
@ -58,13 +58,28 @@ function MyComponent() {
|
|||
}
|
||||
```
|
||||
|
||||
### Theme Class Names
|
||||
If you want to add CSS to any element, you can open the DevTools in your browser to inspect its class names. Class names come in several kinds:
|
||||
|
||||
We provide some predefined CSS class names to provide access for developers to style layout of a page globally in Docusaurus. The purpose is to have stable classnames shared by all themes that are meant to be targeted by custom CSS.
|
||||
- **Theme class names**. These class names are listed exhaustively in [the next subsection](#theme-class-names). They don't have any default properties. You should always prioritize targeting those stable class names in your custom CSS.
|
||||
- **Infima class names**. These class names are found in the classic theme and usually follow the [BEM convention](http://getbem.com/naming/) of `block__element--modifier`. They are usually stable but are still considered implementation details, so you should generally avoid targeting them. However, you can [modify Infima CSS variables](#styling-your-site-with-infima).
|
||||
- **CSS module class names**. These class names have a hash in production (`codeBlockContainer_RIuc`) and are appended with a long file path in development. They are considered implementation details and you should almost always avoid targeting them in your custom CSS. If you must, you can use an [attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) (`[class*='codeBlockContainer']`) that ignores the hash.
|
||||
|
||||
### Theme Class Names {#theme-class-names}
|
||||
|
||||
We provide some stable CSS class names for robust and maintainable global layout styling. These names are theme-agnostic and meant to be targeted by custom CSS.
|
||||
|
||||
:::tip
|
||||
|
||||
If you can't find a way to create a robust CSS selector, please [report your customization use-case](https://github.com/facebook/docusaurus/discussions/5468) and we will consider adding new class names.
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exhaustive list of stable class names</summary>
|
||||
|
||||
```mdx-code-block
|
||||
import ThemeClassNamesCode from '!!raw-loader!@site/../packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts';
|
||||
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
<CodeBlock className="language-ts">
|
||||
|
|
@ -76,25 +91,17 @@ import CodeBlock from '@theme/CodeBlock';
|
|||
</CodeBlock>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Styling your site with Infima {#styling-your-site-with-infima}
|
||||
|
||||
`@docusaurus/preset-classic` uses [Infima](https://infima.dev/) as the underlying styling framework. Infima provides flexible layout and common UI components styling suitable for content-centric websites (blogs, documentation, landing pages). For more details, check out the [Infima website](https://infima.dev/).
|
||||
`@docusaurus/preset-classic` uses [Infima](https://infima.dev/) as the underlying styling framework. Infima provides a flexible layout and common UI components styling suitable for content-centric websites (blogs, documentation, landing pages). For more details, check out the [Infima website](https://infima.dev/).
|
||||
|
||||
When you scaffold your Docusaurus project with `create-docusaurus`, the website will be generated with basic Infima stylesheets and default styling. You may customize the styling by editing the `/src/css/custom.css` file.
|
||||
When you scaffold your Docusaurus project with `create-docusaurus`, the website will be generated with basic Infima stylesheets and default styling. You can override Infima CSS variables globally.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
/**
|
||||
* You can override the default Infima variables here.
|
||||
* Note: this is not a complete list of --ifm- variables.
|
||||
*/
|
||||
:root {
|
||||
--ifm-color-primary: #25c2a0;
|
||||
--ifm-color-primary-dark: rgb(33, 175, 144);
|
||||
--ifm-color-primary-darker: rgb(31, 165, 136);
|
||||
--ifm-color-primary-darkest: rgb(26, 136, 112);
|
||||
--ifm-color-primary-light: rgb(70, 203, 174);
|
||||
--ifm-color-primary-lighter: rgb(102, 212, 189);
|
||||
--ifm-color-primary-lightest: rgb(146, 224, 208);
|
||||
--ifm-code-font-size: 95%;
|
||||
}
|
||||
```
|
||||
|
|
@ -105,19 +112,36 @@ Alternatively, use the following tool to generate the different shades for your
|
|||
|
||||
<ColorGenerator/>
|
||||
|
||||
#### Dark Mode {#dark-mode}
|
||||
### Dark Mode {#dark-mode}
|
||||
|
||||
To customize the Infima variables for dark mode you can add the following to `src/css/custom.css`.
|
||||
In light mode, the `<html>` element has a `data-theme="light"` attribute; and in dark mode, it's `data-theme="dark"`. Therefore, you can scope your CSS to dark-mode-only by targeting `html` with a specific attribute.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
html[data-theme='dark'] {
|
||||
```css
|
||||
/* Overriding root Infima variables */
|
||||
[data-theme='dark'] {
|
||||
--ifm-color-primary: #4e89e8;
|
||||
--ifm-color-primary-dark: #5a91ea;
|
||||
/* any other colors you wish to overwrite */
|
||||
}
|
||||
/* Styling one class specially in dark mode */
|
||||
[data-theme='dark'] .purple-text {
|
||||
color: plum;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- TODO need more refinement here -->
|
||||
### Mobile View {#mobile-view}
|
||||
|
||||
Docusaurus uses `966px` as the cutoff between mobile screen width and desktop. If you want your layout to be different in the mobile view, you can use media queries.
|
||||
|
||||
```css
|
||||
.banner {
|
||||
padding: 4rem;
|
||||
}
|
||||
/** In mobile view, reduce the padding */
|
||||
@media screen and (max-width: 966px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CSS modules {#css-modules}
|
||||
|
||||
|
|
@ -150,7 +174,7 @@ function MyComponent() {
|
|||
}
|
||||
```
|
||||
|
||||
The class names which will be processed by webpack into a globally unique class name during build.
|
||||
The class names will be processed by webpack into a globally unique class name during build.
|
||||
|
||||
## CSS-in-JS {#css-in-js}
|
||||
|
||||
|
|
@ -172,9 +196,10 @@ npm install --save docusaurus-plugin-sass sass
|
|||
|
||||
2. Include the plugin in your `docusaurus.config.js` file:
|
||||
|
||||
```jsx {3} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
// highlight-next-line
|
||||
plugins: ['docusaurus-plugin-sass'],
|
||||
// ...
|
||||
};
|
||||
|
|
@ -186,7 +211,7 @@ module.exports = {
|
|||
|
||||
You can now set the `customCss` property of `@docusaurus/preset-classic` to point to your Sass/SCSS file:
|
||||
|
||||
```jsx {8} title="docusaurus.config.js"
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
|
|
@ -194,6 +219,7 @@ module.exports = {
|
|||
{
|
||||
// ...
|
||||
theme: {
|
||||
// highlight-next-line
|
||||
customCss: [require.resolve('./src/css/custom.scss')],
|
||||
},
|
||||
// ...
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
---
|
||||
description: Customize your site's appearance through creating your own theme components
|
||||
---
|
||||
|
||||
# Swizzling
|
||||
|
||||
In this section, we will introduce how customization of layout is done in Docusaurus.
|
||||
|
||||
> Déja vu...?
|
||||
|
||||
This section is similar to [Styling and Layout](./styling-layout.md), but this time, we will write actual React code instead of playing with stylesheets. We will talk about a central concept in Docusaurus: **swizzling**, which allows **deeper site customizations**.
|
||||
|
||||
In practice, swizzling permits to **swap a theme component with your own implementation**, and it comes in 2 patterns:
|
||||
|
||||
- [**Ejecting**](#ejecting): creates a **copy** of the original theme component, which you can fully **customize**
|
||||
- [**Wrapping**](#wrapping): creates a **wrapper** around the original theme component, which you can **enhance**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Why is it called swizzling?</summary>
|
||||
|
||||
**The name comes from Objective-C and Swift-UI**: [method swizzling](https://pspdfkit.com/blog/2019/swizzling-in-swift/) is the process of changing the implementation of an existing selector (method).
|
||||
|
||||
**For Docusaurus, component swizzling means providing an alternative component that takes precedence over the component provided by the theme.**
|
||||
|
||||
You can think of it as [Monkey Patching](https://en.wikipedia.org/wiki/Monkey_patch) for React components, enabling you to override the default implementation. Gatsby has a similar concept called [theme shadowing](https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/shadowing/).
|
||||
|
||||
To gain a deeper understanding of this, you have to understand [how theme components are resolved](./advanced/client.md#theme-aliases).
|
||||
|
||||
</details>
|
||||
|
||||
## Swizzling Process
|
||||
|
||||
### Overview
|
||||
|
||||
Docusaurus provides an convenient **interactive CLI** to swizzle components. You generally only need to remember the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle
|
||||
```
|
||||
|
||||
It will generate a new component your `src/theme` directory, which should look like this example:
|
||||
|
||||
````mdx-code-block
|
||||
<Tabs>
|
||||
<TabItem value="Ejecting">
|
||||
|
||||
```jsx title="src/theme/SomeComponent.js"
|
||||
import React from 'react';
|
||||
|
||||
export default function SomeComponent(props) {
|
||||
// You can fully customize this implementation
|
||||
// including changing the JSX, CSS and React hooks
|
||||
return (
|
||||
<div className="some-class">
|
||||
<h1>Some Component</h1>
|
||||
<p>Some component implementation details</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Wrapping">
|
||||
|
||||
```jsx title="src/theme/SomeComponent.js"
|
||||
import React from 'react';
|
||||
import SomeComponent from '@theme-original/SomeComponent';
|
||||
|
||||
export default function SomeComponentWrapper(props) {
|
||||
// You can enhance the original component,
|
||||
// including adding extra props or JSX elements around it
|
||||
return (
|
||||
<>
|
||||
<SomeComponent {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
To get an overview of all the themes and components available to swizzle, run:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle -- --list
|
||||
```
|
||||
|
||||
Use `--help` to see all available CLI options, or refer to the reference [swizzle CLI documentation](./cli.md#docusaurus-swizzle).
|
||||
|
||||
:::note
|
||||
|
||||
After swizzling a component, **restart your dev server** in order for Docusaurus to know about the new component.
|
||||
|
||||
:::
|
||||
|
||||
:::warning Prefer staying on the safe side
|
||||
|
||||
Be sure to understand [which components are **safe to swizzle**](#what-is-safe-to-swizzle). Some components are **internal implementation details** of a theme.
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
`docusaurus swizzle` is only an automated way to help you swizzle the component. You can also create the `src/theme/SomeComponent.js` file manually, and Docusaurus will [resolve it](./advanced/client.md#theme-aliases). There's no internal magic behind this command!
|
||||
|
||||
:::
|
||||
|
||||
### Ejecting {#ejecting}
|
||||
|
||||
Ejecting a theme component is the process of **creating a copy** of the original theme component, which you can **fully customize and override**.
|
||||
|
||||
To eject a theme component, use the swizzle CLI interactively, or with the `--eject` option:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle [theme name] [component name] -- --eject
|
||||
```
|
||||
|
||||
An example:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic Footer -- --eject
|
||||
```
|
||||
|
||||
This will copy the current `<Footer />` component's implementation to your site's `src/theme` directory. Docusaurus will now use this `<Footer>` component copy instead of the original one. You are now free to completely re-implement the `<Footer>` component.
|
||||
|
||||
```jsx title="src/theme/SomeComponent.js"
|
||||
import React from 'react';
|
||||
|
||||
export default function Footer(props) {
|
||||
return (
|
||||
<footer>
|
||||
<h1>This is my custom site footer</h1>
|
||||
<p>And it is very different from the original</p>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
Ejecting an [**unsafe**](#what-is-safe-to-swizzle) component can sometimes lead to copying a large amount of internal code, which you now have to maintain yourself. It can make Docusaurus upgrades more difficult, as you will need to migrate your customizations if the props received or internal theme APIs used have changed.
|
||||
|
||||
**Prefer [wrapping](#wrapping) whenever possible**: the amount of code to maintain is smaller.
|
||||
|
||||
:::
|
||||
|
||||
:::tip Re-swizzling
|
||||
|
||||
To keep ejected components up-to-date after a Docusaurus upgrade, re-run the eject command and compare the changes with `git diff`. You are also recommended to write a brief comment at the top of the file explaining what changes you have made, so that you could more easily re-apply your changes after re-ejection.
|
||||
|
||||
:::
|
||||
|
||||
### Wrapping {#wrapping}
|
||||
|
||||
Wrapping a theme component is the process of **creating a wrapper** around the original theme component, which you can **enhance**.
|
||||
|
||||
To wrap a theme component, use the swizzle CLI interactively, or with the `--wrap` option:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle [theme name] [component name] -- --wrap
|
||||
```
|
||||
|
||||
An example:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic Footer -- --wrap
|
||||
```
|
||||
|
||||
This will create a wrapper in your site's `src/theme` directory. Docusaurus will now use the `<FooterWrapper>` component instead of the original one. You can now add customizations around the original component.
|
||||
|
||||
```jsx title="src/theme/SomeComponent.js"
|
||||
import React from 'react';
|
||||
import Footer from '@theme-original/Footer';
|
||||
|
||||
export default function FooterWrapper(props) {
|
||||
return (
|
||||
<>
|
||||
<section>
|
||||
<h2>Extra section</h2>
|
||||
<p>This is an extra section that appears above the original footer</p>
|
||||
</section>
|
||||
<Footer {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>What is this <code>@theme-original</code> thing?</summary>
|
||||
|
||||
Docusaurus uses [theme aliases](./advanced/client.md#theme-aliases) to resolve the theme components to use. The newly created wrapper takes the `@theme/SomeComponent` alias. `@theme-original/SomeComponent` permits to import original component that the wrapper shadows without creating an infinite import loop where the wrapper imports itself.
|
||||
|
||||
</details>
|
||||
|
||||
:::tip
|
||||
|
||||
Wrapping a theme is a great way to **add extra components around existing one** without [ejecting](#ejecting) it. For example, you can easily add a custom comment system under each blog post:
|
||||
|
||||
```jsx title="src/theme/BlogPostItem.js"
|
||||
import React from 'react';
|
||||
import BlogPostItem from '@theme-original/BlogPostItem';
|
||||
import MyCustomCommentSystem from '@site/src/MyCustomCommentSystem';
|
||||
|
||||
export default function BlogPostItemWrapper(props) {
|
||||
return (
|
||||
<>
|
||||
<BlogPostItem {...props} />
|
||||
<MyCustomCommentSystem />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## What is safe to swizzle? {#what-is-safe-to-swizzle}
|
||||
|
||||
> With great power comes great responsibility
|
||||
|
||||
Some theme components are **internal implementation details** of a theme. Docusaurus allows you to swizzle them, but it **might be risky**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Why is it risky?</summary>
|
||||
|
||||
Theme authors (including us) might have to update their theme over time: changing the component props, name, file system location, types... For example, consider a component that receives two props `name` and `age`, but after a refactor, it now receives a `person` prop with the above two properties. Your component, which still expects these two props, will render `undefined` instead.
|
||||
|
||||
Moreover, internal components may simply disappear. If a component is called `Sidebar` and it's later renamed to `DocSidebar`, your swizzled component will be completely ignored.
|
||||
|
||||
**Theme components marked as unsafe may change in a backward-incompatible way between theme minor versions.** When upgrading a theme (or Docusaurus), your customizations might **behave unexpectedly**, and can even **break your site**.
|
||||
|
||||
</details>
|
||||
|
||||
For each theme component, the swizzle CLI will indicate **3 different levels of safety** declared by theme authors:
|
||||
|
||||
- **Safe**: this component is safe to be swizzled, its public API is considered stable, and no breaking changes should happen within a theme **major version**
|
||||
- **Unsafe**: this component is a theme implementation detail, not safe to be swizzled, and breaking changes might happen withing a theme **minor version**
|
||||
- **Forbidden**: the swizzle CLI will prevent you from swizzling this component, because it is not designed to be swizzled at all
|
||||
|
||||
:::note
|
||||
|
||||
Some components might be safe to wrap, but not safe to eject.
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
Don't be too **afraid to swizzle unsafe components**: just keep in mind that **breaking changes** might happen, and you might need to upgrade your customizations manually on minor version upgrades.
|
||||
|
||||
:::
|
||||
|
||||
:::note Report your use-case
|
||||
|
||||
If you have a **strong use-case for swizzling an unsafe component**, please [**report it here**](https://github.com/facebook/docusaurus/discussions/5468) and we will work together to find a solution to make it safe.
|
||||
|
||||
:::
|
||||
|
||||
## Which component should I swizzle? {#which-component-should-i-swizzle}
|
||||
|
||||
It is not always clear which component you should swizzle exactly to achieve the desired result. `@docusaurus/theme-classic`, which provides most of the theme components, has about [100 components](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-classic/src/theme)!
|
||||
|
||||
:::tip
|
||||
|
||||
To print an overview of all the `@docusaurus/theme-classic` components:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic -- --list
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
You can follow these steps to locate the appropriate component to swizzle:
|
||||
|
||||
1. **Component description.** Some components provide a short description, which is a good way to find the right one.
|
||||
2. **Component name.** Official theme components are semantically named, so you should be able to infer its function from the name. The swizzle CLI allows you to enter part of a component name to narrow down the available choices. For example, if you run `yarn swizzle @docusaurus/theme-classic`, and enter `Doc`, only the docs-related components will be listed.
|
||||
3. **Start with a higher-level component.** Components form a tree with some components importing others. Every route will be associated with one top-level component that the route will render (most of them listed in [Routing in content plugins](./advanced/routing.md#routing-in-content-plugins)). For example, all blog post pages have `@theme/BlogPostPage` as the topmost component. You can start with swizzling this component, and then go down the component tree to locate the component that renders just what you are targeting. Don't forget to unswizzle the rest by deleting the files after you've found the correct one, so you don't maintain too many components.
|
||||
4. **Read the [theme source code](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-classic/src/theme)** and use search wisely.
|
||||
|
||||
:::tip Just ask!
|
||||
|
||||
If you still have no idea which component to swizzle to achieve the desired effect, you can reach out for help in one of our [support channels](/community/support).
|
||||
|
||||
We also want to understand better your fanciest customization use-cases, so please [**report them**](https://github.com/facebook/docusaurus/discussions/5468).
|
||||
|
||||
:::
|
||||
|
||||
## Do I need to swizzle? {#do-i-need-to-swizzle}
|
||||
|
||||
Swizzling ultimately means you have to maintain some additional React code that interact with Docusaurus internal APIs. If you can, think about the following alternatives when customizing your site:
|
||||
|
||||
1. **Use CSS.** CSS rules and selectors can often help you achieve a decent degree of customization. Refer to [styling and layout](./styling-layout.md) for more details.
|
||||
2. **Use translations.** It may sound surprising, but translations are ultimately just a way to customize the text labels. For example, if your site's default language is `en`, you can still run `yarn write-translations -l en` and edit the `code.json` emitted. Refer to the [i18n tutorial](./i18n/i18n-tutorial.md) for more details.
|
||||
|
||||
:::tip
|
||||
|
||||
**The smaller, the better.** If swizzling is inevitable, prefer to swizzle only the relevant part and maintain as little code on your own as possible. Swizzling a small component often means less risk of **breaking changes** during upgrade.
|
||||
|
||||
[Wrapping](#wrapping) is also a far safer alternative to [ejecting](#ejecting).
|
||||
|
||||
:::
|
||||
|
||||
## Wrapping your site with `<Root>` {#wrapper-your-site-with-root}
|
||||
|
||||
The `<Root>` component is rendered at the **very top** of the React tree, above the theme `<Layout>`, and **never unmounts**. It is the perfect place to add stateful logic that should not be re-initialized across navigations (user authentication status, shopping card state...).
|
||||
|
||||
Swizzle it **manually** by creating a file at `src/theme/Root.js`:
|
||||
|
||||
```js title="src/theme/Root.js"
|
||||
import React from 'react';
|
||||
|
||||
// Default implementation, that you can customize
|
||||
export default function Root({children}) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Use this component to render React Context providers.
|
||||
|
||||
:::
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue