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,reduxetc.) - 额外安装模板依赖
packages.dependenciesincra-template/template.json - Setup
package.json:appPackage.eslintConfig,appPackage.browserslist.appPackage.dependencies,appPackage.scriptsand merge rest config inpackagesincra-template/template.json(ignore `). - Copy template files from
cra-template-xxx/templatedirectory. - Setup git repository.
- Install deps and devDeps list from
react-scriptsandcra-template-xxx. - Uninstall
cra-template-xxxpackage. - Setup first git commit.
- Print available scripts.
- Done.
React Scripts Commands
Locating in react-scripts/scripts/:
start.jsforreact-scripts start.build.jsforreact-scripts build.test.jsforreact-scripts test.eject.jsforreact-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 withbaseUrl.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
404errors for your users. - Result filenames won’t include
content hashesso 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 exceptNODE_ENVwill be ignored. - HTML access environment variables
%REACT_APP_XXX%. - JavaScript access environment variables via
process.env.REACT_APP_XXX. .envfile 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=31536000forbuild/staticassets,Cache-Control: no-cachefor everything else.build/staticfile contents hash is embedded into the filename.- Change
homepageinpackage.json:"homepage": "."."homepage": "https://example.com/relative/path/".
- Use
path={'${process.env.PUBLIC_URL}/about'}inRoutes.jswhen usingreact-router-dom. - Or use
basenameforreact-router@^4.
// renders <a href="/calendar/today">
export default function App() {
return (
<BrowserRouter basename="/calendar">
<Link to="/today" />
</BrowserRouter>
)
}
SPA Deployment
- Deployment services guide.
{
"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" ]
/* /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}`,
)
}