Skip to content

JustOpposite/learn-to-npm-packaging-react-ts-library

Repository files navigation

Steps to create a React Typescript npm library

This tutorial is based on Article by Igor Gaponov

su npm i -g pnpm

mkdir <lib name>

cd <lib name>

npm init -y

pnpm i -D react react-dom typescript @types/react

$ touch .prettierignore with following:

$ vi package.json with following:

{
   ...
   "type": "module"
   ...
}

$ touch tsconfig.json with following:

{
   "include": ["src"],
   "exclude": ["dist", "node_modules"],
   "compilerOptions": {
      "module": "esnext",
      "lib": ["dom", "esnext"],
      "importHelpers": true,
      "declaration": true,
      "sourceMap": true,
      "rootDir": "./src",
      "outDir": "./dist/esm",
      "strict": true,
      "noImplicitReturns": true,
      "noFallthroughCasesInSwitch": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "moduleResolution": "node",
      "jsx": "react",
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true
   }
}

$ touch App.tsx with following:

import React, { useState } from "react";

export type Props = {
   value?: number,
};
const MyCounter = ({ value = 0 }: Props) => {
   const [counter, setCounter] = useState(value);

   const onMinus = () => {
      setCounter((prev) => prev - 1);
   };

   const onPlus = () => {
      setCounter((prev) => prev + 1);
   };

   return (
      <div>
         <h1>Counter: {counter}</h1>
         <button onClick={onMinus}>-</button>
         <button onClick={onPlus}>+</button>
      </div>
   );
};

$ touch src/index.ts with following:

export * from './components/MyCounter'

$ vi package.json with following:

{
   ...
   "scripts": {
      ...
      "build": "tsc",
      ...
   },
   ...
}

$ pnpm run build

$ git init

$ touch .gitignore with following:

node_modules
.vscode
dist
yarn-error.log

$ pnpm add -D eslint eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser

$ touch .eslintrc with following:

{
  "root": true,
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint",
    "react",
    "react-hooks"
  ],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "@typescript-eslint/no-non-null-assertion": "off",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/no-explicit-any": "off"
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "env": {
    "browser": true,
    "node": true
  },
  "globals": {
    "JSX": true
  }
}

$ touch .eslintignore with following:

node_modules
dist
README.md

$ vi package.json with following:

{
   ...
   "scripts": {
      ...
      "lint": "eslint \"{**/*,*}.{js,ts,jsx,tsx}\""
      ...
   },
   ...
}

$ pnpm run lint

$ pnpm add -D eslint-config-prettier eslint-plugin-prettier prettier

$ touch .prettierrc with following:

{
   "bracketSpacing": true,
   "singleQuote": true,
   "trailingComma": "none",
   "tabWidth": 2,
   "semi": false,
   "printWidth": 120,
   "jsxSingleQuote": true,
   "endOfLine": "auto"
}

$ vi .eslintrc with following:

{
  "root": true,
  "extends": [
    "prettier",
    "plugin:prettier/recommended",
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint",
    "prettier",
    "react",
    "react-hooks"
  ],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "@typescript-eslint/no-non-null-assertion": "off",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/no-explicit-any": "off"
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "env": {
    "browser": true,
    "node": true
  },
  "globals": {
    "JSX": true
  }
}

$ vi package.json with following:

{
   ...
   "scripts": {
      ...
      "prettier": "prettier --write \"{src,tests,example/src}/**/*.{js,ts,jsx,tsx}\""
      ...
   },
   ...
}

$ pnpm run prettier

$ pnpm add -D jest jest-canvas-mock jest-environment-jsdom ts-jest @types/jest @testing-library/react tslib

$ touch jestconfig.json with following:

{
  "transform": {
    "^.+\\.(t|j)sx?$": "ts-jest"
  },
  "testRegex": "(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
  "testEnvironment": "jsdom"
}

$ mkdir tests

$ cd tests

$ touch common.test.tsx with following:

import * as React from 'react'
import { render } from '@testing-library/react'

import 'jest-canvas-mock'

import { MyCounter } from '../src'

describe('Common render', () => {
  it('renders without crashing', () => {
    render(<MyCounter />)
  })
})

$ vi package.json with following:

{
   ...
   "scripts": {
      ...
      "test": "jest --config jestconfig.json"
      ...
   },
   ...
}

$ pnpm run test

$ vi package.json with following:

{
   ...
   "scripts": {
      ...
      "build": "pnpm run build:esm && pnpm run build:cjs",
      "build:esm": "tsc",
      "build:cjs": "tsc --module commonjs --outDir dist/cjs",
      ...
   },
   ...
}

$ pnpm run build

$ vi package.json with following:

{
   "name": "learn-to-npm-packaging-react-ts-library",
   "version": "0.0.1",
   "description": "This is just an sample project to learn how to build and deploy a react typescript library",
   "main": "./dist/cjs/index.js",
   "module": "./dist/esm/index.js",
   "types": "./dist/esm/index.d.ts",
   ...
   "repository": {
      "type": "git",
      "url": "git+https://github.com/JustOpposite/learn-to-npm-packaging-react-ts-library.git"
   },
   "peerDependencies": {
      "react": ">=16"
   },
   "files": [
      "dist",
      "LICENSE",
      "README.md"
   ],
   "keywords": [
      "react",
      "typescript",
      "learn-npm-packaging-react"
   ],
   "author": "Just Opposite (justopposite)",
   ...
   "scripts": {
      ...
      "prepare": "pnpm run build",
      "prePublishOnly": "pnpm run test && pnpm run prettier && pnpm run lint",
      ...
   },
   ...
}

$ git add . $ git commit -m "Initial commit" $ git remote add origin git@github.com:JustOpposite/learn-to-npm-packaging-react-ts-library.git $ git push -u origin main

Alternative is to clone the repo first then make changes before git push

Publish to NPM

Assuming you have an user created on npm

$ npm login

$ npm publish --dry-run

If there are no errors then

$ npm publish

Press Enter to open in browser, when prompted for 2FA code, open up Duo for OTP

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published