Introduction
React is still the most famous frontend library in the web developer community. When Meta (previously Facebook) open-sourced React in late 2013, it made a huge impact on single-page applications (SPAs) by introducing concepts like the virtual DOM, breaking the UI into components, and immutability.
React has evolved a lot in the past few years, and with the introduction of TypeScript support, Hooks, <Suspense>
, and React Server Components, we can assume that React will still hold the crown for best frontend tool. React has opened the doors to some awesome projects like Next.js, Gatsby, and Remix, which focus more on improving the developer experience.
Along with this robust React ecosystem is a wide variety of component libraries, like Material UI, Chakra UI, and React-Bootstrap. When you come across these awesome tools and libraries, have you ever wondered how they are made? Or what it would take to create your own UI component library with React?
In the following article, we’ll learn how to build our component library with TypeScript and publish it to npm, so that you too can contribute to React’s ever-growing community of projects.
Required tools
Creating a UI library is quite different from creating a web application; instead of using popular tools like Next.js or Create React App, we have to start from scratch.
To build this UI library, we’ll be using the following tools:
TypeScript
There’s no doubt that TypeScript is the go-to method when developing with JavaScript. TypeScript will save a ton of time for us, because it introduces types and compile-time checking.
In addition, TypeScript will be helpful when we build components for our library, because we will be dealing with props in React components, and defining types will avoid issues when passing props to the components.
Rollup
We will need some custom configurations for our library. Rollup is an excellent middle ground between popular JavaScript bundlers because it is more customizable than Parcel, but requires less configuration effort than webpack.
Storybook
We are building components, so we need a way of visualizing them in an isolated environment. Storybook does that for us because it spins up a separate playground for UI components
Jest and React Testing Library
Jest is a complete testing framework with a test runner, plus an assertion and mocking library. It also lets the user create snapshot tests for components, which is ideal when building components in React.
React Testing Library helps us write tests as if a real user is working on the elements.
Project structure
Let’s think about the project structure. We will be adding components, tests, stories, and types to our project to add them under component directories.
Let’s start with project initialization. For this, create a directory and initialize it as a JavaScript project using the following command:
npm init
This command will generate a package.json
file in our application.
Now, install TypeScript and React to our project through the following command:
npm i -D react typescript @types/react
Notice that we are passing the flag -D
because we need to install it as devDependencies
rather than a project dependency; we’ll need those dependencies when we are building the bundle.
In the future, this library will be used inside a React project. Therefore, we don’t need to bundle it, and we can move the React dependency to the peerDependency
section (you will probably need to add this in your package.json
file).
Creating components
Now that we have added React and TypeScript, we can start creating our components, beginning with a button.
Create the components under the src/components
directory. Because this is a TypeScript project, we first create the type definitions for the components, which I’m naming Button.types.ts
:
import { MouseEventHandler } from "react" export interface ButtonProps { text?: string, primary?:boolean, disabled?: boolean, size?: "small" | "medium" | "large", onClick?: MouseEventHandler<HTMLButtonElement> }
This file consists of all the props of the button, including the onClick
event. We will use these props in the button component to add or enable different properties. Now, let’s move on to the creation of the button component itself.
Integrating styled-components for a button component
In this project, we will not be using regular CSS; instead, we will be using CSS-in-JS. CSS-in-JS provides many benefits over regular CSS, for example:
- Reusability: Because CSS-in-JS is written in JavaScript, the styles you define will be reusable JavaScript objects, and you can even extend their properties
- Encapsulation: CSS-in-JS scopes are generated by unique selectors that prevent styles from leaking into other components
- Dynamic: CSS-in-JS will allow you to dynamically change the properties of the styling depending on the value that the variables hold
There are many ways to write CSS-in-JS in your component, but for this tutorial we will be using one of the most famous libraries called styled-components. You can run the following commands to install the Storybook dependencies along with the type definitions for TypeScript support:
npm install -D styled-components @types/styled-components
Now, let’s create our button component:
import React,{FC} from 'react' import styled from 'styled-components'; import {ButtonProps} from "./Button.types" const StyledButton = styled.button<ButtonProps>` border: 0; line-height: 1; font-size: 15px; cursor: pointer; font-weight: 700; font-weight: bold; border-radius: 3px; display: inline-block; padding: ${props => props.size === "small"? "7px 25px 8px" : (props.size === "medium"? "9px 30px 11px" : "14px 30px 16px" )}; color: ${props => props.primary? "#1b116e":"#ffffff"}; background-color: ${props => props.primary ? "#6bedb5":"#1b116e"}; opacity: ${props => props.disabled ? 0.5 : 1}; &:hover { background-color: ${props => props.primary ? "#55bd90":"#6bedb5"}; } &:active { border: solid 2px #1b116e; padding: ${props => props.size === "small"? "5px 23px 6px" : (props.size === "medium"? "7px 28px 9px" : "12px 28px 14px" )}; } `; const Button: FC<ButtonProps> = ({size, primary, disabled, text, onClick, ...props}) => { return ( <StyledButton type="button" onClick={onClick} primary={primary} disabled={disabled} size={size} {...props}> {text} </StyledButton> ) } export default Button;
If you go through the code above, you will notice something special: we have defined a variable called StyledButton
to which we assign styling properties through special tags called tagged template literals, a new JavaScript ES6 feature that enables you to define custom string interpolations.
These tagged templates are used to write the StyledButton
variable as a React component that you can use like any other. Notice that we have access to the component props inside these special tagged templates.
Creating an input component
Now let’s create an input component, starting first with its types by creating a file called Input.types.ts
:
import { ChangeEventHandler } from "react" export interface InputProps { id?: string, label?: string, error?:boolean, message?: string, success?:boolean, disabled?: boolean, placeholder?:string, onChange?: ChangeEventHandler<HTMLInputElement> }
Like in the previous component, we have defined the prop attributes in the Input.types.ts
file. You can see that we have added the onChange
event and assigned it ChangeEventHandler<HTMLInputElement>
from React. We do this in order to tell that these props are responsible for an input change event.
Finally, let’s create the input component:
import React, { FC,Fragment } from 'react' import styled from 'styled-components'; import { InputProps } from "./Input.types" const StyledInput = styled.input<InputProps>` height: 40px; width: 300px; border-radius: 3px; border: solid 2px ${props => props.disabled ? "#e4e3ea" :(props.error ? "#a9150b":(props.success ? "#067d68" : "#353637"))}; background-color: #fff; &:focus{ border: solid 2px #1b116e; } `; const StyledLabel = styled.div<InputProps>` font-size: 14px; color: ${props => props.disabled ? "#e4e3ea" : "#080808"}; padding-bottom: 6px; `; const StyledMessage = styled.div<InputProps>` font-size: 14px; color: #a9150b8; padding-top: 4px; `; const StyledText = styled.p<InputProps>` margin: 0px; color: ${props => props.disabled ? "#e4e3ea" : (props.error ? "#a9150b": "#080808")}; `; const Input: FC<InputProps> = ({id, disabled, label, message, error, success, onChange, placeholder, ...props}) => { return ( <Fragment> <StyledLabel><StyledText disabled={disabled} error={error}>{label}</StyledText></StyledLabel> <StyledInput id={id} type="text" onChange={onChange} disabled={disabled} error={error} success={success} placeholder={placeholder} {...props}></StyledInput> <StyledMessage><StyledText error={error}>{message}</StyledText></StyledMessage> </Fragment> ) } export default Input;
In the above code, you can see that we have defined several styled-components
and wrapped them together through a React fragment. We use a fragment because it enables us to group multiple sibling components without introducing any extra elements in the DOM. This will come in handy because there won’t be any unnecessary markup in the rendered HTML of our components.
Configuring TypeScript and Rollup
Now it’s time to configure TypeScript with Rollup. We are using TypeScript to build the components; in order to build the library as a module, we will need to configure Rollup along with it.
In a previous step, we installed TypeScript to our project, so now we just need to add the TypeScript configurations (from the tsconfig.json
file). For this, we can use TypeScript’s CLI to generate the file:
npx tsc --init
Let’s make a few tweaks to this tsconfig.json
file so that it will fit our project scenario:
{ "compilerOptions": { "esModuleInterop": true, "strict": true, "skipLibCheck": true, "jsx": "react", "module": "ESNext", "declaration": true, "declarationDir": "types", "sourceMap": true, "outDir": "dist", "moduleResolution": "node", "emitDeclarationOnly": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, }, "exclude": [ "dist", "node_modules", "src/**/*.test.tsx", "src/**/*.stories.tsx", ], }
In the above code, you can see that we have added the configurations like "skipLibCheck": true
, which skips type checking of declaration files. This can save time during compilation.
Another special configuration is "module": "ESNext"
, which indicates that we will be compiling the code into the latest version of JavaScript (ES6 and above, so you can use import statements).
The attribute "sourceMap": true
tells the compiler that we want source map generation. A source map is a file that maps the transformed source to the original source, which enables the browser to present the reconstructed original in the debugger.
You will notice that we have defined an "exclude"
section in order to tell TypeScript to avoid transpiling specified directories and files, so it won’t transpile the tests and stories of our library.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to animate your React app with AnimXYZ
- Explore Tauri, a new framework for building binaries
- Compare NestJS vs. Express.js
Now that we have configured TypeScript, let’s begin configuring Rollup.
First, install Rollup as a devDependencies
project through the following command:
npm i -D rollup
However, installing Rollup is not enough for our project because we will need additional features, like:
- Bundling to CommonJS format
- Resolving third-party dependencies in
node_modules
- Transpiling our TypeScript code to JavaScript
- Preventing bundling of
peerDependencies
- Minifying the final bundle
- Generating type files (
.d.ts
), which provide TypeScript type information about the components in our project
The above features will come in handy when we finally build and use the library as a package. CommonJS is a specification standard used in Node, and modules are loaded synchronously and processed in the order the JavaScript runtime finds them.
Luckily, there are several plugins for Rollup that we can use for the above requirements, which can be installed through the following command:
npm i -D @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-peer-deps-external rollup-plugin-terser rollup-plugin-dts
Now that Rollup and its awesome plugins are installed, let’s move on to its configuration. Create a rollup.config.js
file in the root of our project and add the following:
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", "styled-components"] }, { input: "dist/esm/types/index.d.ts", output: [{ file: "dist/index.d.ts", format: "esm" }], plugins: [dts()], }, ];
In the code above, you can see that we are building our library with both CommonJS and ES modules. This will allow our component to have more compatibility in projects with different JavaScript versions. ES modules allows us to use named exports, better static analysis, tree shaking, and browser support.
Next, we have to define the paths in package.json
for both ES modules and CommonJS:
"main": "dist/cjs/index.js", "module": "dist/esm/index.js",
Now that we have added the necessary configurations, let’s add the build command in the script section of the package.json
file:
"build": "rollup -c"
Now you can build the project by using the following command from your terminal:
npm run build
The above command will generate a directory called dist
, which is our build directory defined in the Rollup configurations.
Integrating Storybook
The next step is to integrate Storybook into our library. Storybook is an open-source tool for building UI components and pages in isolation. Because we are building a component library it will help us to render our components and see how they behave under particular states or viewpoints.
Configuring Storybook is quite easy thanks to its CLI, which is smart enough to recognize your project type and generate the necessary configurations:
npx sb init
When you execute the above code on your terminal, it will generate the directories .storybook
and stories
in your project. .storybook
will hold all the configurations, and stories
holds the stories for your component. A story is a unit that captures the rendered state of a UI component.
The above command will also add some scripts for our package.json
file as well:
"scripts": { …. "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" }
The above scripts added by the Storybook CLI will allow us to build the Storybook through the npm or yarn command like so:
"npm run storybook" "yarn storybook"
Next, we will change the default directory structure and move the stories
file to our component level. This will make our library more organized, as all the files (types, tests, and stories) related to a particular component are moved to one place. We will have to indicate them in the main.js
file under the .storybook
directory.
First, let’s start by changing the default configurations of the Storybook:
module.exports = { "stories": [ "../src/**/**/*.stories.mdx", "../src/**/**/*[email protected](js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials" ] }
Now that we have done the necessary configurations, we can write our first story for the button component:
import React from 'react'; import { Story, Meta } from '@storybook/react'; import Button from './Button'; import {ButtonProps} from "./Button.types" export default { title: 'Marbella/Button', component: Button, argTypes: { }, } as Meta<typeof Button>; const Template: Story<ButtonProps> = (args) => <Button {...args} />; export const Primary = Template.bind({}); Primary.args = { primary: true, disabled: false, text: 'Primary', }; export const Secondary = Template.bind({}); Secondary.args = { primary: false, disabled: false, text: "Secondary", }; export const Disabled = Template.bind({}); Disabled.args = { primary: false, disabled: true, text: 'Disabled', }; export const Small = Template.bind({}); Small.args = { primary: true, disabled: false, size:"small", text: 'Small', }; export const Medium = Template.bind({}); Medium.args = { primary: true, disabled: false, size:"medium", text: 'Medium', }; export const Large = Template.bind({}); Large.args = { primary: true, disabled: false, size:"large", text: 'Large', };
In the above code, we imported the button component and its types. Next, we created a story template from it to render different states of the button (like primary
, secondary
, and disabled
) through template arguments. This template allows us to see how the button component behaves according to the props we pass to the component.
Now let’s see how this component is rendered in Storybook by running the following command:
npm run storybooks
The above command will open a new tab on your browser and render the component inside the Storybook view.
In the above image, you can see that in the left sidebar we have our components defined in the story, including the templates. In the center, you can see our button component with the options we included in the last code block.
Next, we can create the story for the input component:
import React from 'react'; import { Story, Meta } from '@storybook/react'; import Input from './Input'; import {InputProps} from "./Input.types" export default { title: 'Marbella/Input', component: Input, argTypes: { }, } as Meta<typeof Input>; const Template: Story<InputProps> = (args) => <Input {...args} />; export const Primary = Template.bind({}); Primary.args = { error: false, disabled: false, label: 'Primary', }; export const Success = Template.bind({}); Success.args = { error: false, success:true, disabled: false, label: "Success", }; export const Error = Template.bind({}); Error.args = { error: true, disabled: false, message: "Error", }; export const Disabled = Template.bind({}); Disabled.args = { disabled: true, label: 'Disabled', };
In the above code, we have defined the story templates to indicate the state of the input component through props. Let’s see how this component is rendered in Storybook.
In this image, you can see the input component’s story templates and properties. Now you can play around with these options and see how the components behave in different scenarios. You can enhance these properties by installing some additional add-ons for Storybook.
You may face some issues when configuring Storybook due to missing dependencies like
react-dom
. If you face any issues, go through the logs and install only the necessary library, or try downgrading the version of Storybook.
Testing with Jest and React Testing Library
Now it’s time to add some testing for our component. First, install the dependencies to configure Jest and React Testing Library. You can execute the following command to install the dependencies:
npm install @testing-library/react @testing-library/jest-dom @testing-library/user-event jest @types/jest --save-dev
Here we have installed Jest and testing-library along with several add-ons for them like jest-dom and user-event, which enable Jest to render the components using the DOM for making assertions, and mock user events (like click, focus, or lose focus).
After installing the dependencies, create a jest.config.js
file to hold the configurations for the tests. You can also use the Jest CLI to generate this file by running the following command:
npx jest --init
The above image is the console output that you will get when you use the Jest CLI.
Now, let’s start writing the tests, starting with the button component:
import React from "react"; import '@testing-library/jest-dom' import {render, screen } from '@testing-library/react' import Button from "./Button"; describe("Running Test for Marbella Button", () => { test("Check Button Disabled", () => { render(<Button text="Button marbella" disabled/>) expect(screen.getByRole('button',{name:"Button marbella"})).toBeDisabled(); }); });
In the above code, we are rendering the button component and checking if we are rendering the properties we defined (in this case, disabling the button). This particular test will pass if the rendered button is disabled.
Next, we can test the input component:
import React from "react"; import '@testing-library/jest-dom' import userEvent from "@testing-library/user-event"; import {render, screen } from '@testing-library/react' import Input from "./Input"; describe("Running Test for Marbella Input", () => { test("Check placeholder in Input", () => { render(<Input placeholder="Hello marbella" />) expect(screen.getByPlaceholderText('Hello marbella')).toHaveAttribute('placeholder', 'Hello marbella'); }); test("renders the Input component", () => { render(<Input placeholder="marbella" />) const input = screen.getByPlaceholderText('marbella') as HTMLInputElement userEvent.type(input, 'Hello world!') expect(input.value).toBe('Hello world!') }); });
In the above code, we have two test scenarios: one will render the input component with a prop placeholder, and the other will mock a user event of typing inside the component. Let’s execute the test through the following command:
npm run test
The above image shows the output of running the test with some metrics.
Packaging and publishing to npm
We’re all done! Now we can publish this library as an npm package. To create and publish a package on npm, you will need to create an account on npmjs. When you create an account, search for your package name in npmjs just to see if it already exists, because there may be packages with similar names.
Next, begin the process of publishing your package by running the following command in the terminal:
npm login
This will prompt you to enter the username and password of your npm account. Do so, then run the build command again just to build the package for the last time. After building we can publish it as a package through the following command:
npm publish --access public
You should be able to see the published package on npm in your profile. Now your package will be available for everyone to download!
Conclusion
In this article, we built a React library with TypeScript and used CSS-in-JS with some tools like Rollup, Storybook, and Jest.
There are many ways to create component libraries, and there are a lot of starter templates available for you to create one. But building your own library from scratch gives you the opportunity to add or use the tools that you love the most, and it gives you in-depth knowledge on how build tools work.
Thank you for reading this article! I would like to hear your thoughts in the comment section.
LogRocket: Full visibility into your production React apps
Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?
Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.
No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.
Hi,
Thanks for the wonderful article.
I getting error while running ‘rollup -c’.
dist/esm/types/index.d.ts → dist/index.d.ts…
[!] Error: Could not resolve entry module (dist/esm/types/index.d.ts).
In the dist folder types are are saved in esm/types/components/Button/index.d.ts
How to resolve this?
Good article!!
Btw, were you able to solve the types error?
It took me some time, but a was able to solved it!
Replace “dist/esm/types/index.d.ts” by “types/index.d.ts”
{
input: “types/index.d.ts”,
output: [{ file: “dist/index.d.ts”, format: “esm” }],
plugins: [dts()],
}
I still had an error and it took adding “rootDir” to my tsconfig. If no rootDir this error will persist.
To what did you set the rootDir?
The rollup config file is asking for src/index.ts file but not included with article. please share the contents of it. Also can you share code on a github repo?
Hello, I had the same issue. The tutorial doesn’t mention a folder structure, but the thing it that you must have an index.ts file on each component, but also must have one on the components folder itself, with something like ‘export { default as Button } from ‘./Button” (repeat to all your components), and finally another index.ts file on your src folder with something like ‘export * from ‘./components”. Basically, you must have an index.ts on Button folder, then Components folder, then SRC folder, and you should be fine.
Wooow, I dont believe this, a great article, I just want to suggest that you can creat a full react cource entitled creating a component library by react ,,, it would be great.think about it. Anyway I learned so many things from this article.
thank you.
Hi,
I stopped on “npm run build” with the following error:
src/index.ts → dist/cjs/index.js, dist/esm/index.js…
[!] Error: Could not resolve entry module (src/index.ts).
at async Promise.all (index 0)
in this tutorial there are no instructions for creating the “src/index.ts” file, but there is a reference to it in rollup.config.js in line 12
Regards,
Fernando Pacheco
I created the file with this content:
import Button from ‘./components/Button’
import Input from ‘./components/Input’
export { Button, Input }
build without error
Hello all, wonderful article. Please can anyone shar how to use it in a project. I tried importing it like this into a project:
import { Button } from ‘@philz/react-ui-kit’;
but got the following error:
Could not find a declaration file for module ‘@philz/react-ui-kit’
I could create and publish npm package.
Please refer if you need.
https://github.com/katsuharu/first-ui-component
https://www.npmjs.com/package/first-ui-component
Running into Button is not exported from library error. I have an index file that
exports * from ‘./components/Button/Button.tsx’
published and installed the library into a project and getting this error.
also I’m getting a cannot find type declarations error…
Did you manage to solve it?
I’m getting a bunch of errors relating to styled-components:
Module not found: Error: Can’t resolve ‘styled-components’ in ‘X:\Github\component-library-test2\node_modules\@lsg2099\react-component-library-test2\dist\esm’
WARNING in ./node_modules/@lsg2099/react-component-library-test2/dist/esm/index.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from ‘X:\Github\component-library-test2\node_modules\@lsg2099\react-component-library-test2\src\components\Button.tsx’ file: Error: ENOENT: no such file or directory, open ‘X:\Github\component-library-test2\node_modules\@lsg2099\react-component-library-test2\src\components\Button.tsx’
@ ./src/App.tsx 7:0-64 45:37-43
@ ./src/index.tsx 7:0-24 11:33-36
WARNING in ./node_modules/@lsg2099/react-component-library-test2/dist/esm/index.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from ‘X:\Github\component-library-test2\node_modules\@lsg2099\react-component-library-test2\src\components\Input.tsx’ file: Error: ENOENT: no such file or directory, open ‘X:\Github\component-library-test2\node_modules\@lsg2099\react-component-library-test2\src\components\Input.tsx’
@ ./src/App.tsx 7:0-64 45:37-43
@ ./src/index.tsx 7:0-24 11:33-36
Thats for starters. Most of the others are probably a result of the above failings. Did anyone else have this issue?
hi. where you able to resolve this?
You need add package ‘rollup-plugin-sass-modules’, after that add import it to rollup.config.js
import sassModules from ‘rollup-plugin-sass-modules’;
and use it in rules:
sassModules({include: [‘**/*.scss’, ‘**/*.sass’]})
Anybody having “Could not find a declaration file for module” error after publishing your library, You need to add type properties inside package.json.
“types”: “./dist/index.d.ts”,
hi.
I getting error while running ‘rollup -c’.
[!] Error: Could not resolve entry module (rollup.config.js).
I have a similar kind of task, I have a library which is created in typescript and we are using tsc and tsconfig.json to create the package in dist. We are using this package to link to a nextjs project and utilizing the library there, however the issuw we are facing is that we are not able to debug the component from the next js app, we have the source map on in the package but yet while debugging we are not able to get the debugger. We are using visual studio code for executing the next app
Thanks for the article. Apparently it’s just marketing given that there’s been lots of bug reports and no answers or revisions by the “author”
For me, for example, it says “Now, let’s create our button component:” but it never says what to name the file for that. Same with the input component. No filename is given.
I guess they were src/component/Button.tsx and src/component/Input.tsx but no idea as I got to “npm run buld” and I got
[!] RollupError: Node tried to load your configuration file as CommonJS even though it is likely an ES module. To resolve this, change the extension of your configuration to “.mjs”, set “type”: “module” in your package.json file or pass the “–bundleConfigAsCjs” flag.
That’s because at line 7 the rollup.config.js file uses “require” but that’s not allowed in a module. The author must have had some external options setup for that to work as there’s no way it works by default.
Changed that to
import fs from ‘fs’;
const packageJson = JSON.parse(fs.readFileSync(“./package.json”, ‘utf8’));
As others pointed out there is no `src/ndex.js` in the article. Tried what someone else posted but then I got
> rollup -c
src/index.ts → dist/cjs/index.js, dist/esm/index.js…
created dist/cjs/index.js, dist/esm/index.js in 604ms
dist/esm/types/index.d.ts → dist/index.d.ts…
[!] RollupError: Could not resolve entry module “dist/esm/types/index.d.ts”.
RollupError: Could not resolve entry module “dist/esm/types/index.d.ts”.
at error (/Users/gman/src/spector2/node_modules/rollup/dist/shared/rollup.js:206:30)
at ModuleLoader.loadEntryModule (/Users/gman/src/spector2/node_modules/rollup/dist/shared/rollup.js:23140:20)
at async Promise.all (index 0)
Basically AFAIK you should ignore this tutorial and go find another that actually works.
As others have said, this isn’t actually a good guide. Which is a bummer because I’ve seen other good ones from LogRocket. I’m unfortunately adding to the search shenanigans by interacting with it. But I do believe in other LogRocket guides so I feel good about it.