Creating a modern JavaScript library can be quite an undertaking due to the myriad of tools and configurations available. Today, we’ll walk you through building your own NPM library using Rollup and TypeScript. Let’s break down the provided configuration files and understand the essentials.
Setting up Rollup Configuration
Rollup is a module bundler that allows you to bundle your JavaScript files into different formats such as CommonJS (cjs
) and ECMAScript modules (esm
). Here is the Rollup configuration:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts'; // create type def files
import terser from '@rollup/plugin-terser'; // minify
import peerDepsExternal from 'rollup-plugin-peer-deps-external'; // add peer deps in bundle
import postcss from 'rollup-plugin-postcss';
const packageJson = require('./package.json');
export default [
{
input: 'src/index.ts',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true,
},
{
file: packageJson.module,
format: 'esm',
sourcemap: true,
},
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({ tsconfig: './tsconfig.json' }),
postcss({
minimize: true,
}),
terser(),
],
external: [
'react',
'react-dom'
],
},
{
input: 'src/index.ts',
output: [{ file: 'dist/types.d.ts', format: 'es' }],
plugins: [dts.default()],
external: [/\.css$/, /\.scss$/],
},
];
Configuration Array
The configuration exports an array of configurations. Each configuration object tells Rollup how to create a separate bundle. This configuration will produce two bundles.
First Configuration (Main Library Bundle)
- input:
'src/index.ts'
- This specifies the entry point for Rollup. It will begin bundling from this file.
- output:
- An array detailing the outputs of the bundling process.
- file:
packageJson.main
- The filename to output the bundled code. This value is dynamically sourced from a
package.json
file (presumed to be imported earlier). - format:
'cjs'
- This specifies the output as CommonJS, typically utilized in Node.js environments.
- sourcemap:
true
- Generates a sourcemap, which is useful for debugging.
- The filename to output the bundled code. This value is dynamically sourced from a
- file:
packageJson.module
- Another filename for the bundled output. Again, its value is fetched from
package.json
. - format:
'esm'
- Specifies the output as ES modules, a modern JavaScript module system.
- sourcemap:
true
- Generates a sourcemap for this format as well.
- Another filename for the bundled output. Again, its value is fetched from
- file:
- An array detailing the outputs of the bundling process.
- plugins:
- An array of plugins used during the bundling process.
peerDepsExternal()
: Prevents peer dependencies from being bundled. This ensures peer dependencies are treated as ‘external’ to the bundle.resolve()
: Allows Rollup to resolve and bundle modules from ‘node_modules’.commonjs()
: Converts CommonJS modules to ES6, making them compatible with the Rollup bundle.typescript({ tsconfig: './tsconfig.json' })
: Compiles TypeScript files to JavaScript. The configuration is derived from./tsconfig.json
.postcss({ minimize: true })
: Processes CSS imports to minimize the CSS.terser()
: Minifies the bundled output, reducing its size.
- An array of plugins used during the bundling process.
- external:
['react', 'react-dom']
- This configuration specifies that
react
andreact-dom
should be treated as ‘external’ dependencies. This means they won’t be bundled into the final output but are expected to be present in the consuming environment.
- This configuration specifies that
Second Configuration (Type Definitions)
- input:
'src/index.ts'
- Uses the same entry point as the first configuration.
- output:
- file:
'dist/types.d.ts'
- The output file for type definitions.
- format:
'es'
- The format is set as ES modules.
- file:
- plugins:
- An array of a single plugin.
dts.default()
: This plugin produces a bundled TypeScript definition file.
- An array of a single plugin.
- external:
/\.css$/, /\.scss$/
- Specifies that CSS and SCSS files are ‘external’, implying they won’t be included in this bundle. This makes sense, as this bundle is purely for type definitions.
In summary, this configuration is set up to produce two separate bundles:
- The main JavaScript library bundle, which is compiled from TypeScript, processed with PostCSS, and minified.
- A bundled TypeScript definition file, which describes the types in the library for TypeScript users.
TypeScript Configuration
You’ll also need two TypeScript configurations:
- The main
tsconfig.json
, which has configurations for the library itself. - The
tsconfig.node.json
, designed to handle certain node configurations.
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"jsx": "react",
"outDir": "dist",
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"noImplicitAny": false,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
// tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
}
}
Remember, TypeScript configurations describe how your TypeScript code is transpiled. Some important points from this configuration include:
- Targeting ES2020.
- Enabling JSX syntax for React.
- Specifying linting options to ensure code quality.
PostCSS Configuration
Lastly, you need a PostCSS configuration. This indicates that your library is likely making use of styles. PostCSS will process your styles, and with these plugins.
module.exports = {
plugins: {
autoprefixer: {},
'postcss-import': {}
},
};
Steps to Build Your NPM Library
Now, with the provided configurations, here’s a step-by-step guide:
- Setup Your Project: Start with a fresh directory and initialize it with
npm init
. Fill in the necessary details. - Install Dependencies: Based on your configurations, install the necessary dependencies:
npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-dts @rollup/plugin-terser rollup-plugin-peer-deps-external rollup-plugin-postcss typescript postcss tailwindcss autoprefixer postcss-import
- Add the Provided Configurations: Add the provided Rollup, TypeScript, and PostCSS configurations into your project directory.
- Add the required configurations: Add this snippit to your
package.json
other project importing your library will know wherer to find the files needed:
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "rollup -c --bundleConfigAsCjs",
},
- Write Your Library Code: Create a
src
directory and start coding your library. Remember, based on the configuration, the entry file issrc/index.ts
. - Build the Library: Use the command
npm run build
to bundle your library. This will create the bundles as per your Rollup configuration. - Publish to NPM: Once you’re ready to share your library, make sure you are logged in to your NPM account using
npm login
and then run:
npm publish
- Done! Your library should now be available on NPM for others to use!