How to Bundle a React Library into Reusable Components

Creating a React library can streamline the development process by reusing components across multiple projects. In this blog post, “How to Bundle a React Library into Reusable Components”, we’ll explore the step-by-step process of designing, packaging, and distributing a library. From setting up the project structure to configuring bundlers like Webpack or Rollup, you’ll learn how to build modular, efficient, and maintainable React components ready for deployment.

Table of Contents

Introduction

Welcome to our comprehensive guide on bundling a React library into a reusable component library! In this journey, we’ll explore each step of the compilation process using real examples from the configuration files you’ve shared.

Bundling a react library into a components library

Objective

Imagine you have a React library named @yugensys/react-widgets, and you want to package it into a component library for seamless integration into various projects. Goal here is to compile the source code, bundle it efficiently, and ensure compatibility with different module systems.

Our Services

Book a Meeting with the Experts at Yugensys


What are Configuration Files?

We’ll take example of a config file and understand how each section contributes to the compilation process.

Webpack.config.js

// webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// Define webpack configuration
module.exports = {
  // Entry points for the library
  entry: {
    'App''./src/index.tsx',
    'App.min''./src/index.tsx'
  },
  // Output configuration
  output: {
    filename'[name].js',
    pathpath.resolve(__dirname'dist'),
    library'@yugensys/react-widets',
    libraryTarget'umd'// Universal Module Definition
    umdNamedDefinetrue
  },
  // Optimization settings
  optimization: {
    minimizetrue
  },
  // Source map generation for debugging
  devtool'source-map',
  // Resolve module file extensions
  resolve: {
    extensions: ['.tsx''.ts''.js''.scss''.css'],
    modules: ['node_modules']
  },
  // Define module rules for file handling
  module: {
    rules: [
      // TypeScript files handling
      {
        test/\.(ts|tsx)$/,
        use'ts-loader',
      },
      // CSS and SCSS files handling
      {
        test/\.(css|scss)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',                // Convert CSS into CommonJS
          'sass-loader'                // Compile Sass to CSS
        ]
      },
      // File loader for other assets
      {
        test/\.(png|svg|jpg|jpeg|gif|json|ico)$/,
        use: ['file-loader?name=[name].[ext]']
      }
    ],
  },
  // Define webpack plugins
  plugins: [
    new CleanWebpackPlugin(),             // Clean output directory
    new HtmlWebpackPlugin({               // Generate HTML file
      template'./public/index.html',
    }),
    new MiniCssExtractPlugin({            // Extract CSS into separate files
      filename'[name].css',
    }),
  ],
  // Configuration for webpack-dev-server
  devServer: {
    static: {
      directorypath.join(__dirname'dist'),
    },
    compresstrue,
    port9000,
    opentrue,
  },
};
Here’s a brief note about each of the section, for a more detailed explanation please visit here:
  1. Entry Points Definition: The entry object defines the entry points for your library. Here, './src/index.tsx' serves as the primary entry point, while 'App.min.js' is designated for the minified version.
  2. Output Configuration: The output object determines where and how your bundled code will be generated. We specify the output directory, filenames, library name, and target (UMD) to ensure compatibility with various module systems.
  3. Optimization Settings: The optimization object allows us to specify optimization options. Enabling minimize: true triggers minification of the bundled code.
  4. Source Map Generation: The devtool option configures source map generation, aiding in debugging by mapping bundled code to its original source files.
  5. Module Rules: The module.rules array defines how different file types should be treated during bundling. Loaders like ts-loadercss-loadersass-loader, and file-loader handle TypeScript, CSS/SCSS, and other asset files.
  6. Plugins: Webpack plugins enhance the bundling process. Here, plugins like CleanWebpackPluginHtmlWebpackPlugin, and MiniCssExtractPlugin provide functionalities such as cleaning the output directory, generating HTML files, and extracting CSS into separate files.
  7. Development Server Configuration: The devServer object configures webpack-dev-server settings, facilitating development with features like live reloading and hot module replacement.

TSConfig.json

The TypeScript compiler configuration (tsconfig.json) governs how TypeScript code is compiled into JavaScript. Let’s explore the purpose of each section in the provided tsconfig.json:

// tsconfig.json
{
  "compilerOptions": {
    // Compiler options
    "target""es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "module""CommonJS",
    "jsx""react-jsx"
  },
  "include": [
    "src"
  ],
  "exclude": [
    "dist",
    "**/*.test.ts",
    "**/webpack.config.js"
  ],
  "compilation": {
    "compiler": {
      "context""./src",
      "outputPath""./dist"
    }
  }
}
Let’s break down each section of the provided tsconfig.json file and understand how it contributes to the TypeScript compilation process and aids in bundling the TypeScript code.

 

"compilerOptions"

This section contains various settings for the TypeScript compiler (tsc) to govern how TypeScript code is compiled into JavaScript. Let’s examine each option:

  • "target": "es5": Specifies the ECMAScript version that the compiled JavaScript should be compatible with. In this case, the code is compiled to ES5, ensuring compatibility with older browsers and environments.
  • "lib": ["dom", "dom.iterable", "esnext"]: Defines the default library files to include when compiling TypeScript code. Here, we include dom and dom.iterable for DOM manipulation and iteration, along with esnext for modern ECMAScript features.
  • "module": "CommonJS": Specifies the module system to use for outputting JavaScript code. CommonJS modules are widely supported and commonly used in Node.js environments.
  • "jsx": "react-jsx": Defines how JSX (JavaScript XML) syntax should be handled. Here, react-jsx indicates that JSX should be transformed to React.createElement calls.
 

"include" and "exclude"

These sections determine which files should be included or excluded during the compilation process:

  • "include": ["src"]: Specifies the directory (or directories) where TypeScript files should be included for compilation. In this case, only files within the src directory will be compiled.
  • "exclude": ["dist", "**/*.test.ts", "**/webpack.config.js"]: Defines patterns for excluding specific files or directories from compilation. Here, files within the dist directory, any files ending with .test.ts, and the webpack.config.js file are excluded from compilation.
 

"compilation"

This section appears to be a custom configuration object named "compilation", but it’s not a standard TypeScript compiler option. It seems to define additional settings related to the compilation process:

  • "compiler": { "context": "./src", "outputPath": "./dist" }: This custom configuration seems to specify the compiler context and output path. The "context" property indicates the root directory for resolving entry files, while "outputPath" specifies the directory where compiled JavaScript files will be outputted. In this case, it suggests that the entry files are located within the src directory and the compiled output will be placed in the dist directory.

 

The tsconfig.json file plays a crucial role in configuring the TypeScript compiler and guiding the compilation process. By defining compiler options, inclusion/exclusion patterns, and additional compilation settings, it ensures that TypeScript code is compiled correctly and bundled efficiently. In the context of bundling TypeScript code, this file ensures that the appropriate transformations and optimizations are applied during compilation, resulting in JavaScript code that is ready for bundling and deployment.

Publish to NPM Git Repository

1. Create a Personal Access Token

First, we are going to a Create a Personal Access Token within Github to read and write your packages.

  1. You can do this by going to:
Github Account -> Settings -> Developer Settings -> Personal Access Tokens -> Generate New Token Select scopes: write:packages, read:packages

2. Click on Generate Token, and copy the token to the Clipboard.

3. With the token copied, in the same directory as your package.json file, create an .npmrc file and add the following line, replacing TOKEN with your personal access token.

//npm.pkg.github.com/:_authToken={TOKEN}
Here’s a screenshot of how your .npmrc file would look at this stage,

2. Create a Private Repository in Github

Create a Private repository in Github, just like you would normally and copy the URL. Mine would be:

git://github.com/yugensys/react-widgets

3. Add publish-config to package.json

To successfully publish, you need to make some small changes to your package.json.

  • So far, your package.json should have your folder’s name,
    "name": "react-widgets" .
  • In order to publish your package, you need to rename it to @owner/repo-name. In my case that’s
    "name": "@yugensys/react-widgets".
  • "files" : The folder with our generated library, i.e. the ./dist folder.
  • "publishConfig" : The registry where you want the package published, which is "registry": "https://npm.pkg.github.com".
  • "repository" : URL of the private Github repository we just created.
  • Lastly, if you have the following line in package.json, remove it. Setting "private": true in your package.json prevents it from being published at all. Don’t worry, your package will still be published as a private component library without it. 
 

The package.json file serves as the backbone of a Node.js package, providing crucial metadata and configuration for bundling and publishing. Each section plays a vital role in ensuring that the package is properly bundled, dependencies are managed, and publishing is configured according to the desired specifications, especially when publishing to a private npm package repository.

 

4. Publish to Github registry

Finally, publish your library with the following command and it should be a success!

$ npm publish

Your package is now visible on Github on:

https://github.com/<owner>/<repo-name>/packages

Package.json

 { 
"name""@yugensys/react-widgets",   "main""dist/App.js",   "publishConfig": {   },     "dist/",     "lib-esm/"   "dependencies": {     "@testing-library/react""^13.4.0",     "@types/jest""^27.5.2",     "@types/react""^18.3.0",     "react""^18.3.0",     "react-scripts""5.0.1",     "web-vitals""^2.1.4",     "@emotion/styled""^11.11.5",     "@mui/icons-material""^5.15.15",     "@mui/material""^5.15.15",   },     "start""webpack serve --mode development --open",     "test""react-scripts test",   "eslintConfig": {       "react-app",       "plugin:storybook/recommended"   },     "production": [       "not dead",     ],       "last 1 chrome version",       "last 1 safari version"   },     "@emotion/react""^11.11.4",     "@material-ui/core""^4.12.4",     "@mui/lab""^5.0.0-alpha.170",     "@mui/styled-engine""^5.15.14" }

Conclusion

Congratulations! You’ve gained a deeper understanding of the compilation process involved in bundling a React library into a component library. By dissecting the configuration files and exploring real examples, you’re now equipped to streamline the development and distribution of your React libraries. Armed with this knowledge, you can foster collaboration and code reuse within the community, making a significant impact in the world of web development. 

 

Happy coding!

Vaishakhi Panchmatia

As Tech Co-Founder at Yugensys, I’m passionate about fostering innovation and propelling technological progress. By harnessing the power of cutting-edge solutions, I lead our team in delivering transformative IT services and Outsourced Product Development. My expertise lies in leveraging technology to empower businesses and ensure their success within the dynamic digital landscape.

Looking to augment your software engineering team with a team dedicated to impactful solutions and continuous advancement, feel free to connect with me. Yugensys can be your trusted partner in navigating the ever-evolving technological landscape.

Subscrible For Weekly Industry Updates and Yugensys Expert written Blogs


More blogs from React

React is a widely used JavaScript library for building dynamic and responsive user interfaces. It allows developers to create modular, component-based web and mobile apps with real-time rendering capabilities, making it a top choice for scalable front-end development. Learn how React, the popular JavaScript library, powers dynamic and efficient user interfaces for web and mobile applications, ensuring high performance and flexibility.



Expert Written Blogs

Common Words in Client’s testimonial