@typhonjs-build-test/esm-d-ts v0.2.2
Provides a modern battle tested near zero configuration tool for ESM / ES Module / Javascript developers to generate
bundled Typescript declarations from ESM source code utilizing typed JSDoc
. This tooling can be employed to build
types for a primary export and one or more sub-path exports creating
independent ESM oriented / module based declarations utilizing import / export semantics. This tooling can be
employed by any project, but is particularly useful for library authors as there are many additional options covering
advanced use cases that library authors may encounter. Some of these optional advanced features include support for
re-exporting / re-bundling packages w/ TS declarations and thorough support for utilizing
imports / import conditions in a variety of flexible ways.
Please check out the package documentation here.
Installation:
It is recommended to install esm-d-ts
as a developer dependency in package.json
as follows:
{
"devDependencies": {
"@typhonjs-build-test/esm-d-ts": "0.2.0-next.1"
}
}
Presently the CLI and esm-d-ts
can not be installed or used globally; this will be addressed in a future update.
What's New:
The initial beta release of 0.2.0
features optional postprocessing. The first built-in postprocessing function
is support for @inheritDoc
. This is an unsupported JSDoc tag for Typescript and when types are generated any methods
or constructor functions that use @inheritDoc
have parameters that are typed as any
. You may add processInheritDoc
to a new config parameter postprocess
to enable support. It is also possible to create custom postprocessing
functions. There will be more details and documentation when 0.2.0
releases.
All dependencies updated along with peer dependency requirements of Rollup 3.3 - 4.x
and Typescript 5.1+
.
Overview:
There is a lot to unpack regarding how to set up a modern ESM Node package for efficient distribution that includes
TS declarations. At this time I'll point to the Typescript JSDoc informational resources
and the handbook description
on how to set up package.json
exports
with the types
condition. In time, I will expand the documentation and
resources available about esm-d-ts
covering new patterns unlocked from modern use cases combining JSDoc / TS capabilities. If you have questions please open a discussion in the issue tracker.
You may also stop by the TyphonJS Discord server for discussion & support.
A design goal behind esm-d-ts
is to provide flexibility and near-zero configuration, so that you may adapt and use
esm-d-ts
for a variety of build and usage scenarios. There are four main ways to configure esm-d-ts
:
- CLI immediate mode.
- CLI w/ configuration file.
- As a rollup plugin (100% zero configuration)
- Programmatically.
The Rollup plugin can be used w/ 100% zero configuration, but the other ways to set up esm-d-ts
require at minimum
an input
source file that should be the entry point for the given main or sub-path export. By default, when only
providing the input
entry point the bundled declaration file will be generated next to the input
source file with
the same name and .d.ts
extension. To generate the bundled declaration file at a specific location provide an
output
file path w/ extension. All the ways to configure esm-d-ts
accept the same configuration object. Except for
the Rollup plugin every way to configure esm-d-ts
accepts a list of configuration objects allowing you to completely
build all sub-path exports in one invocation of esm-d-ts
.
Example use cases:
The following examples demonstrate essential usage patterns. Each example will take into consideration a hypothetical
package that has a primary export and one sub-path export. The resulting package.json
exports field looks like this:
{
"exports": {
".": {
"types": "./src/main/index.d.ts",
"import": "./src/main/index.js"
},
"./sub": {
"types": "./src/sub/index.d.ts",
"import": "./src/sub/index.js"
}
}
}
Note: Typescript requires the types
condition to always be the first entry in a conditional block in exports
.
CLI
You may use the CLI via the command line or define a NPM script that invokes it. The CLI has two commands check
and
generate
. generate
has two aliases gen
& g
. The generate
command creates bundled declaration files. The
check
command is a convenient way to log diagnostics from the Typescript compiler checkJs
output that by default is
filtered to only display messages limited to the scope of the source files referenced from the entry point specified.
To receive help about the CLI use esm-d-ts --help
. Please use it to learn about additional CLI options available.
All examples will demonstrate NPM script usage.
There are two ways to use the CLI. The first is "immediate mode" where you directly supply an input / entry point. Presently, only one source file may be specified in "immediate mode".
{
"scripts": {
"types": "esm-d-ts gen src/main/index.js && esm-d-ts gen src/sub/index.js"
}
}
A more convenient way to define a project is through defining a configuration file. You may specify the --config
or
alias -c
to load a default config defined as ./esm-d-ts.config.js
or ./esm-d-ts.config.mjs
. You may also provide
a specific file path to a config after the --config
option.
{
"scripts": {
"types": "esm-d-ts gen --config"
}
}
The config file should be in ESM format and have a default export that provides one or a list of GenerateConfig
objects.
/**
* @type {import('@typhonjs-build-test/esm-d-ts').GenerateConfig[]}
*/
const config = [
{ input: './src/main/index.js' },
{ input: './src/sub/index.js' },
];
export default config;
Programmatic Usage
You may directly import checkDTS
or generateDTS
. These are asynchronous functions that can be invoked with top
level await.
import { checkDTS, generateDTS } from '@typhonjs-build-test/esm-d-ts';
// Generates TS declaration bundles.
await generateDTS([
{ input: './src/main/index.js' },
{ input: './src/sub/index.js' },
]);
// Log `checkJs` diagnostics.
await checkDTS([
{ input: './src/main/index.js' },
{ input: './src/sub/index.js' },
]);
Rollup Plugin
A Rollup plugin is accessible via generateDTS.plugin()
and takes the same configuration object as generateDTS
. When
using Rollup you don't have to specify the input
or output
parameters as it will use the Rollup options for input
and file
option for output
. An example use case in a Rollup configuration object follows:
import { generateDTS } from '@typhonjs-build-test/esm-d-ts';
// Rollup configuration object which will generate the `dist/index.d.ts` declaration file.
export default [
{
input: 'src/main/index.js',
plugins: [generateDTS.plugin()],
output: {
format: 'es',
file: 'dist/main/index.js'
}
},
{
input: 'src/sub/index.js',
plugins: [generateDTS.plugin()],
output: {
format: 'es',
file: 'dist/sub/index.js'
}
}
]
esm-d-ts
will generate respective bundled declarations next to the output file
:
dist/main/index.d.ts
dist/sub/index.d.ts
Presently esm-d-ts
only handles a single input entry point. A future update may expand this to handle multiple entry
points. If you need this functionality please open an issue.
There is no checkDTS
Rollup plugin.
Advanced Configuration
There are several more advanced configuration options and usage scenarios that are not discussed in this README
. You
may view a description of all options available in the documentation for
GenerateConfig /
GeneratePluginConfig
esm-d-ts
allows some rather advanced usage scenarios for library authors as well from handling imports
in
package.json
to further modification of the TS declarations generated through processing the intermediate AST /
Abstract Syntax Tree data.
Caveats
There is not a well-defined resource that pulls together all the concepts employed or available for using JSDoc to
generate Typescript declarations. esm-d-ts
has been in development since November 2021. It is completely working and
used in production for TyphonJS
packages and releases. A good recent article to review that covers JSDoc + Typescript
is Boost Your JavaScript with JSDoc Typing.
That being said presently esm-d-ts
does require a very particular way of linking all types in JSDoc across a project
requiring explicit use of import types
for all symbols linked. Even symbols from the local project. This likely is a foreign concept to most ESM / JS
developers used to IDE tooling that analyzes a project and allows local symbols to be referenced directly in @param
JSDoc tags. This will be solved by adding an analysis stage to esm-d-ts
in the future allowing local symbols to be
used without import types
.
The background on the current need for import types
is that with Typescript you must explicitly import all symbols
referenced in documentation or source code. Typescript performs "import / export elision" when transpiling TS to JS
source code removing imports only used in documentation. JSDoc when used in IDEs for ESM / JS development handles any
project analysis and documentation generation tooling also analyzes a project for local symbols.
An additional caveat to be aware of is that presently esm-d-ts
during the generation process creates intermediate TS
declaration files and by default they are located in the ./.dts
folder. It is recommended to add an exclusion rule
in a .gitignore
file for /.dts
. This also is on the roadmap to provide a completely in-memory generation process.
Roadmap
- Create an initial processing stage where
esm-d-ts
analyzes all exported symbols of the local code base allowing local symbols to be used withoutimport types
.
- Provide a way to manage the generation process entirely in memory. Presently the intermediate individual TS
declarations created in execution are stored in the
./.dts
folder. Add this folder to your.gitignore
. This is a limitation ofrollup-plugin-dts
& the TS compiler API utilized that uses the file system for bundling. I will be looking into submitting a PR torollup-plugin-dts
to handle virtual bundling.
- Generate source maps for the bundled TS declarations allowing IDEs to not just jump to the declarations, but also open linked source code.
Appreciation
I would like to bring awareness to the awesome underlying packages that make esm-d-ts
possible:
28 days ago
1 month ago
1 month ago
2 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
6 months ago
6 months ago
6 months ago
10 months ago
6 months ago
10 months ago
10 months ago
10 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago