Repost from: Easy Documentation with Docusaurus
What is Docusaurus?
Docusaurus is a Static Site Generator (SSG) solution that allows us to build beautiful documentation sites with the least amount of effort. Powered by React and its rich ecosystem, Docusaurus comes with a complete feature set:
- CLI tool to initialize a Docusaurus application
- Markdown / MDX support
- Feature-packed templates
- Advanced features like Versioning, i18n, Search, and Theming
Learn more about Docusaurus at: https://docusaurus.io/docs
Create a React library
For the purposes of this article, we are going to create a UI library using React (https://reactjs.org/). Let’s start by creating an empty Nx Workspace.
1npx create-nx-workspace happyorg-docusaurus --preset=appsNext, we will install the @nrwl/react plugin to have the best integration between React and Nx in our workspace.
1npm install --save-dev @nrwl/reactWith the plugin installed, we can generate a React library now. This library is going to be published to a registry (eg: NPM) so we will tell the generator that by setting the --publishable flag.
1npx nx generate @nrwl/react:lib ui --publishable --import-path="@happyorg-docusaurus/ui"Publishable Libraries require
importPathto be specified. Read more at Nx Publishable and Buildable Libraries
The Nx React library generator gives us a fully set-up library that we can build, test, and lint against.
1.2└── libs/ui/3├── README.md4├── jest.config.ts5├── package.json6├── project.json7├── src/8│ ├── index.ts9│ └── lib/10│ ├── ui.module.css11│ ├── ui.spec.tsx12│ └── ui.tsx13├── tsconfig.json14├── tsconfig.lib.json15└── tsconfig.spec.jsonLet’s assume that our library is ready. Next, we are moving on to adding Docusaurus to write documentation for the library.
At this point, we can either generate a new React application, or we can leverage Storybook to render our library.
Add Docusaurus to Nx
Nx does not come with an official plugin for Docusaurus. However, Docusaurus comes with its own CLI to get started, and we can just use that in our Nx Workspace. We will generate a new Docusaurus application named docs with the classes template. We also generate this Docusaurus application in our apps/ directory.
1npx create-docusaurus docs classics apps/There are several other options that
create-docusaurusprovides. Feel free to explore on your own.
From here, we can cd apps/docs and run the scripts to start or build our Docusaurus application. This approach does come with a couple of hiccups:
- We always have to remember to
cd apps/docsto do anything with our Docusaurus application - We do not take advantage of Nx caching mechanism and task orchestration.
With the current setup, we can integrate Docusaurus with Nx with one small configuration. Open up workspace.json and add the following
1{2 "$schema": "./node_modules/nx/schemas/workspace-schema.json",3 "version": 2,4 "projects": {5 "ui": "libs/ui",6 "docs": {7 "root": "apps/docs"8 }9 }10}Here, we tell Nx that there is a project called docs under apps/docs.
Docusaurus and React 17
As of the time that this blog post is written, Docusaurus comes with React 17 while Nx React generators come with React 18. In addition to the configuration above, we need to update the React version of Docusaurus to React 18 before proceeding.
Let’s open apps/docs/package.json and update react with react-dom to ^18.0.0.
Depending on your package manager, you might need to update React dependencies with
--forcebecause Docusaurus sets React 17 as its peer dependencies.
Working with Docusaurus and Nx
With the above small addition to workspace.json, we can now stay at the root of our workspace and invoke the scripts in apps/docs/package.json. Let’s start by serving our Docusaurus application
1npx nx start docsThis command will subsequently invoke the start script in apps/docs/package.json which in turn invokes docusaurus start. We can use Nx to invoke any script in apps/docs/package.json, for example, build
1npx nx build docsCaching Docusaurus build
With the current setup, we will see that our docusaurus build isn’t cached. The reason is Nx does not know about the output of docusaurus build, which is apps/docs/build. Conveniently, we can tell Nx about that by adding the following property to apps/docs/package.json
1{2 "name": "docs",3 "version": "0.0.0",4 "private": true,5 "scripts": {6 ...7 },8 "dependencies": {9 ...10 },11 "devDependencies": {12 ...13 },14 "browserslist": {15 ...16 },17 "engines": {18 "node": ">=16.14"19 },20 "nx": {21 "targets": {22 "build": {23 "outputs": ["apps/docs/build"]24 }25 }26 }27}Now, running npx nx build docs might yield something like this
1> NX Successfully ran target build for project docs (15s)Running npx nx build docs the second time will then yield:
1> NX Successfully ran target build for project docs (17ms)Your time might differ from what is shown here.
Control Nx command inputs
In addition to specifying the outputs, we can also specify the inputs that can help Nx determine whether to invalidate the cache.
Docusaurus comes with both documentation and blogging capabilities. We’d like to continue using the documentation capability in this scenario, but we want to hold off on blogging. But, we do not want to remove everything that relates to blogging capability. With inputs configuration, we can tell Nx to invalidate the cache only if the files in apps/docs/docs change
1{2 "name": "docs",3 "version": "0.0.0",4 "private": true,5 "scripts": {6 ...7 },8 "dependencies": {9 ...10 },11 "devDependencies": {12 ...13 },14 "browserslist": {15 ...16 },17 "engines": {18 "node": ">=16.14"19 },20 "nx": {21 "targets": {22 "build": {23 "inputs": [24 "{projectRoot}/docs/*.(md|mdx)",25 "{projectRoot}/docs/**/*.(md|mdx)"26 ],27 "outputs": ["apps/docs/build"]28 }29 }30 }31}That’s it. Now only changes to markdown files under apps/docs/docs invalidate the cache of our Docusaurus build.
Bonus: Using Docusaurus Community Plugin
At Nx, we are extremely proud of our community. While there is no official Docusaurus plugin, there is one called nx-plus/docusaurus that is created by the Nx Community. We are going to use @nx-plus/docusaurus to add another Docusaurus application to our workspace.
First, we need to install the plugin
1npm install --save-dev @nx-plus/docusaurusNext, we can generate a Docusaurus app by using the plugin’s app generator
1npx nx generate @nx-plus/docusaurus:app plugin-docsYou can explore the options of
@nx-plus/docusaurus:appby using the flag--help
Now, we will have a new Docusaurus application under apps/plugin-docs. We can also start serving our new Docusaurus application with Nx
1npx nx serve plugin-docsWhat is the difference between using create-docusaurus and the plugin?
The main difference is Docusaurus dependencies are added to the root package.json per Single Version Policy which might or might not be in our favor depending on the nature of our workspace. In return, the Nx plugin provides a unified way to build and serve the Docusaurus application using targets
Conclusion
We did it! We finally have a great documentation solution for our library, provided by Docusaurus. In addition, we get to keep working both on the library and documentation under the same scalable and maintainable workspace provided by Nx.
Here are the things that we covered:
- How to generate an Nx Workspace and add a React library from scratch
- How to add a Docusaurus application in our Nx Workspace using
create-docusaurus - How to configure Nx with Docusaurus for discoverability and cache-ability
- How to use the Docusaurus community plugin instead of
create-docusaurus