How to Bundle a React Library into Reusable Components
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.
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.
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', path: path.resolve(__dirname, 'dist'), library: '@yugensys/react-widets', libraryTarget: 'umd', // Universal Module Definition umdNamedDefine: true }, // Optimization settings optimization: { minimize: true }, // 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: { directory: path.join(__dirname, 'dist'), }, compress: true, port: 9000, open: true, }, };
- 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. - 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. - Optimization Settings: The
optimization
object allows us to specify optimization options. Enablingminimize: true
triggers minification of the bundled code. - Source Map Generation: The
devtool
option configures source map generation, aiding in debugging by mapping bundled code to its original source files. - Module Rules: The
module.rules
array defines how different file types should be treated during bundling. Loaders likets-loader
,css-loader
,sass-loader
, andfile-loader
handle TypeScript, CSS/SCSS, and other asset files. - Plugins: Webpack plugins enhance the bundling process. Here, plugins like
CleanWebpackPlugin
,HtmlWebpackPlugin
, andMiniCssExtractPlugin
provide functionalities such as cleaning the output directory, generating HTML files, and extracting CSS into separate files. - 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" } } }
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 includedom
anddom.iterable
for DOM manipulation and iteration, along withesnext
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 thesrc
directory will be compiled."exclude": ["dist", "**/*.test.ts", "**/webpack.config.js"]
: Defines patterns for excluding specific files or directories from compilation. Here, files within thedist
directory, any files ending with.test.ts
, and thewebpack.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 thesrc
directory and the compiled output will be placed in thedist
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.
- 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}
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!
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