paint-brush
Building Efficient npm Packages with React, TypeScript, and CSS Modules: A Comprehensive Guideby@lastcallofsummer
5,273 reads
5,273 reads

Building Efficient npm Packages with React, TypeScript, and CSS Modules: A Comprehensive Guide

by Olga StogovaJuly 14th, 2023
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

React, TypeScript, CSS Modules, and other tools can make your development process more efficient and enjoyable. In this article, we'll guide you through creating a modern and robust project setup using React, Type script, and Rollup. The key features include: **React & TypeScript**: Modern UI development with strong type safety and a superior developer experience.
featured image - Building Efficient npm Packages with React, TypeScript, and CSS Modules: A Comprehensive Guide
Olga Stogova HackerNoon profile picture

Creating reusable npm packages can make your development process more efficient and enjoyable. In this article, we'll guide you through creating a modern and robust project setup using React, TypeScript, CSS Modules, and other tools.


Before we start, you can find the source code here: https://github.com/helgastogova/npm-react-typescript-template. This repository serves as a base for creating npm packages using React and TypeScript. It's preconfigured with a build process and a set of recommended packages for a modern development workflow.


The key features include:


  1. React & TypeScript: Modern UI development with strong type safety and a superior developer experience.
  2. CSS Modules: Styling components in isolation, avoiding CSS conflicts, and enabling modular design.
  3. ESLint: Ensuring code quality by adhering to JavaScript and React's best practices.
  4. Rollup: Efficiently bundling React and TypeScript code into a single file for distribution.
  5. PostCSS: Utilizing next-gen CSS features and handling browser compatibility.
  6. Size Limit: Monitoring your library's size and preventing accidental size bloat.


Let's dive into each tool more comprehensively.

CSS Modules

CSS modules serve as a beacon of safety in the realm of styling chaos. They implement local scoping for your styles, warding off conflicts and overlap issues. Each CSS module will be "encapsulated" into the component, ensuring the styles you define won't leak out and affect other elements unintentionally.


Consider this simple component where we use CSS Module:


// TestComponent.tsx

import React from 'react';
import s from './TestComponent.module.css';

type TestComponentProps = {
  text?: string;
};

export const TestComponent: React.FC<TestComponentProps> = ({ text }) => {
  return <div className={s.root}>{text ?? 'Hello!'}</div>;
};


And its associated CSS Module:


/* TestComponent.module.css */

.root {
  background-color: pink;
  padding: 20px;
  border-radius: 8px;
}


In this case, the .root class from TestComponent.module.css won't affect any other .root class in a different module.

ESLint

ESLint is like a lighthouse guiding you through a tumultuous sea of code. It helps maintain code quality, catching errors and enforcing best coding practices before they become problems.


In your package.json, you have:


"scripts": {
  "lint": "eslint './src/**/*.{ts,tsx}'"
}


Run the linter with npm run lint. ESLint will scan through your TypeScript files and warn you about any potential issues. This is particularly handy for large codebases where it's easy for small errors or inconsistencies to creep in.

Rollup

Rollup is your code's personal fitness trainer. It takes your JavaScript, TypeScript, and CSS and bundles them into one lean, efficient package ready for distribution.


It's lightweight and fast, but the real benefit comes from its "tree-shaking" capability. Rollup can eliminate unused code from the final bundle, making your package as lean as possible. Here's an example of how your Rollup configuration might look:


// rollup.config.js

const postcss = require('rollup-plugin-postcss');
const typescript = require('@rollup/plugin-typescript');
const peerDepsExternal = require('rollup-plugin-peer-deps-external');
const resolve = require('@rollup/plugin-node-resolve').default;
const commonjs = require('@rollup/plugin-commonjs');

module.exports = {
  input: 'src/index.tsx',
  output: {
    dir: 'dist',
    format: 'cjs',
    sourcemap: true,
  },
  plugins: [
    peerDepsExternal(),
    resolve(),
    typescript(),
    commonjs(),
    postcss({
      modules: true,
    }),
  ],
};


PostCSS

PostCSS is like a time-traveler, allowing you to write CSS using future syntax and features. It then travels back in time (so to speak), transforming these modern styles into code that even older browsers can understand.


You can see PostCSS in action in the Rollup configuration above. Using the rollup-plugin-postcss, your modern CSS is transformed and included in your final bundle. The beauty of this is that you can write CSS using the latest features without worrying about browser compatibility.

Size Limit

Size Limit is the ever-vigilant watchman, making sure your library doesn't get too bloated. It calculates the real cost of your library by adding both the JavaScript and CSS that will be downloaded by users. It's a valuable tool to help you keep your bundle size in check.


In your package.json:


"scripts": {
  "size": "size-limit",
},
"size-limit": [
  {
    "path": "dist/*.js",
    "limit": "10 KB"
  }
]


You can then run npm run size to check the size of your bundle. If it exceeds the limit you've set (in this case, 10 KB), the script will throw an error. It's a great way to ensure you're not unknowingly adding to your users' download times.

Setup

To start using this template, clone the repository:


git clone https://github.com/helgastogova/npm-react-typescript-template.git


Navigate into the directory:


cd npm-react-typescript-template


Install the dependencies:


npm install


You're all set to start developing your package! The entry point is src/index.tsx

Building the Package

After creating your own component and when you're ready to build your package for distribution, run:


npm run build


Your built package will be in the dist directory, ready for publishing to npm.

Publishing to npm

Ensure that you've set the name field in your package.json to your desired package name. Also, remember to update the version number before each new publish. Once that's done, log in to npm using:


npm login


Enter your username, password, and email. Once logged in, you can publish your package with:


npm publish


Now you have published your component in the npmjs library, and people can start using it. You are awesome!


Happy coding!