Skip to content

Instantly share code, notes, and snippets.

@sangramthecoder
Created February 23, 2021 06:58
Show Gist options
  • Save sangramthecoder/8648e7ff28f28f6a6ee9d0fe44a79339 to your computer and use it in GitHub Desktop.
Save sangramthecoder/8648e7ff28f28f6a6ee9d0fe44a79339 to your computer and use it in GitHub Desktop.
Create React Library with Simple zsh script
#!/bin/zsh
function jsonValue() {
KEY=$1
num=$2
awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p
}
echo "Creating directory " $1
mkdir $1
cd $1
echo "Initiate NPM Repository";
npm init
mkdir example example/public example/src && touch example/.gitignore example/package.json example/README.md example/public/index.html example/public/manifest.json example/public/robots.txt example/src/App.js example/src/index.js example/src/App.test.js example/src/reportWebVitals.js example/src/setupTests.js
mkdir src && touch src/index.tsx src/index.test.tsx src/$2.tsx
touch README.md rollup.config.js tsconfig.json .npmignore .babelrc .gitignore .eslintrc .eslintignore .editorconfig
echo "Creating .editorconfig content";
cat > .editorconfig <<EOF
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true%
EOF
echo "Creating .eslintrc content"
cat > .eslintrc <<EOF
{
"parser": "@typescript-eslint/parser",
"extends": [
"standard",
"standard-react",
"plugin:prettier/recommended",
"prettier/standard",
"prettier/react",
"plugin:@typescript-eslint/eslint-recommended"
],
"env": {
"node": true
},
"parserOptions": {
"ecmaVersion": 2020,
"ecmaFeatures": {
"legacyDecorators": true,
"jsx": true
}
},
"settings": {
"react": {
"version": "17"
}
},
"rules": {
"space-before-function-paren": 0,
"react/prop-types": 0,
"react/jsx-handler-names": 0,
"react/jsx-fragments": 0,
"react/no-unused-prop-types": 0,
"import/export": 0
}
}
EOF
echo "Creating .eslintignore content"
cat > .eslintignore <<EOF
dist/
node_modules/
.snapshots/
*.min.js
EOF
echo "Creating .gitignore content"
cat > .gitignore <<EOF
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules
/.pnp
.pnp.js
# testing
coverage
/coverage
# builds/production
build
dist
.rpt2_cache
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
EOF
echo "Creating .tsconfig.json content"
cat > tsconfig.json <<EOF
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"target": "es5",
"lib": ["es6","dom","es2016","es2017"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"declaration":true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "example", "rollup.config.js"]
}
EOF
echo "Creating .babelrc content"
cat > .babelrc <<EOF
{
"plugins": [],
"presets": [
"@babel/preset-react",
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"> 1%",
"Chrome >= 48",
"Firefox >= 44",
"Firefox ESR",
"Safari >= 9.1",
"Edge >= 12",
"ios_saf >= 9.3",
"ie 11"
]
},
"modules": false,
"forceAllTransforms": true
}
]
],
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
],
"plugins": [
[
"babel-plugin-styled-components",
{
"minify": false
}
]
]
}
}
}
EOF
echo "Creating rollup config js content"
cat > rollup.config.js << 'EOF'
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import external from 'rollup-plugin-peer-deps-external';
import { terser } from 'rollup-plugin-terser';
import { uglify } from 'rollup-plugin-uglify';
import typescript from 'rollup-plugin-typescript2';
import pkg from './package.json';
const input = "src/index.tsx"
export default [
{
input: input,
output: {
name: pkg.name,
file: `dist/${pkg.name}.dev.js`,
format: "cjs",
exports: "named",
},
plugins: [
resolve({
browser: true,
preferBuiltins: true,
extensions: [".mjs", ".js", ".jsx",".tsx"],
}),
external(),
babel({
exclude: "node_modules/**"
}),
commonjs({
include: "node_modules/**",
}),
typescript({
typescript: require("typescript"),
})
],
external: ["react", "react-dom"]
},
{
input: input,
output: {
name:pkg.name,
file: pkg.main,
format: "cjs",
exports: "named",
},
plugins: [
resolve({
browser: true,
preferBuiltins: true,
extensions: [".mjs", ".js", ".jsx",".tsx"],
}),
external(),
babel({
exclude: "node_modules/**"
}),
commonjs({
include: "node_modules/**",
}),
uglify(),
typescript({
typescript: require("typescript"),
})
],
external: ["react", "react-dom"]
},
{
input: input,
output: {
name:pkg.name,
file: pkg.module,
format: "es",
exports: "named",
},
plugins: [
resolve({
browser: true,
preferBuiltins: true,
extensions: [".mjs", ".js", ".jsx",".tsx"],
}),
external(),
babel({
exclude: "node_modules/**"
}),
commonjs({
include: "node_modules/**",
}),
terser(),
typescript({
typescript: require("typescript"),
})
],
external: ["react", "react-dom"]
},
{
input: input,
output: {
name: pkg.name,
file: `dist/${pkg.name}.umd.js`,
format: "umd",
globals: {
react: "React",
},
exports: "named",
},
plugins: [
resolve({
browser: true,
preferBuiltins: true,
extensions: [".mjs", ".js", ".jsx",".tsx"],
}),
external(),
babel({
exclude: "node_modules/**"
}),
commonjs({
include: "node_modules/**",
}),
uglify({}),
typescript({
typescript: require("typescript"),
})
],
external: ["react", "react-dom"]
}
]
EOF
echo "Going to install npm packages, this will take a while to complete"
npm i -D react react-dom react-scripts web-vitals typescript @types/react @types/react-dom @types/jest @types/node rollup rollup-plugin-typescript2 @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-terser rollup-plugin-uglify @babel/core @babel/runtime rimraf npm-run-all cross-env @testing-library/jest-dom @testing-library/react @testing-library/user-event
mainJsonPackage="package.json"
node > new_${mainJsonPackage} <<EOF
//Read data
var data = require("./${mainJsonPackage}");
//Manipulate data
data.main = "dist/index.cjs.js";
data.module = "dist/index.es.js";
data.browser = "dist/index.cjs.js";
data.types = "dist/index.d.ts";
data.scripts={
"prebuild": "rimraf dist",
"prepublishOnly": "npm run build",
"build": "rollup -c",
"watch": "rollup -c --watch",
"test": "run-s test:unit test:build",
"test:build": "run-s build",
"test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
"test:watch": "react-scripts test --env=jsdom"
}
data.peerDependencies = {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
};
data.files = ["dist"];
//Output data
console.log(JSON.stringify(data,null,2));
EOF
cp new_package.json package.json
rm new_package.json
packageName=`cat package.json | jsonValue name | xargs`;
echo "new package Name " $packageName;
cat > src/index.tsx << EOF
import $2 from "./$2";
export default $2;
EOF
cat > src/$2.tsx << EOF
const $2 = () => {
return (
<div>
Your $2 Component
</div>
)
}
export default $2;
EOF
cat > src/index.test.tsx << EOF
import $2 from '.'
describe("$2", () => {
it('is truthy', () => {
expect($2).toBeTruthy()
})
});
EOF
cp .gitignore example/.gitignore
cat > example/package.json <<EOF
{
"name": "example",
"version": "0.1.0",
"private": false,
"dependencies": {
"@testing-library/jest-dom": "file:../node_modules/@testing-library/jest-dom",
"@testing-library/react": "file:../node_modules/@testing-library/react",
"@testing-library/user-event": "file:../node_modules/@testing-library/user-event",
"react": "file:../node_modules/react",
"react-dom": "file:../node_modules/react-dom",
"react-scripts": "file:../node_modules/react-scripts",
"web-vitals": "file:../node_modules/web-vitals",
"$packageName": "file:.."
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
EOF
cat > example/public/index.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="$2 exmaple website"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Example $2</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
EOF
curl https://static.thenounproject.com/png/24031-200.png > example/public/favicon.ico
curl https://static.thenounproject.com/png/24031-200.png > example/public/logo192.png
cat > example/public/manifest.json << EOF
{
"short_name": "example",
"name": "$2 example app",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
EOF
cat > example/public/robots.txt << EOF
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
EOF
cat > example/src/App.js << EOF
import $2 from '$packageName';
import { useEffect, useState } from "react";
function App() {
const [count,setCount] = useState(0);
useEffect(() => {
setCount(prevCount => prevCount + 1);
},[]);
return (
<div className="App">
<$2 text={'Hola la le lo '} number={count}/>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>Learn React
</a>
</div>
);
}
export default App;
EOF
cat > example/src/index.js << EOF
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
EOF
cat > example/src/App.test.js << EOF
import { render, screen } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
EOF
cat > example/src/reportWebVitals.js << EOF
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
EOF
cat > example/src/setupTests.js << EOF
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom";
EOF
cd example
npm i
@sangramthecoder
Copy link
Author

Create React Library for npm packaging using zsh script.

Simple and robust. it accepts two parameters
Parameter 1: name of the library you want to create.
Parameter 2: name of the base component of your library.

Internally it uses rollup.js for bundling your package and uses typescript as a base for your library. It's important to have typescript because it helps others to know what api's/parameters are exposed for your react component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment