rushstack icon indicating copy to clipboard operation
rushstack copied to clipboard

[api-extractor] using `@microsoft/api-extractor-model` in browser

Open alirezamirian opened this issue 3 years ago • 2 comments

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-model into a separate package, to make @microsoft/api-extractor-model usable in both Node.js and browser.
  • Just provide a loadFromObject method 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.

alirezamirian avatar Jun 12 '22 10:06 alirezamirian

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

iCrawl avatar Jun 30 '22 10:06 iCrawl