Generate a one stop shop CLI for building and testing your React applications.
React Ryo CLI is a roll-your-own version of CRA ("create-react-app") react-scripts
CLI, where you can reconfigure internal configurations, such as Webpack, Babel, and Jest. This package is based on Craco. Using the aforementioned third-party, we are able to abstract away the intricacies of cross-industry build tools and their configurations, yet keep a "roll-your-own" approach to enable fine-grain changes. While Vue.js already incorporated customizability in its CLI, CRA does not follow the same path, hence solutions like Craco have emerged, followed by this package.
This package is a work in progress. You can expect API changes from what is currently described in this documentation. Feel free to review, offer suggestions, improvements etc'.
Execute the following command to create a boilerplate for your own CLI package.
$ npx react-ryo-cli init
Or add to an existing package:
$ npm install react-ryo-cli
$ yarn add react-ryo-cli
Create a craco.config.js
file at the root of your package and react-ryo-cli
will pick it up. See Craco docs for its configuration API. Your configuration will be merged with react-ryo-cli
default configuration. However, you can choose to opt-out by calling spawnApi
with { noExtend: true }
or by calling your CLI with the --noExtend
argument. See all arguments.
This package is mainly targeted at UI infrastructure teams, architects, leads and anyone who maintains several React applications across their organization.
TL;DR: Create your own one stop shop CLI for building and testing your React.js applications.
Many software companies develop more than one front-end application (based on React) which means at some point they run into an infrastructure problem where they would have CRA boilerplate copies everywhere, which are not customizable and uncontrolled. To solve this issue, you can either create an internal package that will configure its own set of build-tool configurations or eject from CRA. It's also possible to fork CRA, apply your changes and have a bot that will sync your fork with its origin. All of these solutions have far too many drawbacks for real world usage.
While an internal package seems beneficial, it's a rather risky approach, because instead of relying on the black box that is react-scripts
, you are now taking full responsibility for those build tools and the pitfalls that will follow. Another pet peeve is maintenance. Build tools configurations can be esoteric, which means a select few will be able to maintain it. Given the many years of development Facebook has done on their CLI, it's definitely not worth giving it up for your own proprietary solution.
Craco to the rescue. Craco essentially replaces react-scripts
with scripts you can customize, without actually detaching from react-scripts
. While it solves our main concern, it does not solve the infrastructure problem, where managing more than one application creates a hoard of unmaintainable boilerplate duplication. Hence, this package was born. It allows you to create your own CLI for building and testing, which you can publish and distribute across your organization.
Combined with Craco, this is what you get.
- CRA 3.* support.
- Node.js 8.16.* support.
- One stop shop CLI for your React applications.
- Scalable and more future-proof than other solutions.
- Adherence to industry standards without the lock penalty.
- Abstracts away intricate configurations, which helps avoiding configuration pitfalls.
- Setups Jest and Enzyme with real-world configurations, so you can focus on writing tests only.
- Styled-Components configuration for Jest.
- Automatic Lodash tree shaking.
You can configure up to three layers of Craco configurations by placing a craco.config.js
at the root of your project and/or CLI package and react-ryo-cli
will merge them on top of each other. A CLI built with react-ryo-cli
can choose to opt-put from the default Craco configuration by passing a noExtend
option to spawnCli
API. However, the topmost configuration will still merge onto the default configuration provided by the custom CLI. See illustration:
📦 react-app
┣ 📂 node_modules
┃ ┣ 📂 react-ryo-cli
+ ┃ ┃ ┗ 📜 craco.config.js
┃ ┗ 📂 <your-cli-package>
+ ┃ ┃ ┗ 📜 craco.config.js
+ ┗ 📜 craco.config.js
When testing, the following modules are imported automatically, hence you don't have to manually import them on every .spec
file, so you can focus on writing your tests. 🎯
/* React, Enzyme.shallow, Enzyme.mount, Enzyme.render */
Circumvent CRA restriction when importing files out of src
, by defining an allowed-files.json
file at the root of your project. JSON should be an array of relative paths. See this Stack Overflow page and this CRA issue for more details. Mind, this is an escape hatch and mostly discouraged, so use with caution.
Assume the following file structure (e.g. with Yarn workspaces):
📦 workspace-root
┣ 📂 react-app (workspace)
┃ ┗ 📂 src
┃ ┃ ┗ 📂 components
+ ┃ ┃ ┃ ┗ 📜 Foo.js
┣ 📜 allowed-files.json
+ ┗ 📜 README.md
Setup
allowed-files.json
👉:
Notice our relative path needs to go back once to reach README.md
:
JSON Path:
<rootDir>/README.md
["../README.md"]
In your app:
Notice we have to go back three times to reach README.md
.
Module path:
<rootDir>/sub_project/src/components/Foo.js
import readme from '../../../README.md'
If all done correctly, you should be able to import README.md
successfully.
Update existing calls to react-scripts
in the scripts
section of your package.json
file to use your CLI. You can also update them automatically.
/* package.json */
"scripts": {
- "start": "react-scripts start",
+ "start": "<your-cli-package> start",
- "build": "react-scripts build",
+ "build": "<your-cli-package> build",
- "test": "react-scripts test",
+ "test": "<your-cli-package> test",
}
Out of the box, every react-scripts
script will work except for eject
, as ejecting defeats the purpose of having a custom CLI.
react-ryo-cli
provides a few extra scripts for your convenience:
/* package.json */
"scripts": {
+ "build:development": "<your-cli-package> build:development",
+ "build:stats": "<your-cli-package> build:stats",
+ "test:watch": "<your-cli-package> test:watch",
+ "test:update": "<your-cli-package> test:update",
+ "test:production": "<your-cli-package> test:production",
+ "inspect": "<your-cli-package> build --inspect",
+ "inspect:output": "<your-cli-package> build --inspect > output.json",
}
You can automate this by calling the CLI 🔨:
$ npx react-ryo-cli update-scripts --cli=<your-cli-package>
Use argument
--extend
to include extra scripts.
📦 react-app
┣ 📁 src
┣ 📁 public
┣ 📜 README.md
┣ 📜 yarn.lock
┣ 📜 .gitignore
┣ 📜 package.json
+ ┣ 📜 craco.config.js
+ ┗ 📜 allowed-files.json
If provided CLI arguments are not enough, you can use the API to further customize your CLI package.
⛔️ Notice the shebang, without it, your CLI entry-point will not be executable.
#!/usr/bin/env node
require('react-ryo-cli').spawnCli()
noOverride[Bool]
- Lock Craco configuration from end-consumers.
noExtend[Bool]
- Opt-out of default Craco configuration.
outputPath[String]
- Change Webpack output path (Default:'build'
).
withBabelPolyfill[Bool]
- Toggle Babel Polyfill support (Default:false
). Seebabel-polyfill
for details.
withEnzyme[Bool]
- Toggle Enzyme support (Default:false
).
withSignature[Bool]
- Toggle CLI signature (Default:true
).
withStyledComponents[Bool]
- Togglestyled-Components
support for Jest (Default:false
).
signature[String]
- Set CLI name (e.g.: "-react-cli").
signatureGradient[Array]
- Set your own gradient. Seegradient-string
API. This option takes precedence oversignatureTheme
.
signatureTheme[String]
- Select a predefined theme from the list below.
A few helper methods are provided to ease with the configuration of Craco. Import like so:
import { isStart, isBuild /* etc' */ } from 'react-ryo-cli'
isStart
- Test whether current script is astart
script.
isBuild
- Test whether current script is abuild
script.
isTest
- Test whether current script is atest
script.
getParentArgv
- Get parent processargv
.
getCliOptions
- Get CLI options passed tospawnCli
.
getEnvironmentVariables
- Get all environment variables defined byreact-ryo-cli
. Alias:getEnvVars
.
Craco allows you to define a custom location for its craco.config.js
however, it looks for the file under current working directory only, which means it can only be placed under the end consumer project, which is less than ideal. Without custom location support (outside the end consumer project), it is not possible to support Babel
with Jest
.
In attempt to circumvent this issue, you can setup your craco.config.js
with a condition to exclude Babel
configuration when testing. See example:
import { isBuild } from 'react-ryo-cli'
module.exports = {
...(isBuild() && {
babel: {
plugins: ['lodash']
}
})
}
Babel Lodash
plugin is used to optimize a production build, which makes it irrelevant for testing. Therefore, it can be excluded safely when testing. Tip: conditional destructuring is quite useful in this case. Read more about it here.
Once ready, you should publish your custom CLI to your organization and then apply a style-guide that dictates using the CLI for every React application. When all consumers use the same tool, it makes things a lot easier to manage and control.
Just a quick preview of what to expect. Excuse my PowerShell. 😄
Feel free to submit issues and pull requests. Search existing issues before starting a new one. 🙌