Rescripts
💥 Use the latest react-scripts with custom configurations for Babel, ESLint, TSLint, Webpack,... ∞
Install / Use
/learn @harrysolovay/RescriptsREADME
Take control of your create-react-app project configurations. No ejecting, no custom react-scripts fork, no limitations.
Highlights
-
🎯 create the perfect config with minimal effort
-
🎩 take advantage of cutting-edge software that hasn't made its way into CRA
-
🥳 draw from a library of open-source "rescripts"
-
👽 compatibility with "rewires" designed for react-app-rewired
Guide
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->- Background
- Installation
- Basic Usage
- Advanced Usage
- Rescript Structure
- Rescript SDK
- Middleware
- Rescript Library
- Miscellaneous
- Acknowledgements
Background
CRA (create-react-app) provides a first-class React developer experience. For building single-page web apps, it's not only the fastest bootstrap––it's also the most carefully-curated, well-supported, and feature-fledged. There is a downside, however: in an effort to create stability and simplicity for beginners, its creators excluded many configuration options and newer technologies (such as Babel transformations based on early-stage TC39 proposals). CRA comes with an "eject" script which––once irreversibly run––allows customization of the "start", "build", and "test" scripts, along with their corresponding configurations. While this does allow you some DX freedom, it isn't always preferable; ejection makes it impossible to upgrade to new versions of react-scripts, and it exposes a lot of tedious, knarly-lookin' code. Rescripts is for developers who don't want to eject or worry about configuration, but still want to use cutting-edge tools.
Tim Arney's react-app-rewired was the first project to successfully tackle this problem. It offered a solution that led to many "rewires" (community-made plugins for simpler setup). But––when CRA 2.0 came around––there were some breaking changes. Not to mention, the react-app-rewired DX was something to be further simplified.
Rescripts tackles this same probem for CRA 2.0+ with several key DX differences. First off, it was designed to be more of a focal point for all non-standard configuration. The underlaying loader can handle deeply nested "rescripts" (conceptually similar to babel plugins), all of which can modify any CRA process. The tools used to transform configuration are more robust and flexible than its predecessor's (@rescripts/utilities), and should weather most updates. The API also exposes a middleware entry, so that you can track your configurations as they are transformed. It should also be noted that Rescripts is compatible with many Webpack rewires built for react-app-rewired.
If you like this framework, please tweet at @gaearon requesting an "everything-i-did-not-include" rescript!
Installation
Install @rescripts/cli as a dev dependency:
npm i -D @rescripts/cli
react-scripts@^2.1.2 requires you be using at least @rescripts/utilities^0.0.4 and @rescripts/cli^0.0.7
Install the rescript(s) you wish to use:
npm i -D @rescripts/rescript-env
@rescripts/rescript-env scans your
package.json& project root for Babel, ESLint and TSLint configuration files. If present, these configurations will override the CRA defaults.
Basic Usage
1) Replace react-scripts calls with rescripts calls
package.json
{
"name": "built-with-rescripts",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.6.1",
"react-dom": "^16.6.1",
"react-scripts": "2.1.1"
}
"devDependencies": {
"@rescripts/cli": "^0.0.11",
"@rescripts/rescript-env": "^0.0.10"
}
"scripts": {
- "start": "react-scripts start",
+ "start": "rescripts start",
- "build": "react-scripts build",
+ "build": "rescripts build",
- "test": "react-scripts test",
+ "test": "rescripts test",
- "eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
2) Define a 'rescripts' field and specify which to use
package.json
{
"name": "built-with-rescripts",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.6.1",
"react-dom": "^16.6.1",
"react-scripts": "2.1.1"
}
"devDependencies": {
"@rescripts/cli": "^0.1.0"
}
"scripts": {
"start": "rescripts start",
"build": "rescripts build",
"test": "rescripts test"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
+ "rescripts": [
+ "env"
+ ]
}
You could also––instead of placing this in your package.json––specify your "root rescript" in a root-level .rescriptsrc file (with whatever convention you prefer: .js, .json, or no extension.)
3) Use the newly-enabled feature(s)
In the case of @rescripts/rescript-env, you will now be able to use custom Babel, ESLint and TSLint configurations. Use any of the following conventions:
Babel: place config inside of a root-level .babelrc, .babelrc.js, .babelrc.json, or babel.config.js file, or inside of the babel field of your package.json
ESLint: place config inside of a root-level.eslintrc, .eslintrc.js, .eslintrc.json, or eslint.config.js file, or inside of the eslintConfig field of your package.json
TSLint: place config inside of a root-leveltslint.js or tslint.json file
4) Good practice with the env rescript
@rescripts/rescript-env actually installs 3 rescripts:
@rescripts/rescript-use-babel-config@rescripts/rescript-use-eslint-config@rescripts/rescript-use-tslint-config
For an incrementally faster boot time, use these independently and actually specify their configurations. Aka...
.rescriptsrc
module.exports = [
['use-babel-config', '.babel.json'],
['use-tslint-config', 'tslint.json'],
]
Advanced Usage
Your root rescript should be an array of other rescripts. Some rescripts take in options and/or other parameters. Some do not. Some contain functions that transform your webpack config. Some contain transformations for any combination of processes (webpack, devServer and jest). Consider the following:
In this example, the root rescript makes reference to @rescripts/rescript-env. This rescript takes in no arguments, which means that it has to scan your project at every run.
module.exports = ['env']
Alternatively, you could use @rescripts/rescript-use-babel-config and @rescripts/rescript-use-eslint-config (or @rescripts/rescript-use-tslint-config if you prefer TypeScript):
module.exports = [
['use-babel-config', '.babelrc'],
['use-eslint-config', '.eslintrc'],
]
This example illustrates how arguments can be passed to a rescript by wrapping its reference inside of another array and adding the arguments as subsequent elements.
The eventual goal of Rescripts is to provide a single, simple interface for deep customizations:
.rescriptsrc.js
module.exports = [
[
'use-babel-config',
{
presets: ['react-app'],
plugins: [
'react-require',
[
'module-resolver',
{
root: '.',
alias: {
'~': './src',
},
},
],
],
},
],
[
'use-eslint-config',
{
extends: ['react-app'],
plugins: ['ramda'],
rules: {
'ramda/compose-pipe-style': 'error',
'react/react-in-jsx-scope': 0,
},
},
],
]
Rescript Structure
Rescripts transform the default configurations used by the three main processes of CRA (webpack, its developement server, and test-running via Jest). Rescripts can do much more though, such as writing logs, caching files, commiting changes and triggering other processes.
A rescript can be...
<details> <summary>an array of other rescripts</summary>child-rescript.js
// define ch
