Clean setup for developing a React, Typescript, component library.
How to build a React library with TypeScript
Today, I am going to show you how to build a React library with TypeScript. Let’s get started!

How to build a React library with TypeScript
Prerequisites
[lerna](https://lerna.js.org/)- A tool for managing JavaScript projects with multiple packages.[Yarn workspace](https://classic.yarnpkg.com/lang/en/docs/workspaces/)- Setup NodeJS workspace[React Components](https://reactjs.org/docs/components-and-props.html)- Basic knowledge about React Components- Understand NodeJS module system
[ECMAScript modules - ESM](https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules)and[CommonJS - cjs](https://nodejs.org/docs/latest/api/modules.html#modules_modules_commonjs_modules).
UPDATES:
2022–01–29: Add CSS/SCSS modules supports when building React library with TypeScript and Rollup. Check the updates on section 5 (Configure TypeScript for
my-react-package) and section 8 (Write code for our package).
Practices
1. Create a new project with a package.json file
Root workspace package.json file
Two important points
privateshould be turned totrueworkspacescontains workspace paths. I usepackages/*to provide that my packages should be implemented under thepackagesfolder, andexamples/*for all examples with my built libraries
Folder structure
./learn-to-build-react-package
| |-- package.json
| |-- examples
| | |-- example-app
| | | |-- package.json
| |-- packages
| | |-- my-react-package
| | | |-- package.json
2. Configure lerna
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "independent"
}
Notes:
npmClient: whethernpmoryarnclient called when running lerna commanduseWorkspacesuse workspace flagversion: we should chooseindependentto make every single package in our workspace has an independent version, not the same)
3. Create new package packages/my-react-package
mkdir packages/my-react-package;
cd packages/my-react-package;
npm init -y;
4. Install peerDependencies for packages/my-react-package
npx lerna add react --scope my-react-package --peer;
npx lerna add react-dom --scope my-react-package --peer;
Why do we use peerDependencies?
=> It is because our package scope is just a MODULE that can be installed by any project and which must have our package peerDependencies installed also.
Now our my-react-package peerDependencies section in the package.json file looks like below
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
5. Configure TypeScript for my-react-package
Create my-react-package/tsconfig.json file should look like below:
{
"compilerOptions": {
"outDir": "lib/esm",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom", "es2016", "es2017"],
"jsx": "react-jsx",
"declaration": true,
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*.ts*"],
"exclude": ["node_modules", "lib"]
}
my-react-package/tsconfig.json file
Some highlights:
outDirstands for output directory after compiled TypeScript to thetargetECMAScript versiones5- Must use
"jsx": "react-jsx"to use JSX compiler - Turn on
declarationto extract type definitions - Folder “node_modules” and “lib” must be excluded while compiling TypeScript to JavaScript.
Create new my-react-package/src/global.d.ts to define global types
my-react-package/src/global.d.ts file
6. Configure Rollup to bundle our package
- Install devDependencies
cd packages/my-react-package;
yarn add -D rollup typescript rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup-plugin-postcss postcss node-sass
- Create new file
my-react-package/rollup.config.js
my-react-package/rollup.config.js file
Our module exposes two types of module system: CommonJS — cjs and ECMAScript — esm
All packages in the peerDependencies section will be treated as external dependencies. It means Rollup does not include them in the bundling process.
We use some Rollup plugins:
- @rollup/plugin-node-resolve resolves modules located in node_modules
- @rollup/plugin-commonjs converts CommonJS modules to ES6 modules to be included in Rollup
- rollup-plugin-typescript2 supports TypeScript
- rollup-plugin-postcss compiles PostCSS in Rollup, with autoprefixer we can gain auto prefixes for all CSS styles for all browsers automatically. If you want to use SCSS/SASS you must install
node-sassadditionally
7. Declare module definition in the my-react-package/package.json file
{
"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
"files": \[
"/lib"
\],
}
- Here we define the main file for our project is
"./lib/cjs/index.js" - Our package also expose esm module at
"./lib/esm/index.js" - Type definitions will be included at
"./lib/esm/index.d.ts" - The last important is
"files", which tells NPM which files or folders will be packaged. For our package, it will be"lib"folder
8. Write code for our package
- my-react-package/src/hello/index.tsx
my-react-package/src/hello/index.tsx file
- my-react-package/src/hello/styles.module.css
my-react-package/src/hello/styles.module.css file
- my-react-package/src/hello/styles.module.scss
my-react-package/src/hello/styles.module.scss file
- my-react-package/src/index.ts
my-react-package/src/index.ts file
9. Bundle
- In the
my-react-package/package.jsonfile add some useful commands:
my-react-package scripts
prepack Run before packing library into a package file. Eg: packages/my-react-package/my-react-package-1.0.0.tgz
build Build source code
watch Watch & build changes
- In the root workspace
package.jsonfile add some useful commands:
workspace scripts
build Run build my-react-package
watch Watch & build changes my-react-package. This is a helpful command in the development process to build a library if any changes occur.
package Pack my-react-package into a package file
Usages
- Create a new React App (prefer to TypeScript template) under
./examplesfolders:
cd examples;
create-react-app example-app --template typescript;
- Install package
my-react-packageintoexample-app:
npx lerna add my-react-package --scope example-app
I use lerna add command here to get my-react-package installed into example-app and have the latest source code of my-react-package if any new bundles
Now just import and see how it works on examples/example-app/src/App.tsx:
Example App.tsx file
In the development phase, you can write code for my-react-package and the example-appparallelly by using:
- Start
example-app:
cd examples/example-app;
yarn start;
- Watch and build our package my-react-package if any changes
yarn watch
So now, when you want to develop new components or hooks or anything else, you just write the code and our my-react-package will be built automatically.
Conclusion
To sum it up, there are 9 steps to build a React Library with TypeScript:
- Create a new project with package.json file
- Configure lerna
- Create new package packages/my-react-package
- Install peerDependencies for packages/my-react-package
- Configure TypeScript for
my-react-package - Configure Rollup to bundle our package
- Declare module definition in the package.json file
- Write code for our package
- Bundle
Last but not least, thank you for reading through this section! I hope you find this article helpful and solve your concerns when trying to build a React library.
If you have any questions or feedbacks, do not hesitate to leave a comment in the box below.
Thank you and see you next time!
References
[Lerna](https://lerna.js.org/)[Yarn workspace](https://classic.yarnpkg.com/lang/en/docs/workspaces/)[React Components](https://reactjs.org/docs/components-and-props.html)[NodeJS peerDependencies](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#peerdependencies)[ECMAScript modules -](https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules) ESM[CommonJS - CJS](https://nodejs.org/docs/latest/api/modules.html#modules_modules_commonjs_modules)[EcmaScript Exports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)