Skip to main content

Create React App

npx create-react-app app-name --scripts-version @sabertazimi/react-scripts --use-npm
npm init react-app app-name --scripts-version @sabertazimi/react-scripts --use-npm

CRA CLI

createReactApp.js:

init -> commander setup -> createApp() -> process CLI args -> run() -> process react-scripts@version and cra-template-xxx@version -> install react, react-dom, react-scripts and cra-template-xxx -> invoke react-scripts init for further process.

React Scripts

React Scripts Initialization

Initialization in react-scripts/scripts/init.js:

  • 可以用于改变默认 registry:
'use strict'

const registries = {
npm: 'https://registry.npmjs.org',
yarn: 'https://registry.yarnpkg.com',
aliyun: 'https://registry.npm.taobao.org',
}

module.exports = registries
  • 自定义安装默认依赖 (react, react-dom, react-router, redux etc.)
  • 额外安装模板依赖 packages.dependencies in cra-template/template.json
  • Setup package.json: appPackage.eslintConfig, appPackage.browserslist. appPackage.dependencies, appPackage.scripts and merge rest config in packages in cra-template/template.json (ignore `).
  • Copy template files from cra-template-xxx/template directory.
  • Setup git repository.
  • Install deps and devDeps list from react-scripts and cra-template-xxx.
  • Uninstall cra-template-xxx package.
  • Setup first git commit.
  • Print available scripts.
  • Done.

React Scripts Commands

Locating in react-scripts/scripts/:

  • start.js for react-scripts start.
  • build.js for react-scripts build.
  • test.js for react-scripts test.
  • eject.js for react-scripts eject.

React Scripts Start

When develop react-scripts locally with react-scripts start, it will use templatePath located in react-scripts/config/paths.js to find local template.

React Scripts Configuration

Config in react-scripts/config/ directory:

  • env.js: static environment variables.
  • getHttpsConfig.js: get HTTPS(SSL) config.
  • modules.js: locale modules webpack alias with baseUrl.
  • paths.js: configurable paths variables (most for Webpack config).
  • webpackDevServer.config.js: Webpack Dev Server configuration.
  • webpack.config.js: Webpack configuration (paths, deps/devDeps, plugins, loader rules etc.).
// Add support for Ant Design UI.
const webpackConfig = {
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve('babel-preset-react-app/webpack-overrides'),
plugins: [
[
require.resolve('babel-plugin-import'),
{
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
},
],
],
cacheDirectory: true,
cacheCompression: isEnvProduction,
compact: isEnvProduction,
},
}
// Add Webpack bundle analyzer plugin.
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

const webpackConfig = {
plugins: [
isEnvDevelopment
&& new BundleAnalyzerPlugin({
analyzerPort: 5000,
}),
].filter(Boolean),
}

CRA CSS

@import-normalize; /* bring in normalize.css styles */

/* rest of app styles */

CRA Public Folder

  • None of the files in public folder get post-processed or minified.
  • Missing files will not be called at compilation time, and will cause 404 errors for your users.
  • Result filenames won’t include content hashes so you’ll need to add query arguments or rename them every time they change.
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
class Component {
render() {
// Note: this is an escape hatch and should be used sparingly!
// Normally recommend using `import` for getting asset URLs
// as described in “Adding Images and Fonts” section.
return <img src={`${process.env.PUBLIC_URL}/img/logo.png`} alt="Here" />
}
}

CRA Environment Variables

  • Create custom environment variables beginning with REACT_APP_. Any other variables except NODE_ENV will be ignored.
  • HTML access environment variables %REACT_APP_XXX%.
  • JavaScript access environment variables via process.env.REACT_APP_XXX.
  • .env file define permanent environment variables:
    • npm start: .env.development.local>.env.local>.env.development>.env.
    • npm run build: .env.production.local>.env.local>.env.production>.env.
    • npm test: .env.test.local>.env.test>.env.
  • Environment variables list.
GENERATE_SOURCEMAP=false
REACT_APP_NOT_SECRET_CODE=abcdef
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<title>%REACT_APP_WEBSITE_NAME%</title>
export default function App() {
return (
<div>
<small>
You are running this application in
{' '}
<b>{process.env.NODE_ENV}</b>
{' '}
mode.
</small>
<form>
<input
type="hidden"
defaultValue={process.env.REACT_APP_NOT_SECRET_CODE}
/>
</form>
</div>
)
}
<div>
<small>You are running this application in <b>development</b> mode.</small>
<form>
<input type="hidden" value="abcdef" />
</form>
</div>

CRA Code Splitting

Code splitting for production build with import('dep').then();:

import type { ReportHandler } from 'web-vitals'

function reportWebVitals(onPerfEntry?: ReportHandler) {
if (onPerfEntry && typeof onPerfEntry === 'function') {
// Code splitting into separate chunk
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry)
getFID(onPerfEntry)
getFCP(onPerfEntry)
getLCP(onPerfEntry)
getTTFB(onPerfEntry)
})
}
}

export default reportWebVitals

CRA Service Worker

CRA Deployment

  • Official Documentation.
  • Deploy Subdirectory.
  • Cache-Control: max-age=31536000 for build/static assets, Cache-Control: no-cache for everything else. build/static file contents hash is embedded into the filename.
  • Change homepage in package.json:
    • "homepage": ".".
    • "homepage": "https://example.com/relative/path/".
  • Use path={'${process.env.PUBLIC_URL}/about'} in Routes.js when using react-router-dom.
  • Or use basename for react-router@^4.
// renders <a href="/calendar/today">
export default function App() {
return (
<BrowserRouter basename="/calendar">
<Link to="/today" />
</BrowserRouter>
)
}

SPA Deployment

  • Deployment services guide.

vercel.json:

{
"routes": [{ "src": "/[^.]+", "dest": "/", "status": 200 }]
}
{
"routes": [
{ "handle": "filesystem" },
{ "src": "/.*", "dest": "/index.html" }
]
}
# https://vercel.com/sabertaz/awesome-notes/settings/git
# Ignored Build Step
[ "$VERCEL_GIT_COMMIT_REF" == "gh-pages" ]

Netlify:

/*    /index.html   200

GitHub Pages:

# 404 fallback
ln -s index.html 404.html

Custom CRA

  • Custom packages/cra-template-*: change HTML/CSS/JS boilerplate.
  • Custom packages/react-scripts/config/: change paths, deps/devDeps, plugins, loader rules etc.
  • Custom packages/react-scripts/scripts/: change react-scripts CLI behaviors.
  • Custom react scripts.

CRA MonoRepo

  • babel-preset-react-app: babel preset configuration.
  • cra-template/cra-template-typescript: CRA default templates.
  • eslint-config-react-app: eslint configuration.
  • react-app-polyfill: polyfills for various browsers.
  • react-dev-utils: most utility functions for paths, helpers, middleware, and webpack plugins.

Custom React Scripts

In Create React App code:

const templatesVersionMinimum = '3.3.0'

// Assume compatibility if we can't test the version.
if (!semver.valid(packageVersion))
packageVersion = templatesVersionMinimum

// Only support templates when used alongside new react-scripts versions.
const supportsTemplates = semver.gte(packageVersion, templatesVersionMinimum)
if (supportsTemplates)
allDependencies.push(templateToInstall)

Due to version checking for template feature, custom react scripts should publish with version ^3.3.0 or ^4.x.x.

Custom CRA Templates

HTML/CSS/JSX boilerplate in react-scripts/template/ directory, now Templates are always named in the format cra-template-[template-name] in packages/cra-template and packages/cra-template-typescript.

npx create-react-app my-app --template [template-name]

Dependencies in template.json will bump to latest minor version automatically.

In react-scripts/scripts/utils/verifyTypeScriptSetup.js, if template src don't exist react-app-env.d.ts file, it will create automatically with reference to react-scripts types:

// Reference `react-scripts` types
if (!fs.existsSync(paths.appTypeDeclarations)) {
fs.writeFileSync(
paths.appTypeDeclarations,
`/// <reference types="react-scripts" />${os.EOL}`,
)
}