Request for Comment (RFC) and a proposal for adopting JSDoc within the three.js project. The proposal intends to mitigate or solve two longstanding problems:
- Unofficial type definitions: Increasingly, many web projects and IDEs rely on type definitions in libraries, which three.js does not natively provide. The community maintains type definitions in a separate repository, with some overhead in cost and potential for mistakes or delays.
- Cost of maintaining localized documentation: API documentation for each class is maintained in hand-written HTML files, one file for each {class, language} pair. Maintainers contribute to the English-language documentation, while volunteers are largely responsible for identifying where English translations have changed and updating the localized versions.
Required if RFC is accepted.
JavaScript source files will be annotated with comments in JSDoc format, describing only those type definitions required for public-facing APIs. Human-readable API descriptions are not present at this milestone. From the JSDoc comments, release builds will generate TypeScript type definitions published to npm within the library.
Example: `src/core/Object.js`
/**
* @property {true} isObject3D
* @property {string} uuid
* @property {number} id
* @property {string} name
* @property {string} type
* @property {Object3D|null} parent
* @property {Object3D[]} children
* @property {Vector3} up
* @property {Vector3} position
* @property {Euler} rotation
* @property {Vector3} scale
* ...
*/
class Object3D extends EventDispatcher {
constructor() { ... }
/**
* @param {WebGLRenderer} renderer
* @param {Scene} scene
* @param {Camera} camera
* @param {BufferGeometry} geometry
* @param {Material} material
* @param {any} group
*/
onBeforeRender() { ... }
/**
* @param {WebGLRenderer} renderer
* @param {Scene} scene
* @param {Camera} camera
* @param {BufferGeometry} geometry
* @param {Material} material
* @param {any} group
*/
onAfterRender() { ... }
/**
* @param {Matrix4} matrix
*/
applyMatrix4(matrix) { ... }
...
}
We'll add typescript
to package.json#devDependencies
, and create a tsconfig.json
file with checkJS
and allowJS
options enabled. Editors like VSCode should then automatically provide hints when types are invalid. The code will run as expected in a browser, regardless of whether types are updated or compiled. At build time, TypeScript compiles the JSDoc comments to build/three.d.ts
, including API definitions for the entire library — including three
and three/addons/*
. See dts-buddy
for details on how this should work.
Optional, and depends on Milestone 1.
In addition to type annotations, JSDoc comments will now include human-readable descriptions, in English, for each public-facing API item. In a build step, tooling will process the JSDoc comments or the d.ts
files, and generate corresponding HTML pages identical to our current pages.
What about inline examples?
If desired, examples may be specified in one of two ways:
/**
* Description of Mesh class here.
*
* @example link_to_example.html
*
* @example
* Inline example below:
* ```javascript
* import { Mesh } from 'three';
* const mesh = new Mesh( geometry, material );
* ```
*/
class Mesh {
}
The former requires external files, and the latter is more verbose. Either will require some work on the HTML generator, which I believe is manageable. For simplicity, it may be preferable to leave these examples out of the API documentation and link to other examples or the manual instead.
Optional, and depends on Milestones 2–3.
JSDoc or type definitions are processed in a build step, assigning a unique key to each English-language comment (e.g. Mesh#geometry
). For each target output language, a human readable file (likely .csv or .yaml) is generated with content equivalent to:
Example: lang_it.csv
key | enUpdated | itUpdated | en | it |
---|---|---|---|---|
Mesh#geometry | 2021-05-04 | 2021-10-15 | An instance of BufferGeometry... | Un'istanza di BufferGeometry... |
Mesh#material | 2021-05-04 | 2021-10-15 | An instance of Material... | Un'istanza di Material... |
The lastUpdated
column will be maintained by the generator, allowing translators to more easily find sections where the English comments have changed since the last translation. Optionally, translations may be modified in external software like Microsoft Excel or Google Sheets.
In a final build step, these translation files are processed, and translated HTML pages for API documentation are generated alongside the English-language versions.
- By generating API documentation automatically, the process for maintaining API docs diverges from the process for maintaining the manual and other written resources on the website.
- JSDoc type annotations are admittedly verbose, and less ergonomic to write than TypeScript annotations. This problem could be mitigated if proposals for JavaScript Type Annotations are approved and implemented.
-
Rewrite three.js in TypeScript. None of the primary maintainers of three.js are currently interested in a change toward writing and maintaining TypeScript code.
-
Maintain
d.ts
type definitions manually. Manually updatingd.ts
files was attempted as a trial for several three.js releases. Cost of maintenance was prohibitive, and inability to validate hand-writtend.ts
files against source files created unacceptable problems.
- TypeScript cannot parse
@property
or@member
directives in JSDoc, breaking use ofObject.defineProperty
. See list of supported tags.- microsoft/TypeScript#7237
- microsoft/TypeScript#28730
- microsoft/TypeScript#15715
- dsherret/ts-morph#1427 (possible workaround without the TypeScript compiler)
@onsummer thank you! I hadn't run into tsd-jsdoc before, and will give that a closer look.
@AndrewRayCode JSDoc expresses types with similar precision to TypeScript definitions, and may be as strict or as loose as its authors require. Both support
any
, it's not unique to JSDoc. And we'll be using JSDoc to generate TypeScript type definitions, as explained above.Optionally, you can have the TypeScript compiler check JSDoc as well. Currently three.js type definitions are maintained by the community (https://github.com/three-types/three-ts-types), by hand, separately from the source code, and it's difficult for volunteers to keep that in sync. Generating typescript type definitions from JSDoc improves on that process.
Have you read through the proposal above? We would not be generating documentation from JSDoc — the JSDoc is used to generate TypeScript type definitions, which are then parsed into machine-readable CSV or YAML files. The system will then "generate corresponding HTML pages identical to our current pages." The user-facing API documentation (e.g. https://threejs.org/docs/#api/en/cameras/Camera) will not change at all.
API docs (like https://threejs.org/docs/#api/en/cameras/Camera) are best generated automatically. Tutorials (like https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene) are best hand-written. If you prefer to use tutorials that is fine, of course, but we're not trying to get rid of either.
@DefinitelyMaybe thank you!