Ever wonder how libraries like Tailwind CSS and Material UI are created and released? It’s lot easier than you think, I assure you. We’ll go over how to take our react-toast-alert component and publish it to NPM in this guide.
Publishing your own library can help you attract freelance clients or get a job by adding value to your portfolio. It’s a useful ability that makes a strong impression on potential employers.
Step-1 Setting up the Project
I have a pre built React with TypeScript Toast component. You can get the full code of building this component here.
Create a new folder for your project.
Copy thesrc
folder from your toast component and delete all global files and create an index.ts
file exporting our component.
import useNotification from "./hooks/useNotification";
export default useNotification;
It will look something like this –
Install necessary dependencies like React, TypeScript, and tslib.npm i react typescript @types/react tslib –save-dev
npm i react typescript @types/react tslib --save-dev
Compiling TypeScript Files
Create a tsconfig.json
file by running:
npx tsc -init
Here is the essential configuration we need in tsconfig.json
:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
Explanation of Key Options
- “target”: “es5”: Ensures compatibility with older browsers.
- “lib”: [“dom”, “dom.iterable”, “esnext”]: Includes necessary libraries.
- “allowJs”: true: Allows processing of JavaScript files.
- “skipLibCheck”: true: Skips type checks for libraries.
- “esModuleInterop”: true: Enables ES module interoperability.
- “allowSyntheticDefaultImports”: true: Allows default imports.
- “strict”: true: Enables strict type-checking.
- “forceConsistentCasingInFileNames”: true: Enforces consistent file name casing.
- “noFallthroughCasesInSwitch”: true: Prevents fall-through cases in switch statements.
- “module”: “esnext”: Uses ESNext module system.
- “moduleResolution”: “node”: Uses Node.js module resolution.
- “resolveJsonModule”: true: Resolves JSON modules.
- “isolatedModules”: true: Isolates each module.
- “noEmit”: true: Prevents emitting JavaScript files.
- “jsx”: “react-jsx”: Uses React JSX factory.
Bundling Using Rollup
Now that we have compiled our code, we need to bundle it for different environments.
Install Rollup:
npm i rollup
Install additional plugins:
npm i @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-peer-deps-external @rollup/plugin-terser rollup-plugin-dts --save-dev
List
- @rollup/plugin-node-resolve: Resolves dependencies in your code.
- @rollup/plugin-commonjs: Allows use of CommonJS modules.
- @rollup/plugin-typescript: Enables TypeScript support.
- rollup-plugin-peer-deps-external: Manages peer dependencies.
- @rollup/plugin-terser: Minifies JavaScript code.
- rollup-plugin-dts: Generates type declarations
Createrollup.config.js
:
- Add following keys to
package.json
{
...
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
...
}
Writing the config (rollup.config.js
) –
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";
import terser from "@rollup/plugin-terser";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
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" }),
terser(),
],
external: ["react", "react-dom"],
},
{
input: "src/index.ts",
output: [{ file: packageJson.types }],
plugins: [dts.default()],
},
];
format: "cjs"
: Output as CommonJS module.format: "esm"
: Output as ES module.external
: Excludes specified dependencies from the bundle.
Build Script:
{
...
"scripts": {
"rollup": "rollup -c --bundleConfigAsCjs",
...
}
}
Explanation of the Build Script
- “rollup”: This is the name of the script. You can run it using
npm run rollup
. - “rollup -c –bundleConfigAsCjs”: This command runs Rollup with the specified options:
-c
: Tells Rollup to use a configuration file (rollup.config.js
by default).--bundleConfigAsCjs
: Ensures the output is bundled as a CommonJS module.
- Handling CSS:
- Install the postcss plugin:
npm i rollup-plugin-postcss
Update rollup.config.js
:
import postcss from "rollup-plugin-postcss";
...
plugins: [
...
postcss(),
],
external: [/\.css$/]
...
Here’s our final rollup configuration file –
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";
import terser from "@rollup/plugin-terser";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
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" }),
terser(),
postcss(),
],
external: ["react", "react-dom"],
},
{
input: "src/index.ts",
output: [{ file: packageJson.types }],
plugins: [dts.default()],
external: [/\.css$/],
},
];
Publish to NPM
Finally, you can publish your package to NPM by following these steps:
- Log in to NPM:
npm login
Publish the package:
npm publish
And that’s it! You’ve successfully created and published a React TypeScript component to NPM.