feat(plugin): add externalJsonProps option to improve build perf#1279
feat(plugin): add externalJsonProps option to improve build perf#1279
Conversation
…prove build performance Add new externalJsonProps configuration option that extracts large JSON props from MDX files into separate .json files loaded via require(). This bypasses MDX AST parsing for large JSON objects, significantly improving build times for large OpenAPI specs. The option is enabled by default due to the significant performance benefits (25x faster builds in benchmarks). Users can opt-out by setting externalJsonProps: false. Changes: - Add externalizeJsonProps.ts utility for JSON extraction - Integrate with doc generation and cleanup flows - Add TypeScript types and Joi validation (default: true) - Update README with documentation and usage examples - Update .gitignore to exclude generated JSON files
412f242 to
cb08d69
Compare
|
Size Change: +263 B (+0.01%) Total Size: 2.17 MB
ℹ️ View Unchanged
|
|
Visit the preview URL for this PR (updated for commit cb08d69): https://docusaurus-openapi-36b86--pr1279-hd8ujlaq.web.app (expires Sun, 15 Feb 2026 20:52:15 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: bf293780ee827f578864d92193b8c2866acd459f |
There was a problem hiding this comment.
I'm not a fan of manipulating strings using RegExps like this and would have prefered to manipulate the data in a structured way before emitting the markdown content.
But if it worksas-is, that's already nice.
Also wondering how did you define the threshold. Isn't it faster if you always externalize json files?
At the same time, using blocking IOs might slow down code generation if you emit many tiny json files. But not sure it would be a problem if you emitted those files asynchronously.
| * @returns The transformed MDX and list of JSON files to write | ||
| */ | ||
| export function externalizeJsonPropsSimple( | ||
| mdx: string, |
There was a problem hiding this comment.
Not super fan of processing MDX as a string here, but hey if that works it's better than nothing.
If you are keen to refactor things, just an idea that could likely produce a more robust implementation:
create()return an object containing the string + external filesrender([])can accept this new object type and also return it (merging all the external files to create)
Implements slorber's suggestion from PR #1279 to handle externalization at the source (in create()) rather than post-processing MDX strings. Changes: - Add externalization context system to utils.ts - Modify create() to detect large JSON props and externalize inline - Remove externalizeJsonProps.ts (no longer needed) - Update index.ts to use context-based approach This is more architecturally clean as the externalization decision happens where the component is created, not via regex parsing afterward.
* refactor(plugin): externalize JSON props at source in create() Implements slorber's suggestion from PR #1279 to handle externalization at the source (in create()) rather than post-processing MDX strings. Changes: - Add externalization context system to utils.ts - Modify create() to detect large JSON props and externalize inline - Remove externalizeJsonProps.ts (no longer needed) - Update index.ts to use context-based approach This is more architecturally clean as the externalization decision happens where the component is created, not via regex parsing afterward. * refactor(plugin): drop size threshold for externalization Always externalize eligible props (responses, parameters, body, schema) regardless of size. This simplifies the logic and provides consistent behavior - users either have externalization on or off, no edge cases. * refactor(plugin): use one JSON file per component with spread props Implements slorber's suggestion to externalize all props for a component into a single JSON file and use spread syntax: <StatusCodes {...require('./add-pet.StatusCodes.json')} /> Instead of separate files per prop: <StatusCodes responses={require('./add-pet.responses.json')} /> Benefits: - Cleaner file organization (one file per component vs per prop) - Simpler logic (no need to track which props to externalize) - All props for a component are colocated in one file * refactor(plugin): use runWithExternalization wrapper for cleaner API Provides a cleaner API similar to AsyncLocalStorage pattern but uses module-level state internally (AsyncLocalStorage isn't available in browser bundles that Docusaurus creates). The runWithExternalization() function wraps generation with try/finally to ensure context is always cleaned up, providing the same safety guarantees as AsyncLocalStorage.run().
Major performance improvement: The new `externalJsonProps` option (enabled by default) dramatically reduces build times and bundle sizes by externalizing large JSON props from MDX files. - New `externalJsonProps` plugin option significantly improves build performance - Sticky positioning for the API Explorer right panel improves UX on long API pages - Dynamic request body updates when switching anyOf/oneOf tabs #### 🚀 New Feature - feat(plugin): add externalJsonProps option (enabled by default) to improve build performance (#1279) - feat(theme): add sticky positioning to API Explorer right panel (#1288) - feat: dynamically update request body when anyOf/oneOf tab changes (#1287) #### 🐛 Bug Fix - fix: render inline enum values in anyOf schemas (#1286) - fix: generate correct examples for different request content types (#1284) #### 🏠 Refactoring - refactor: change plugin and theme types.ts to types.d.ts (#1281) - refactor: externalize using create() and drop size threshold requirement (#1280) #### 📝 Documentation - docs: sync README and intro.mdx with plugin docs #### 🤖 Dependencies - chore(deps): bump lodash from 4.17.21 to 4.17.23 (#1282) #### Committers: 3 - dependabot[bot] - Ollie Monk - Steven Serrata
Major performance improvement: The new `externalJsonProps` option (enabled by default) dramatically reduces build times and bundle sizes by externalizing large JSON props from MDX files. - New `externalJsonProps` plugin option significantly improves build performance - Sticky positioning for the API Explorer right panel improves UX on long API pages - Dynamic request body updates when switching anyOf/oneOf tabs #### 🚀 New Feature - feat(plugin): add externalJsonProps option (enabled by default) to improve build performance (#1279) - feat(theme): add sticky positioning to API Explorer right panel (#1288) - feat: dynamically update request body when anyOf/oneOf tab changes (#1287) #### 🐛 Bug Fix - fix: render inline enum values in anyOf schemas (#1286) - fix: generate correct examples for different request content types (#1284) #### 🏠 Refactoring - refactor: change plugin and theme types.ts to types.d.ts (#1281) - refactor: externalize using create() and drop size threshold requirement (#1280) #### 📝 Documentation - docs: sync README and intro.mdx with plugin docs #### 🤖 Dependencies - chore(deps): bump lodash from 4.17.21 to 4.17.23 (#1282) #### Committers: 3 - dependabot[bot] - Ollie Monk - Steven Serrata
Description
Add new externalJsonProps configuration option that extracts large JSON props from MDX files into separate .json files loaded via require(). This bypasses MDX AST parsing for large JSON objects (>500 chars), significantly improving build times for large OpenAPI specs.
The option is enabled by default due to the significant performance benefits (up to 25x faster builds in benchmarks). Users can opt-out by setting externalJsonProps: false.
Changes:
Motivation and Context
Large json props can greatly increase build times. See facebook/docusaurus#11664 (reply in thread) for background.
How Has This Been Tested?
Tested using the Harvester OpenAPI spec