Rollup TypeScript: generating declarations for dist, cjs, and es modules

I am working on packaging a TypeScript library using rollup with declaration (d.ts) files, and I am aiming to generate both cjs and es versions.

After brainstorming, I came up with the following rollup configuration:

const {nodeResolve} = require('@rollup/plugin-node-resolve')
const nodeExternals = require('rollup-plugin-node-externals');
const json = require('@rollup/plugin-json');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('rollup-plugin-typescript2');
const packagePlugin = require('@mpen/rollup-plugin-package');
const cleanPlugin = require('@mpen/rollup-plugin-clean');
const findUp = require('find-up');
const {readFileSync} = require('fs');

module.exports = function rollupPresetTslib(opts = {}) {
    const tsconfigFile = findUp.sync(opts.tsconfig ?? 'tsconfig.json')
    const tsconfig = JSON.parse(readFileSync(tsconfigFile))

    return {
        input: tsconfig.files,
        plugins: [
            commonjs({
                include: 'node_modules/**',
            }),
            nodeExternals({
                builtins: true,
                deps: true,
                devDeps: false,
                peerDeps: true,
                optDeps: false,
            }),
            json(),
            typescript({
                abortOnError: process.env.NODE_ENV === 'production',
                tsconfig: tsconfigFile,
                ...opts.typescriptOptions,
            }),
            nodeResolve({
                extensions: ['.ts', '.json']
            }),
            packagePlugin(),
            cleanPlugin(),
            ...opts.plugins ?? [],
        ],
        watch: {
            buildDelay: 200,
            ...opts.watch,
        },
        preserveSymlinks: true,  
        preserveModules: false,  
        output: ['cjs', 'es'].map(format => ({
            dir: `dist/${format}`,
            format: format,
            sourcemap: true,
            inlineDynamicImports: false,
        })),
    }
}

The current output looks good but it only compiles to cjs:

https://i.sstatic.net/OaKSM.png

Attempting to output to both formats resulted in duplicate .d.ts files:

https://i.sstatic.net/PzP46.png

How can I achieve a single copy of the d.ts files along with cjs and es builds?

Answer №1

I have set up rollup to generate a single file at dist/index.d.ts, by appending the contents of my declarations.d.ts file to it using a postbuild script:

cat declarations.d.ts >> dist/index.d.ts

This is what my rollup.config.js looks like:

import commonjs from '@rollup/plugin-commonjs';
import clear from 'rollup-plugin-clear';
import ts from 'rollup-plugin-ts';
import styles from 'rollup-plugin-styles';
import image from '@rollup/plugin-image';
import { builtinModules } from 'module';
import pkg from './package.json';

module.exports = {
  input: pkg.source,
  output: [
    { file: pkg.main, format: 'cjs', sourcemap: true },
    { file: pkg.module, format: 'esm', sourcemap: true }
  ],
  external: [
    ...builtinModules,
    ...(pkg.dependencies ? Object.keys(pkg.dependencies) : []),
    ...(pkg.devDependencies ? Object.keys(pkg.devDependencies) : []),
    ...(pkg.peerDependencies ? Object.keys(pkg.peerDependencies) : [])
  ],
  watch: {
    include: 'lib/**'
  },
  plugins: [
    clear({
      targets: ['dist'],
      watch: false
    }),
    ts({
      hook: {
        // Rename declaration files to index.d.ts to avoid emitting duplicate declaration files with the same content
        outputPath: (path, kind) =>
          kind === 'declaration' ? './dist/index.d.ts' : path
      }
    }),
    image(),
    styles({
      modules: true,
      autoModules: /\.module\.\S+$/
    }),
    commonjs()
  ]
};

I trust this will be valuable to anyone in need of a similar solution.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide on utilizing the useContext hook in React/Next.js while incorporating TypeScript

As I embark on my journey in the world of TypeScript, I find myself working on a new project in Next.js using TypeScript. My goal is to incorporate authentication functionality into this project by utilizing createContext. Coming from a background in JavaS ...

Is it possible for an Interface's property to be a type that contains an array?

As I dive into the Angular code, I encountered a peculiar type for a property within an Interface named 'Origin' that has left me perplexed. Here's the snippet: export interface Origin { areaNum?: number; open?: { [key: stri ...

Avoid assigning an `any` value in an unsafe manner, especially when using a custom hook function

export const useSpecificHook = () => { return useContext(OurContext); }; export const useCustomProcessor = () => { const [notes, setNotes] = useState([]); const removeItems = () => { setItems([]); }; return { clearNotes, } ...

I am seeking guidance on how to manually provide data to an rxjs observable. Can anyone help me with this basic question?

I am interested in using an observable to communicate "exceptional states" to different parts of my Angular application, but I am struggling to grasp their functionality. In the code snippet below, I have created an observer object and turned it into an o ...

Error in typescript: The property 'exact' is not found in the type 'IntrinsicAttributes & RouteProps'

While trying to set up private routing in Typescript, I encountered the following error. Can anyone provide assistance? Type '{ exact: true; render: (routerProps: RouterProps) => Element; }' is not compatible with type 'IntrinsicAttribu ...

Utilizing Mongoose Typescript 2 Schema with fields referencing one another in different schemas

I'm currently facing an issue as I attempt to define 2 schemas in mongoose and typescript, where each schema has a field that references the other schema. Here's an example: const Schema1: Schema = new Schema({ fieldA: Number, fieldB: Sch ...

Guide on how to update an array within typed angular reactive forms

I'm currently working on finding a solution for patching a form array in a strongly-typed reactive Angular form. I've noticed that patchValue and setValue don't consistently work as expected with FormControl. Here's an example of the fo ...

Access to the 'currentUrlTree' property is restricted to the 'Router' class as it is marked as private and cannot be accessed externally

Currently, I am in the process of developing a login feature using jwt. However, I am encountering an error when attempting to retrieve the current URL of the active route as shown below. Error Message: [default] /Users/~/src/app/app.component.ts:51:75 P ...

Utilizing Typescript template strings for data inference

In coding practice, a specific convention involves denoting the child of an entity (meaning an association with another entity) with a '$' symbol. class Pet { owner$: any; } When making a reference to an entity child, users should have the opt ...

The term "primordials is not defined" is a common error

Whenever I attempt to run Gulp using the task runner, I am encountering this error message. I suspect it may be due to updating my npm project, but I'm unsure about how to resolve it. Should I try installing a different version of npm? >Failed to r ...

Unleash the power of Typescript and Node to create detailed REST API documentation!

Is it possible to generate REST API documentation using https://github.com/TypeStrong/typedoc similar to what can be done with ? I would appreciate any recommendations on leveraging TypeScript types for creating REST API documentation (specifically within ...

Guide on properly defining typed props in Next.js using TypeScript

Just diving into my first typescript project and finding myself in need of some basic assistance... My code seems to be running smoothly using npm run dev, but I encountered an error when trying to use npm run build. Error: Binding element 'allImageD ...

Using "array_agg" in a "having clause" with Sequelize

I am facing a particular scenario with my database setup. I have three tables named computers, flags, and computerFlags that establish relationships between them. The structure of the computerFlags table is as follows: computerName | flagId computer1 | ...

What could be causing Sequelizer to overlook my username?

I have configured a NestJS project and implemented Sequelize to interact with my database. My setup includes a database provider and module that are designed to be used globally. Here is how they are structured: database.module.ts: import {Global, Module ...

Sorting data by percentages in AngularJS

I am currently facing an issue with sorting percentages in a table column. Despite using methods like parseFloat and other AngularJS (1.5.0) sorting techniques, the percentages are not being sorted as expected. [ {percentage: 8.82} {percentage: 0. ...

Understanding the meaning of `.then()` in Excel JavaScript involves recognizing its function

Excel.run(function (context) { var sheet = context.workbook.worksheets.getItem("Sample"); var range = sheet.getRange("B2:C5"); range.load("address"); return context.sync() .then(function () { ...

React TypeScript - Module not found

Organizational structure: src - components - About.tsx In an attempt to optimize performance, I am experimenting with lazy loading: const About = React.lazy(() => import('components/About')); However, Visual Studio Code is flagging &ap ...

In TypeScript, inferring argument types

Here is the code snippet in question: type Inferred<T> = T extends (...args: (infer UnionType)[]) => any ? UnionType : never function f(first: 'first', second: 'second', bool: boolean) {} type T = Inferred<typeof f> // ...

Generic partial application fails type checking when passing a varargs function argument

Here is a combinator I've developed that converts a function with multiple arguments into one that can be partially applied: type Tuple = any[]; const partial = <A extends Tuple, B extends Tuple, C> (f: (...args: (A & B)[]) => C, ...a ...

Netlify is unable to install a forked npm module due to the failure to retrieve metadata

I recently forked and modified the g-sheets-api module. Here is my version: https://github.com/lpares12/g-sheets-api After making the modifications, I installed it in my web project using the following command: npm install git+https://github.com/lpares12/ ...