[api-extractor] using `@microsoft/api-extractor-model` in browser
Summary
@microsoft/api-extractor-model now only supports reading model from a file, which introduces dependency to "os", "fs" and other dependencies specific to Node.js environment. If there were a loadFromObject, one could just import the JSON file, or even fetch it over the network, and use ApiModel in frontend code, as well.
Currently, ApiModel is used in static documentation generation tools, like @microsoft/api-documenter but making @microsoft/api-extractor-model isomorphic opens the door for more dynamic approaches, such as a react component library which provides building blocks for creating documentation out of a generated API model. Imagine something like this:
<ApiModelProvider apiModel={apiModelObject}>
...
</ApiModelProvider>
Then you can implement various components to be used in creating a documentation app, using the design system of your choice:
<Summary uid="@my-org/my-package!MyReactComponent:function(1)" />
<InterfaceTable uid="@my-org/my-package!MyReactComponentProps:interface" />
Suggestions
- Extract fs read/write part of the
@microsoft/api-extractor-modelinto a separate package, to make@microsoft/api-extractor-modelusable in both Node.js and browser. - Just provide a
loadFromObjectmethod to allow avoiding fs operations. Then one could at least shim node default modules to something dummy, to be able to build for browser.
I'd be more than happy to contribute to api-extractor eco-system by a react library that would provide building blocks in form of hooks and components, to be used in a documentation website.
Hey,
I fiddled around with this too since I like to build my own websites around documentation instead of using some pre-defined design + unchangeable components / markdown.
I thought I'd need to fork or PR a method like this, but as I dug deeper into the code of the load function: You can easily replicate what the load function does. Here is some tiny work around in how we solved it for our website running remix (so yes SSR, but if you shim it should also work directly in the browser):
const model = new ApiModel();
// Sadly the api-extractor-model package does not expose the interface type for the json object here, so I cast to any
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const apiPackage = ApiItem.deserialize(json as any, {
// This just is used for diagnostic purposes and nothing else at this point in deserialization
apiJsonFilename: '',
toolPackage: json.metadata.toolPackage,
toolVersion: json.metadata.toolVersion,
versionToDeserialize: json.metadata.schemaVersion,
tsdocConfiguration: new TSDocConfiguration(),
// I thought it was weird to cast here but this is also what they do, see references
}) as ApiPackage;
model.addMember(apiPackage);
From this point on you can just continue using the package like expected.
As seen in the references I stripped down the load function significantly and you can obviously include all the error checks yourself too, but it wasn't needed for our use case.
References: https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiPackage.ts#L133 https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiPackage.ts#L142 https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiPackage.ts#L180 https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiPackage.ts#L193-L199 https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiPackage.ts#L201 https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/src/model/ApiModel.ts#L65