Skip to content

Latest commit

 

History

History
288 lines (184 loc) · 12.2 KB

README.md

File metadata and controls

288 lines (184 loc) · 12.2 KB

React Ryo CLI

React Ryo CLI

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.

⚠️ Work In Progress Notice

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'.

Usage

Execute the following command to create a boilerplate for your own CLI package.

$ npx react-ryo-cli init

Or add to an existing package:

Using NPM:

$ npm install react-ryo-cli

Using Yarn:

$ yarn add react-ryo-cli

Configuration

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.

Who Is It For

This package is mainly targeted at UI infrastructure teams, architects, leads and anyone who maintains several React applications across their organization.

Why

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.

What You Get

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.

3-Way Merge Craco Configuration

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

Global Imports

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.

How to use

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.

Consumer Apps

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",
}

Available Scripts

Out of the box, every react-scripts script will work except for eject, as ejecting defeats the purpose of having a custom CLI.

Extra Scripts

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.

Configuration files placement in file structure (e.g. with default CRA boilerplate)

 📦 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.

spawnCli([, options])

⛔️ Notice the shebang, without it, your CLI entry-point will not be executable.

#!/usr/bin/env node

require('react-ryo-cli').spawnCli()

spawnCli Options

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). See babel-polyfill for details.

withEnzyme[Bool] - Toggle Enzyme support (Default: false).

withSignature[Bool] - Toggle CLI signature (Default: true).

withStyledComponents[Bool] - Toggle styled-Components support for Jest (Default: false).

signature[String] - Set CLI name (e.g.: "-react-cli").

signatureGradient[Array] - Set your own gradient. See gradient-string API. This option takes precedence over signatureTheme.

signatureTheme[String] - Select a predefined theme from the list below.

Gradient Themes

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 a start script.

isBuild - Test whether current script is a build script.

isTest - Test whether current script is a test script.

getParentArgv - Get parent process argv.

getCliOptions - Get CLI options passed to spawnCli.

getEnvironmentVariables - Get all environment variables defined by react-ryo-cli. Alias: getEnvVars.

⚠️ Known Limitations

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.

Possible Workarounds

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.

🚀 Publish Custom CLI to Organization

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.

📹 Preview

Just a quick preview of what to expect. Excuse my PowerShell. 😄

Preview

Contributing

Feel free to submit issues and pull requests. Search existing issues before starting a new one. 🙌

License

MIT