├── .eslintignore ├── .eslintrc.js ├── .github ├── FUNDING.yml └── workflows │ ├── npm-publish.yml │ └── test.action.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierrc.js ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── src ├── __tests__ │ └── index.test.tsx └── index.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | jest: true, 6 | }, 7 | extends: ['plugin:react/recommended', 'plugin:import/typescript', 'airbnb'], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | ecmaFeatures: { 11 | jsx: true, 12 | }, 13 | ecmaVersion: 'latest', 14 | sourceType: 'module', 15 | }, 16 | plugins: ['react', '@typescript-eslint'], 17 | settings: { 18 | 'import/resolver': { 19 | node: { 20 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 21 | }, 22 | }, 23 | }, 24 | rules: { 25 | 'import/prefer-default-export': 'off', 26 | 'arrow-body-style': ['error', 'as-needed'], 27 | 'implicit-arrow-linebreak': 'off', 28 | 'import/extensions': [ 29 | 'error', 30 | 'ignorePackages', 31 | { 32 | js: 'never', 33 | jsx: 'never', 34 | ts: 'never', 35 | tsx: 'never', 36 | }, 37 | ], 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [bring-shrubbery] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Publish 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-node@v2 16 | with: 17 | node-version: 14 18 | - run: yarn 19 | - run: yarn build 20 | 21 | publish-npm: 22 | needs: build 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/setup-node@v2 27 | with: 28 | node-version: 14 29 | registry-url: https://registry.npmjs.org/ 30 | - run: yarn publish --access public 31 | env: 32 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 33 | 34 | # Uncomment to publish to Github Package Registry. 35 | # You will also need to add Github Token to secret variables. 36 | # 37 | # publish-gpr: 38 | # needs: build 39 | # runs-on: ubuntu-latest 40 | # permissions: 41 | # contents: read 42 | # packages: write 43 | # steps: 44 | # - uses: actions/checkout@v2 45 | # - uses: actions/setup-node@v2 46 | # with: 47 | # node-version: 14 48 | # registry-url: https://npm.pkg.github.com/ 49 | # - run: npm ci 50 | # - run: npm publish 51 | # env: 52 | # NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 53 | -------------------------------------------------------------------------------- /.github/workflows/test.action.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: NPM Test Package 5 | 6 | on: 7 | push: 8 | branches: [main] 9 | pull_request: 10 | branches: [main] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x, 16.x, 17.x] 19 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: yarn 28 | - run: yarn build 29 | - run: yarn test 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .nyc_output 3 | .vscode 4 | build 5 | coverage 6 | node_modules 7 | npm-debug.log 8 | yarn-error.log 9 | yarn.lock 10 | __pycache__ 11 | dist 12 | .swc 13 | .turbo 14 | .vscode 15 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm test 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('@quassum/prettier-config'), 3 | } 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | antoni.silvestrovic@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Antoni Silvestrovič 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 😌 Easy NPM Package template for React 2 | 3 | This package is a template you can use to create [NPM](https://npmjs.org/) packages that work well with the React library. 4 | 5 | ## Project Overview 6 | 7 | This project includes following features: 8 | 9 | - 🚀 Ultra fast code bundling powered by [ESBuild](https://esbuild.github.io/) using [tsup](https://github.com/egoist/tsup). 10 | - 🚀 Turbo speed testing with [`@swc/jest`](), [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/). 11 | - 💅 Prettier for code formatting. 12 | - 💅 ESLint for code linting. 13 | - 🥺 Husky for commit validation. 14 | - 🚀 Github action to automatically publish the package on every Github Release. 15 | - 🚀 Github action to automatically test default branch or a new Pull Request. 16 | - 🚀 Double build for CommonJS and ES Modules - to support all JavaScript environments. 17 | 18 | ## Getting started 19 | 20 | ### `Use this template` button 21 | 22 | The easiest way of getting started with this template is to use the `Use this template` button at the top of this page - then follow the steps to create your own repo from it. 23 | 24 | ### Degit 25 | 26 | You can use [`degit`](https://github.com/Rich-Harris/degit) to clone this repo without the git history. 27 | 28 | ```bash 29 | npx degit github:bring-shrubbery/easy-npm-package-react 30 | ``` 31 | 32 | ### Adding source code and building 33 | 34 | All your source code should go into `src` folder. 35 | After you do that run `yarn build` and you'll have your code compiled into `dist` folder. 36 | You can also run `yarn test` to test your code after you add your tests. 37 | 38 | ### Environment Variables 39 | 40 | To have package automatically deployed on new release, add `npm_token` env variable to your Github repository. 41 | 42 | ## Support 43 | 44 | Please consider following this project's author, Antoni Silvestrovič on [Github](https://github.com/bring-shrubbery) or [Bluesky](https://bsky.app/profile/bring-shrubbery.bsky.social), or by starring the project to show your ❤️ and support. 45 | 46 | ## License 47 | 48 | [MIT](https://github.com/bring-shrubbery/easy-npm-package-react/blob/main/LICENSE) 49 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | rootDir: 'src', 4 | transform: { 5 | "^.+\\.(t|j)sx?$": ["@swc/jest"], 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easy-npm-package-react", 3 | "version": "1.0.0", 4 | "description": "Easy to use template for new NPM packages using React library", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "module": "dist/index.mjs", 8 | "files": [ 9 | "dist/" 10 | ], 11 | "engines": { 12 | "node": ">=14" 13 | }, 14 | "scripts": { 15 | "build": "tsup src/index.ts --format esm,cjs --dts --minify --external react", 16 | "test": "jest", 17 | "clean": "rimraf dist", 18 | "lint": "eslint ./src/**/*", 19 | "lint:fix": "npm run lint -- --fix", 20 | "format": "prettier --write ./src --loglevel error", 21 | "prepare": "husky install && npm run build", 22 | "posttest": "npm run lint" 23 | }, 24 | "keywords": [ 25 | "npm", 26 | "template", 27 | "react" 28 | ], 29 | "peerDependencies": { 30 | "react": "^17 || ^16.8", 31 | "react-dom": "^17 || ^16.8" 32 | }, 33 | "devDependencies": { 34 | "@quassum/prettier-config": "^1.2.0", 35 | "@swc/core": "^1.2.149", 36 | "@swc/jest": "^0.2.20", 37 | "@testing-library/react": "^12.1.3", 38 | "@testing-library/react-hooks": "^7.0.2", 39 | "@types/jest": "^27.4.1", 40 | "@types/node": "^14.18.12", 41 | "@types/react": "^17", 42 | "@types/react-dom": "^17", 43 | "@typescript-eslint/eslint-plugin": "^5.13.0", 44 | "@typescript-eslint/parser": "^5.13.0", 45 | "eslint": "^8.10.0", 46 | "eslint-config-airbnb": "^19.0.4", 47 | "eslint-plugin-import": "^2.25.4", 48 | "eslint-plugin-jsx-a11y": "^6.5.1", 49 | "eslint-plugin-react": "^7.29.3", 50 | "eslint-plugin-react-hooks": "^4.3.0", 51 | "husky": "^7.0.4", 52 | "jest": "^27.5.1", 53 | "prettier": "^2.5.1", 54 | "react": "^17", 55 | "react-dom": "^17", 56 | "react-test-renderer": "^17", 57 | "rimraf": "^3", 58 | "typescript": "^4.6.2" 59 | }, 60 | "homepage": "https://github.com/bring-shrubbery/easy-npm-package-react", 61 | "repository": { 62 | "type": "git", 63 | "url": "git+https://github.com/bring-shrubbery/easy-npm-package-react" 64 | }, 65 | "bugs": { 66 | "url": "https://github.com/bring-shrubbery/easy-npm-package-react/issues" 67 | }, 68 | "author": { 69 | "name": "Antoni Silvestrovič", 70 | "email": "antoni.silvestrovic@gmail.com", 71 | "url": "http://antoni.ai/" 72 | }, 73 | "license": "MIT", 74 | "dependencies": { 75 | "tsup": "^5.11.13" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | import { add } from '../index'; 2 | 3 | describe('Basic number addition', () => { 4 | test('should add up positive numbers', async () => { 5 | const sum = add(0, 1, 2, 3, 4, 5, 6); 6 | 7 | expect(sum).toEqual(21); 8 | }); 9 | 10 | test('should add up negative numbers', async () => { 11 | const sum = add(0, -1, -2, -3, -4, -5, -6); 12 | 13 | expect(sum).toEqual(-21); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the index of the project. Default export from this file 3 | * can be imported from the published npm package like so: 4 | * 5 | * ```js 6 | * import PackageName from 'your-package-name'; 7 | * ``` 8 | * 9 | * And non-default exports can be imported like this: 10 | * 11 | * ```jss 12 | * import {functionName} from 'your-package-name'; 13 | * ``` 14 | * 15 | * Created by Antoni Silvestrovic @bring-shrubbery 16 | */ 17 | 18 | /** 19 | * Adds up all parameters. 20 | * @param ...params Any number of parameters to be summed up 21 | * @returns Sum of the parameters 22 | */ 23 | export const add = (...params: number[]): number => 24 | params.reduce((prev, curr) => prev + curr, 0); 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Base Config", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "lib": ["ES2015"], 18 | "module": "ESNext", 19 | "target": "ES6", 20 | "jsx": "react-jsx", 21 | "allowJs": false, 22 | "baseUrl": "./src" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules"] 26 | } 27 | --------------------------------------------------------------------------------