Skip to content

Externalize using create() and drop size threshold requirement#1280

Merged
sserrata merged 4 commits intomainfrom
refactor/externalize-at-source
Jan 21, 2026
Merged

Externalize using create() and drop size threshold requirement#1280
sserrata merged 4 commits intomainfrom
refactor/externalize-at-source

Conversation

@sserrata
Copy link
Member

Description

Implements changes suggested by @slorber in #1279

Motivation and Context

  • Drops regex string parser for more structured approach
  • Drop size threshold for externalization which means all props will be externalized regardless of size

How Has This Been Tested?

This deploy preview

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.
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.
@sserrata sserrata self-assigned this Jan 20, 2026
@sserrata sserrata added the enhancement New feature or request label Jan 20, 2026
@github-actions
Copy link

github-actions bot commented Jan 20, 2026

Size Change: 0 B

Total Size: 2.17 MB

ℹ️ View Unchanged
Filename Size
demo/.docusaurus/codeTranslations.json 2 B
demo/.docusaurus/docusaurus.config.mjs 14.7 kB
demo/.docusaurus/globalData.json 60.5 kB
demo/.docusaurus/i18n.json 372 B
demo/.docusaurus/registry.js 87.6 kB
demo/.docusaurus/routes.js 82.8 kB
demo/.docusaurus/routesChunkNames.json 34.3 kB
demo/.docusaurus/site-metadata.json 1.51 kB
demo/build/assets/css/styles.********.css 163 kB
demo/build/assets/js/main.********.js 643 kB
demo/build/assets/js/runtime~main.********.js 20.9 kB
demo/build/index.html 92.3 kB
demo/build/petstore/add-pet/index.html 29.3 kB
demo/build/petstore/create-user/index.html 24 kB
demo/build/petstore/create-users-with-array-input/index.html 24.1 kB
demo/build/petstore/create-users-with-list-input/index.html 24.1 kB
demo/build/petstore/delete-order/index.html 23.8 kB
demo/build/petstore/delete-pet/index.html 24.1 kB
demo/build/petstore/delete-user/index.html 24.3 kB
demo/build/petstore/find-pets-by-status/index.html 24.8 kB
demo/build/petstore/find-pets-by-tags/index.html 25.4 kB
demo/build/petstore/get-inventory/index.html 23.1 kB
demo/build/petstore/get-order-by-id/index.html 24.1 kB
demo/build/petstore/get-pet-by-id/index.html 24.9 kB
demo/build/petstore/get-user-by-name/index.html 24.4 kB
demo/build/petstore/login-user/index.html 24.9 kB
demo/build/petstore/logout-user/index.html 23.7 kB
demo/build/petstore/new-pet/index.html 24.3 kB
demo/build/petstore/pet/index.html 22.5 kB
demo/build/petstore/place-order/index.html 23.3 kB
demo/build/petstore/schemas/apiresponse/index.html 24.6 kB
demo/build/petstore/schemas/cat/index.html 38.8 kB
demo/build/petstore/schemas/category/index.html 25.7 kB
demo/build/petstore/schemas/dog/index.html 39 kB
demo/build/petstore/schemas/honeybee/index.html 39.1 kB
demo/build/petstore/schemas/id/index.html 22.7 kB
demo/build/petstore/schemas/order/index.html 26.8 kB
demo/build/petstore/schemas/pet/index.html 38.6 kB
demo/build/petstore/schemas/tag/index.html 24.1 kB
demo/build/petstore/schemas/user/index.html 46.4 kB
demo/build/petstore/store/index.html 21.5 kB
demo/build/petstore/subscribe-to-the-store-events/index.html 30.2 kB
demo/build/petstore/swagger-petstore-yaml/index.html 30.2 kB
demo/build/petstore/update-pet-with-form/index.html 24.3 kB
demo/build/petstore/update-pet/index.html 24.7 kB
demo/build/petstore/update-user/index.html 24.3 kB
demo/build/petstore/upload-file/index.html 24.1 kB
demo/build/petstore/user/index.html 22.2 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

Visit the preview URL for this PR (updated for commit bb1e3a2):

https://docusaurus-openapi-36b86--pr1280-nxk0yj1l.web.app

(expires Thu, 19 Feb 2026 20:24:29 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: bf293780ee827f578864d92193b8c2866acd459f

Copy link
Contributor

@slorber slorber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks more robust than before 👍

* Module-level externalization context.
* Set via setExternalizationContext() before generating MDX.
*/
let externalizationContext: ExternalizationContext | null = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not a big deal in your context, but if you want to get rid of the global module state, one option could be to leverage node async local storage: https://nodejs.org/api/async_context.html#asynclocalstoragerunstore-callback-args

It's like React context but for async code, useful to pass context to a tree without having to pass explicit function attributes

Copy link
Member Author

@sserrata sserrata Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I wasn't able to get this to work as it appears to only be available in node and not the browser. The builds were failing since docusaurus builds for both client and server.

Comment on lines +26 to +123
for (const [key, value] of Object.entries(rest)) {
propString += `\n ${key}={${JSON.stringify(value)}}`;
// Check if this prop should be externalized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering, why not create one json file per JSX tag.
Instead of handling props one by one, you could do:

<tag {...require("./myApi.props.json")}/>

You can spread children too this way, it doesn't really need special handling

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

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
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().
@sserrata sserrata force-pushed the refactor/externalize-at-source branch from 9d985c9 to bb1e3a2 Compare January 20, 2026 20:20
@sserrata sserrata merged commit bfe7bd8 into main Jan 21, 2026
10 checks passed
@sserrata sserrata deleted the refactor/externalize-at-source branch January 21, 2026 15:42
sserrata added a commit that referenced this pull request Jan 27, 2026
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
@sserrata sserrata mentioned this pull request Jan 27, 2026
sserrata added a commit that referenced this pull request Jan 27, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants