Skip to content

Commit

Permalink
feat: generate .d.mts and .d.cts declarations (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoxiangmoe authored Jul 18, 2023
1 parent 87e5035 commit 9fd918f
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 25 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default {
}
```

You can either use `unbuild` key in `package.json` or `build.config.{js,ts,json}` to specify configuration.
You can either use `unbuild` key in `package.json` or `build.config.{js,cjs,mjs,ts,mts,cts,json}` to specify configuration.

See options [here](./src/types.ts).

Expand All @@ -109,8 +109,14 @@ export default defineBuildConfig({
// Change outDir, default is 'dist'
outDir: 'build',

// Generates .d.ts declaration file
declaration: true,
/**
* * `compatible` means "src/index.ts" will generate "dist/index.d.mts", "dist/index.d.cts" and "dist/index.d.ts".
* * `node16` means "src/index.ts" will generate "dist/index.d.mts" and "dist/index.d.cts".
* * `true` is equivalent to `compatible`.
* * `false` will disable declaration generation.
* * `undefined` will auto detect based on "package.json". If "package.json" has "types" field, it will be `"compatible"`, otherwise `false`.
*/
declaration: 'compatible',
})
```

Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"license": "MIT",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
"import": "./dist/index.mjs"
}
},
"types": "./dist/index.d.ts",
Expand Down
9 changes: 6 additions & 3 deletions src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ export function inferEntries(
for (const output of outputs) {
// Supported output file extensions are `.d.ts`, `.cjs` and `.mjs`
// But we support any file extension here in case user has extended rollup options
const outputSlug = output.file.replace(/(\*[^/\\]*|\.d\.ts|\.\w+)$/, "");
const outputSlug = output.file.replace(
/(\*[^/\\]*|\.d\.(m|c)?ts|\.\w+)$/,
""
);
const isDir = outputSlug.endsWith("/");

// Skip top level directory
Expand All @@ -128,7 +131,7 @@ export function inferEntries(
const SOURCE_RE = new RegExp(`(?<=/|$)${d}${isDir ? "" : "\\.\\w+"}$`);
return sourceFiles
.find((i) => SOURCE_RE.test(i))
?.replace(/(\.d\.ts|\.\w+)$/, "");
?.replace(/(\.d\.(m|c)?ts|\.\w+)$/, "");
}, undefined as any);

if (!input) {
Expand All @@ -144,7 +147,7 @@ export function inferEntries(
entries.find((i) => i.input === input) ||
entries[entries.push({ input }) - 1];

if (output.file.endsWith(".d.ts")) {
if (/\.d\.(m|c)?ts$/.test(output.file)) {
dts = true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/builder/mkdist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function mkdistBuild(ctx: BuildContext) {
distDir,
format: entry.format,
cleanDist: false,
declaration: entry.declaration,
declaration: !!entry.declaration,
pattern: entry.pattern,
// @ts-ignore
ext: entry.ext,
Expand Down
50 changes: 39 additions & 11 deletions src/builder/rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,24 +179,52 @@ export async function rollupBuild(ctx: BuildContext) {
await ctx.hooks.callHook("rollup:dts:options", ctx, rollupOptions);
const typesBuild = await rollup(rollupOptions);
await ctx.hooks.callHook("rollup:dts:build", ctx, typesBuild);
// #region cjs
if (ctx.options.rollup.emitCJS) {
await typesBuild.write({
dir: resolve(ctx.options.rootDir, ctx.options.outDir),
entryFileNames: "[name].d.cts",
chunkFileNames: (chunk) => getChunkFilename(ctx, chunk, "d.cts"),
});
}
// #endregion
// #region mjs
await typesBuild.write({
dir: resolve(ctx.options.rootDir, ctx.options.outDir),
format: "esm",
entryFileNames: "[name].d.mts",
chunkFileNames: (chunk) => getChunkFilename(ctx, chunk, "d.mts"),
});
// #endregion
// #region .d.ts for node10 compatibility (TypeScript version < 4.7)
if (
ctx.options.declaration === true ||
ctx.options.declaration === "compatible"
) {
await typesBuild.write({
dir: resolve(ctx.options.rootDir, ctx.options.outDir),
entryFileNames: "[name].d.ts",
chunkFileNames: (chunk) => getChunkFilename(ctx, chunk, "d.ts"),
});
}
// #endregion
}

await ctx.hooks.callHook("rollup:done", ctx);
}

export function getRollupOptions(ctx: BuildContext): RollupOptions {
const getChunkFilename = (chunk: PreRenderedChunk, ext: string) => {
if (chunk.isDynamicEntry) {
return `chunks/[name].${ext}`;
}
// TODO: Find a way to generate human friendly hash for short groups
return `shared/${ctx.options.name}.[hash].${ext}`;
};
const getChunkFilename = (
ctx: BuildContext,
chunk: PreRenderedChunk,
ext: string
) => {
if (chunk.isDynamicEntry) {
return `chunks/[name].${ext}`;
}
// TODO: Find a way to generate human friendly hash for short groups
return `shared/${ctx.options.name}.[hash].${ext}`;
};

export function getRollupOptions(ctx: BuildContext): RollupOptions {
return (<RollupOptions>{
input: Object.fromEntries(
ctx.options.entries
Expand All @@ -209,7 +237,7 @@ export function getRollupOptions(ctx: BuildContext): RollupOptions {
dir: resolve(ctx.options.rootDir, ctx.options.outDir),
entryFileNames: "[name].cjs",
chunkFileNames: (chunk: PreRenderedChunk) =>
getChunkFilename(chunk, "cjs"),
getChunkFilename(ctx, chunk, "cjs"),
format: "cjs",
exports: "auto",
interop: "compat",
Expand All @@ -221,7 +249,7 @@ export function getRollupOptions(ctx: BuildContext): RollupOptions {
dir: resolve(ctx.options.rootDir, ctx.options.outDir),
entryFileNames: "[name].mjs",
chunkFileNames: (chunk: PreRenderedChunk) =>
getChunkFilename(chunk, "mjs"),
getChunkFilename(ctx, chunk, "mjs"),
format: "esm",
exports: "auto",
generatedCode: { constBindings: true },
Expand Down
11 changes: 9 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface BaseBuildEntry {
input: string;
name?: string;
outDir?: string;
declaration?: boolean;
declaration?: "compatible" | "node16" | boolean;
}

export interface UntypedBuildEntry extends BaseBuildEntry {
Expand Down Expand Up @@ -64,7 +64,14 @@ export interface BuildOptions {
rootDir: string;
entries: BuildEntry[];
clean: boolean;
declaration?: boolean;
/**
* * `compatible` means "src/index.ts" will generate "dist/index.d.mts", "dist/index.d.cts" and "dist/index.d.ts".
* * `node16` means "src/index.ts" will generate "dist/index.d.mts" and "dist/index.d.cts".
* * `true` is equivalent to `compatible`.
* * `false` will disable declaration generation.
* * `undefined` will auto detect based on "package.json". If "package.json" has "types" field, it will be `"compatible"`, otherwise `false`.
*/
declaration?: "compatible" | "node16" | boolean;
outDir: string;
stub: boolean;
externals: (string | RegExp)[];
Expand Down
11 changes: 8 additions & 3 deletions test/auto.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,14 @@ describe("inferEntries", () => {
const result = inferEntries(
{
exports: {
types: "dist/test.d.ts",
import: "dist/test.mjs",
require: "dist/test.cjs",
import: {
types: "dist/test.d.mts",
default: "dist/test.mjs",
},
require: {
types: "dist/test.d.cts",
default: "dist/test.cjs",
},
},
},
["src/", "src/test.ts"]
Expand Down

0 comments on commit 9fd918f

Please sign in to comment.