I was too lazy to include webpack to bundle the react component as it needs a lot of boilerplate configuration code. so easiest way was to build the react typescript project using the typescript compiler with a little help from tsc-hooks.
you can follow the steps to know more about building and publishing a react project without the use of webpack.
Let's first initialise the project.
mkdir toggle-button
yarn init
or
npm init
Add the following packages as dev dependencies-
yarn add -D react react-dom @types/react @types/react-dom typescript tsc-hooks
or
npm install --save-dev react react-dom @types/react @types/react-dom typescript tsc-hooks
Update react as peer dependency so that the user of this package will be prompted to install react while adding this package.
now the package.json should look like -
package.json
{
"name": "react-toggle-button",
"version": "0.0.1",
"description": "React toggle button",
"main": "dist/", // update this
"scripts": {
"test": "yarn test",
"build": "tsc" // runs tsc compiler to build the project in dist directory (configured in tsconfig.json)
},
"repository": {
"type": "git",
"url": "git+https://github.com/YOUR-REPO/react-toggle-button.git"
},
"keywords": [
"react",
"react-toggle-button"
],
"author": "AUTHOR NAME",
"license": "ISC",
"bugs": {
"url": "https://github.com/YOUR-REPO/react-toggle-button/issues"
},
"homepage": "https://github.com/YOUR-REPO/react-toggle-button#readme",
"devDependencies": {
"@types/react": "^18.0.18",
"react": "^18.2.0",
"tsc-hooks": "^1.1.1", // needed to copy css files in the final build
"typescript": "^4.8.3"
},
"peerDependencies": {
"react": "^18.2.0" // add react as a peer dependency
},
"files": [
"/dist" // tells the bundler to only add dist folder while publishing the package. package.json will be automatically added.
]
}
Add tsconfig.json
now let's add tsconfig.json for the typescript compiler to know where and how to build the typescript files.
tsconfig.json
{
"compilerOptions": {
"target": "ES2015",
"jsx": "react",
"module": "esnext",
"moduleResolution": "node",
"allowJs": true,
"declaration": true, // required to generate corresponding *.d.ts files
"outDir": "./dist",
"esModuleInterop": true,
"strict": true,
"noImplicitAny": true,
},
"exclude": [
"node_modules",
],
"hooks": [
"copy-files" // copies all files to the dist folder
],
"include": [
"src/",
"src/**/*.module.css" // include css files while building the project using tsc
]
}
if you want to avoid copying all files to the final build then another workaround is to use a package copyfiles and add a script in package.json to manually copy selective files. For eg. In this case we are copying all css files.
package.json
...
"copy-files": "copyfiles -u 1 src/**/*.css dist/",
...
Add .npmignore
Add .npmignore to exclude src files from the final npm package build.
.npmignore
/src
Now lets add the react component in the src directory
src/ToggleButton/ToggleButton.tsx
import React from "react";
import styles from "./ToggleButton.module.css";
interface ToggleButtonProps {
onClick: () => void;
value: boolean;
}
const ToggleButton = ({ onClick, value }: ToggleButtonProps) => {
function clickHandler() {
onClick();
}
return (
<div
id={value ? "on" : "off"}
className={styles.toggleButton}
onClick={clickHandler}
>
<div className={styles.bar}>
<div className={styles.circle}></div>
</div>
</div>
);
};
export default ToggleButton;
src/ToggleButton/ToggleButton.module.css
.toggleButton {
position: relative;
width: 36px;
height: 1rem;
display: flex;
align-items: center;
}
.circle {
width: 17px;
height: 17px;
border-radius: 50%;
position: absolute;
top: 50%;
transform: translateY(-50%);
transition: all 0.3s ease-in;
--on : #eb5757;
--off: #e0e0e0;
}
.bar {
height: 20px;
width: 100%;
border-radius: 50px;
padding: 2px;
}
#on .bar {
background-color: var(--on);
}
#off .bar {
background-color: var(--off);
}
#on .circle {
background-color: var(--on);
left: calc(100% - 19px);
}
#off .circle {
background-color: var(--off);
left: 2px;
}
Add declarations.d.ts
Add declarations.d.ts file so that typescript compliler know about the *.module.css files.
src/declarations.d.ts
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}
Directory structure should look like -
Add Readme file
Don't forget to add a README.md file in the root directory with all the installation and usage of the package you are deploying. I am skipping this step in the example.
Build package & Publish
Lets run tsc compiler to generate the respective files in dist directory -
yarn build // spits the output files in the dist/ directory
now we are ready to publish the package. If you are deploying for the first time - create an npm account and login in the terminal.
npm login // skip this if you are already logged in
npm publish
Update the package version before every publish otherwise the publish will fail.