Skip to content

Instantly share code, notes, and snippets.

@bmingles
Last active February 17, 2020 00:43
Show Gist options
  • Save bmingles/72d03b02effa3b77a0fdf794f42db939 to your computer and use it in GitHub Desktop.
Save bmingles/72d03b02effa3b77a0fdf794f42db939 to your computer and use it in GitHub Desktop.
NodeJS script to scaffold minimal React + TypeScript app using ParcelJS
#!/usr/bin/env node
/**
* Script for scafolding a React + TypeScript app using
* ParcelJS as a bundler.
*
* - TypeScript
* - React
* - ParcelJS
* - Sass
* - eslint
* - prettier
*/
const fs = require('fs')
const path = require('path')
if (process.argv.length < 3) {
console.error('Missing app directory arg.')
process.exit(1)
}
const appRoot = path.resolve(process.argv[2])
const appName = appRoot.substr(appRoot.lastIndexOf(path.sep) + 1)
if (fs.existsSync(appRoot)) {
console.error(`${appRoot} already exists.`)
process.exit(1)
}
fs.mkdirSync(path.join(appRoot, 'src', 'components'), { recursive: true })
fs.writeFileSync(
path.join(appRoot, 'package.json'),
`{
"name": "${appName}",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
"@typescript-eslint/eslint-plugin": "^2.19.2",
"@typescript-eslint/parser": "^2.19.2",
"eslint": "^6.8.0",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^2.3.0",
"node-sass": "^4.13.1",
"parcel-bundler": "^1.12.4",
"prettier": "^1.19.1",
"typescript": "^3.7.5"
},
"scripts": {
"build": "parcel build index.html",
"start": "parcel index.html"
},
"dependencies": {
"react": "^16.12.0",
"react-dom": "^16.12.0"
}
}
`
)
fs.writeFileSync(
path.join(appRoot, 'tsconfig.json'),
`{
"compilerOptions": {
"downlevelIteration": true,
"esModuleInterop": true,
"jsx": "react",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"strict": true
},
"exclude": [
"node_modules"
],
"include": ["src/**/*"]
}`
)
fs.writeFileSync(
path.join(appRoot, '.prettierrc.js'),
`module.exports = {
semi: false,
singleQuote: true,
trailingComma: 'all',
tabWidth: 2,
};`
)
fs.writeFileSync(
path.join(appRoot, '.gitignore'),
`.cache
/dist
node_modules`
)
fs.writeFileSync(
path.join(appRoot, 'index.html'),
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${appName[0].toUpperCase()}${appName.slice(1)}</title>
</head>
<body>
<div id="app"></div>
<script src="src/index.tsx"></script>
</body>
</html>
`
)
fs.writeFileSync(
path.join(appRoot, 'src', 'index.tsx'),
`import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './components'
import './index.scss'
ReactDOM.render(<App />, document.getElementById('app'))`
)
fs.writeFileSync(
path.join(appRoot, 'src', 'components', 'App.tsx'),
`import React from 'react'
export interface AppProps {}
const App: React.FC<AppProps> = () => <div>App</div>
export default App`
)
fs.writeFileSync(
path.join(appRoot, 'src', 'index.scss'),
`* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
font-size: 16px;
}`
)
fs.writeFileSync(
path.join(appRoot, 'src', 'components', 'index.ts'),
`export { default as App } from './App'`
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment