├── .eslintignore ├── .huskyrc ├── src ├── types │ └── index.ts ├── index.ts ├── css │ └── tailwind-setup.css ├── assets │ └── check.svg ├── stories │ └── ReactLibraryStarter.stories.tsx ├── components │ └── App.tsx └── typings.d.ts ├── .lintstagedrc ├── .storybook ├── Layout.tsx ├── preview.js └── main.js ├── tailwind.config.js ├── .prettierrc ├── postcss.config.js ├── .gitignore ├── tsconfig.json ├── LICENSE ├── rollup.config.js ├── .eslintrc.json ├── README.md └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "lint-staged" 4 | } 5 | } -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type AppProps = { 2 | text?: string 3 | description?: string 4 | } 5 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import './css/tailwind-setup.css' 2 | 3 | export { default as MyComponent } from './components/App' 4 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "*.{ts,tsx}": ["eslint --fix"], 4 | "**/*.+(ts|tsx|json|css|md)": ["prettier --write"] 5 | } -------------------------------------------------------------------------------- /src/css/tailwind-setup.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .app { 6 | @apply bg-green-400; 7 | } 8 | -------------------------------------------------------------------------------- /.storybook/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Layout: React.FC = ({ children }) => { 4 | return
{children}
5 | } 6 | 7 | export default Layout 8 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | future: {}, 3 | purge: ['./src/**/*.tsx'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | variants: {}, 8 | plugins: [], 9 | } 10 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { addDecorator } from '@storybook/react' 3 | import Layout from './Layout' 4 | 5 | addDecorator(storyFn => {storyFn()}) 6 | -------------------------------------------------------------------------------- /src/assets/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": true, 4 | "jsxBracketSameLine": false, 5 | "jsxSingleQuote": false, 6 | "printWidth": 80, 7 | "semi": false, 8 | "singleQuote": true, 9 | "tabWidth": 2, 10 | "trailingComma": "es5", 11 | "useTabs": false 12 | } 13 | -------------------------------------------------------------------------------- /src/stories/ReactLibraryStarter.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { MyComponent } from '..' 3 | 4 | export default { 5 | title: 'React Library Starter', 6 | } 7 | 8 | export const Default: React.FC = () => { 9 | return ( 10 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-flexbugs-fixes'), 4 | require('postcss-preset-env')({ 5 | autoprefixer: { 6 | flexbox: 'no-2009', 7 | }, 8 | stage: 3, 9 | features: { 10 | 'custom-properties': false, 11 | }, 12 | }), 13 | require('tailwindcss')('./tailwind.config.js'), 14 | require('cssnano'), 15 | ], 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /dist 13 | /storybook-static 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "dist", 5 | "module": "esnext", 6 | "target": "es5", 7 | "lib": ["es6", "dom", "es2016", "es2017"], 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "moduleResolution": "node", 11 | "allowSyntheticDefaultImports": true, 12 | "esModuleInterop": true 13 | }, 14 | "include": ["./src/**/*"], 15 | "exclude": ["node_modules", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { AppProps } from '../types' 3 | import { ReactComponent as Check } from '../assets/check.svg' 4 | 5 | const App: React.FC = ({ text, description }) => { 6 | return ( 7 |
8 |
9 | 10 |
11 |

{text}

12 |

{description}

13 |
14 | ) 15 | } 16 | export default App 17 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Default CSS definition for typescript, 3 | * will be overridden with file-specific definitions by rollup 4 | */ 5 | declare module '*.css' { 6 | const content: { [className: string]: string } 7 | export default content 8 | } 9 | 10 | interface SvgrComponent extends React.FC> {} 11 | 12 | declare module '*.svg' { 13 | const svgUrl: string 14 | const svgComponent: SvgrComponent 15 | export default svgUrl 16 | export { svgComponent as ReactComponent } 17 | } 18 | 19 | // use this to provide proper keys to elements on an array 20 | // https://reactjs.org/docs/lists-and-keys.html#keys 21 | declare module 'react-uuid' 22 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../src/**/*.stories.tsx'], 3 | webpackFinal: async config => { 4 | const assetRule = config.module.rules.find(({ test }) => test.test('.svg')) 5 | 6 | const assetLoader = { 7 | loader: assetRule.loader, 8 | options: assetRule.options || assetRule.query, 9 | } 10 | config.module.rules.push({ 11 | test: /\.(ts|tsx)$/, 12 | use: [ 13 | { 14 | loader: require.resolve('ts-loader'), 15 | }, 16 | ], 17 | }) 18 | config.module.rules.unshift({ 19 | test: /\.svg$/, 20 | use: ['@svgr/webpack', assetLoader], 21 | }) 22 | config.resolve.extensions.push('.ts', '.tsx') 23 | return config 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rhaidzsal Ali 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 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import peerDepsExternal from 'rollup-plugin-peer-deps-external' 2 | import resolve from '@rollup/plugin-node-resolve' 3 | import commonjs from '@rollup/plugin-commonjs' 4 | import typescript from 'rollup-plugin-typescript2' 5 | import postcss from 'rollup-plugin-postcss' 6 | import svgr from '@svgr/rollup' 7 | import url from '@rollup/plugin-url' 8 | import analyze from 'rollup-plugin-analyzer' 9 | 10 | const packageJson = require('./package.json') 11 | 12 | export default { 13 | input: 'src/index.ts', 14 | output: [ 15 | { 16 | exports: 'named', 17 | file: packageJson.main, 18 | format: 'cjs', 19 | sourcemap: true, 20 | }, 21 | { 22 | exports: 'named', 23 | file: packageJson.module, 24 | format: 'esm', 25 | sourcemap: true, 26 | }, 27 | { 28 | name: 'ReactLibraryStarter', 29 | file: packageJson.unpkg, 30 | format: 'umd', 31 | globals: { 32 | react: 'React', 33 | }, 34 | }, 35 | ], 36 | plugins: [ 37 | peerDepsExternal(), 38 | postcss({ 39 | minimize: true, 40 | modules: false, 41 | extract: true, 42 | config: { 43 | path: './postcss.config.js', 44 | ctx: null, 45 | }, 46 | }), 47 | url(), 48 | svgr(), 49 | resolve(), 50 | commonjs(), 51 | typescript({ useTsconfigDeclarationDir: true }), 52 | analyze(), 53 | ], 54 | external: ['react'], 55 | } 56 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "ecmaFeatures": { 5 | "jsx": true 6 | }, 7 | "ecmaVersion": 11, 8 | "sourceType": "module" 9 | }, 10 | "env": { 11 | "browser": true, 12 | "es6": true 13 | }, 14 | "globals": { 15 | "Atomics": "readonly", 16 | "SharedArrayBuffer": "readonly" 17 | }, 18 | "extends": [ 19 | "plugin:react/recommended", 20 | "airbnb", 21 | "airbnb/hooks", 22 | "plugin:@typescript-eslint/recommended", 23 | "prettier", 24 | "prettier/react", 25 | "prettier/@typescript-eslint" 26 | ], 27 | "plugins": ["react", "import", "prettier", "@typescript-eslint"], 28 | "rules": { 29 | // prettier 30 | "prettier/prettier": ["error"], 31 | // TypeScript 32 | "@typescript-eslint/no-unused-vars": "error", 33 | "@typescript-eslint/no-empty-interface": [ 34 | "error", 35 | { 36 | "allowSingleExtends": true 37 | } 38 | ], 39 | // React 40 | "react/prop-types": ["off", {}], 41 | "react/jsx-filename-extension": [ 42 | 1, 43 | { 44 | "extensions": [".ts", ".tsx"] 45 | } 46 | ], 47 | "react/jsx-props-no-spreading": "off", 48 | "import/extensions": [ 49 | "error", 50 | "ignorePackages", 51 | { 52 | "js": "never", 53 | "jsx": "never", 54 | "ts": "never", 55 | "tsx": "never" 56 | } 57 | ], 58 | "import/prefer-default-export": "off" 59 | }, 60 | "settings": { 61 | "import/resolver": { 62 | "typescript": {} // this loads /tsconfig.json to eslint 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-library-starter 2 | 3 | ⚡ A library starter kit and bundler for your React projects, powered by Rollup. 4 | 5 | ## Features 6 | 7 | - React with TypeScript support 8 | - [Rollup](https://rollupjs.org/) for bundling (with a customizable bundler config file) 9 | - [Babel](https://babeljs.io/) for transpiling 10 | - [Storybook](https://storybook.js.org) for development and component explorer 11 | - [SVGR](https://react-svgr.com/) support 12 | - Uses [TailwindCSS 2.0](https://blog.tailwindcss.com/tailwindcss-v2) 13 | - Linting before commit support with [ESLint](https://eslint.org/), [Husky](https://github.com/typicode/husky) and [Lint Staged](https://github.com/okonet/lint-staged) 14 | - Supports CSS modules configurable with [PostCSS](https://postcss.org/) 15 | - [styled-components](https://styled-components.com/) support 16 | - [react-uuid](https://www.npmjs.com/package/react-uuid) for component key indexing 17 | - Supports CJS, ESM and UMD formats 18 | - Sourcemap creation 19 | 20 | 21 | ## Development 22 | 23 | Clone this repo and run the following commands to start development with Storybook. 24 | 25 | ```bash 26 | npm install --production=false 27 | npm run storybook 28 | ``` 29 | 30 | Go to `localhost:6006` and you should see something like this. 31 | 32 | ![storybook-dev](https://user-images.githubusercontent.com/22829115/101779100-c59f8680-3b2f-11eb-985f-ca2ba37ed1f7.png) 33 | 34 | ## Building 35 | To build your project, run `npm run build`. 36 | 37 | ## Publishing 38 | ```bash 39 | npm publish 40 | ``` 41 | This builds `commonjs`, `esm`, and `umd` versions of your module to `dist/` and then publishes your module to `npm`. 42 | Make sure that any npm modules you want as peer dependencies are properly marked as `peerDependencies` in `package.json`. The rollup config will automatically recognize them as peers and not try to bundle them in your module. 43 | 44 | ## License 45 | 46 | MIT © [Rhaidzsal Ali](https://github.com/rhaicode) 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-library-starter", 3 | "version": "1.0.0", 4 | "description": "A bundler for your React projects, powered by Rollup.", 5 | "author": "rhaicode", 6 | "license": "MIT", 7 | "repository": "rhaicode/react-library-starter", 8 | "main": "dist/index.js", 9 | "module": "dist/index.modern.js", 10 | "unpkg": "dist/index.umd.js", 11 | "files": [ 12 | "dist" 13 | ], 14 | "scripts": { 15 | "build": "cross-env NODE_ENV=production && rm -rf dist && rollup -c", 16 | "storybook": "start-storybook -p 6006", 17 | "build-storybook": "build-storybook" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.10.5", 21 | "@rollup/plugin-commonjs": "^14.0.0", 22 | "@rollup/plugin-node-resolve": "^8.4.0", 23 | "@rollup/plugin-url": "^6.0.0", 24 | "@storybook/addon-actions": "^6.1.10", 25 | "@storybook/addon-links": "^6.1.10", 26 | "@storybook/addons": "^6.1.10", 27 | "@storybook/react": "^6.1.10", 28 | "@svgr/rollup": "^5.5.0", 29 | "@svgr/webpack": "^5.5.0", 30 | "@types/react": "^16.9.27", 31 | "@types/react-dom": "^16.9.7", 32 | "@types/styled-components": "^5.1.4", 33 | "@typescript-eslint/eslint-plugin": "^3.7.1", 34 | "@typescript-eslint/parser": "^3.7.1", 35 | "autoprefixer": "^10.1.0", 36 | "babel-loader": "^8.1.0", 37 | "cross-env": "^7.0.3", 38 | "cssnano": "^4.1.10", 39 | "eslint": "^7.6.0", 40 | "eslint-config-airbnb": "^18.2.0", 41 | "eslint-config-prettier": "^6.11.0", 42 | "eslint-import-resolver-typescript": "^2.2.0", 43 | "eslint-plugin-import": "^2.22.0", 44 | "eslint-plugin-jsx-a11y": "^6.3.1", 45 | "eslint-plugin-prettier": "^3.1.4", 46 | "eslint-plugin-react": "^7.20.5", 47 | "eslint-plugin-react-hooks": "^4.0.8", 48 | "husky": "^4.2.5", 49 | "lint-staged": "^10.2.11", 50 | "postcss": "^8.2.0", 51 | "postcss-flexbugs-fixes": "^4.2.1", 52 | "postcss-modules": "^4.0.0", 53 | "postcss-preset-env": "^6.7.0", 54 | "prettier": "^2.0.5", 55 | "react": "^16.13.1", 56 | "react-dom": "^16.13.1", 57 | "rollup": "^2.23.0", 58 | "rollup-plugin-analyzer": "^3.3.0", 59 | "rollup-plugin-peer-deps-external": "^2.2.3", 60 | "rollup-plugin-postcss": "^4.0.0", 61 | "rollup-plugin-typescript2": "^0.27.1", 62 | "ts-loader": "^8.0.1", 63 | "typescript": "^3.9.7" 64 | }, 65 | "peerDependencies": { 66 | "react": ">=16.8.0", 67 | "react-dom": ">=16.8.0", 68 | "tailwindcss": ">=2.0.1" 69 | }, 70 | "dependencies": { 71 | "@use-it/event-listener": "^0.1.6", 72 | "casual-browserify": "^1.5.19-2", 73 | "clsx": "^1.1.1", 74 | "react-uuid": "^1.0.2", 75 | "styled-components": "^5.2.1", 76 | "tailwindcss": "^2.0.1" 77 | } 78 | } 79 | --------------------------------------------------------------------------------