nx/docs/react/migration/migration-cra.md
2021-09-08 15:02:37 -04:00

290 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Migrating a Create-React-App project into an Nx Workspace
Create-React-App (CRA) is the most widely used tool for creating, building and testing a React app. This guide will show you how move an app generated with CRA into an Nx workspace. Once the migration process is complete, you'll be able to take advantage of all of Nx's features without needing to completely recreate your build process.
You can either use a CLI tool to migrate your app automatically, or you can follow the steps described below to do the migration manually.
## Using a tool that will do it for you
You can use the [`cra-to-nx`](https://www.npmjs.com/package/cra-to-nx) tool, that will run the following steps for you, and will turn your Create-React-App (CRA) project into an Nx workspace.
Just `cd` into your Create-React-App (CRA) project and run the following command:
```bash
npx cra-to-nx
```
Then just sit back and wait. After a while, take advantage of the [full magic of Nx](https://nx.dev/latest/react/getting-started/intro). Start from [the commands mentioned in this article](https://nx.dev/latest/react/migration/migration-cra#try-nx).
**Note:** The command will fail if you try execute it and you have uncommitted changes in your repository. Commit any local changes, and then try to run the command.
## Doing the migration manually
In this article, youll learn how to:
- Create an Nx workspace for a React application
- Migrate a React application into your Nx workspace
- Convert CRA scripts for use in Nx
- Create a library and use it in your application
For this example, youll be migrating the default CRA typescript template app into an Nx workspace. This is the code that is generated when you run `yarn create react-app webapp --template typescript`.
There is also a [repo](https://github.com/nrwl/migrate-cra-to-nx) that shows the finished result of this guide and for each step a [diff](https://github.com/nrwl/migrate-cra-to-nx/commits/stepbystep) will be provided to see the exact code changes that occur for that step.
### 1. Create your workspace
To start migrating your app, create an Nx workspace:
```bash
npx create-nx-workspace acme --appName=webapp --preset=react --style=css --nx-cloud
```
**Note:** Replace `acme` with your organization's npm scope. This will be used when importing workspace projects. You can also replace `webapp` with a different name -- you can have more than one app in an Nx workspace.
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/0e1c6375b7ea4b7f3723c47cfb8cbf99a30ebbe6)
### 2. Add npm packages to your workspace to support CRA
We'll need to add a few dependencies to the Nx workspace that are needed to allow CRA to function.
```bash
yarn add --dev react-scripts @testing-library/jest-dom eslint-config-react-app react-app-rewired
```
**Note:** The `react-app-rewired` package allows us to customize the webpack config without ejecting.
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/31fa9a327a939abe0fa420130760bde974b2f6fe)
### 3. Replace code generated by Nx with the CRA app
The source code for each app in an Nx workspace should be contained within the folder of a generated app. The `create-nx-workspace` command from step 1 created an app folder at `apps/webapp` that we can use to contain the CRA app. Delete the existing contents and copy over the CRA app code.
```bash
rm -rf apps/webapp/* apps/webapp/{.babelrc,.browserslistrc}
cp -r /path/to/cra-app/{README.md,package.json,tsconfig.json,src,public} apps/webapp
```
Replace `/path/to/cra-app` with the actual path to your CRA app on your machine.
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/a8ad934998949a760e5b62782689683cb469dd7c)
### 4. Add CRA commands to workspace.json
Run the following terminal commands to set up the CRA commands in `workspace.json`. `cwd` specifies the directory the command should be executed from and `outputs` lets Nx know which files are modified when the command is executed.
```bash
nx g @nrwl/workspace:run-commands serve \
--project webapp \
--command "node ../../node_modules/.bin/react-app-rewired start" \
--cwd "apps/webapp"
nx g @nrwl/workspace:run-commands build \
--project webapp \
--command "node ../../node_modules/.bin/react-app-rewired build" \
--cwd "apps/webapp" \
--outputs "dist/apps/webapp"
nx g @nrwl/workspace:run-commands lint \
--project webapp \
--command "node ../../node_modules/.bin/eslint src/**/*.tsx src/**/*.ts" \
--cwd "apps/webapp"
nx g @nrwl/workspace:run-commands test \
--project webapp \
--command "node ../../node_modules/.bin/react-app-rewired test --watchAll=false" \
--cwd "apps/webapp"
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/009266330cc0c158372c0ae527cdd3dc66a43d13)
### 5. Add outputs to your app's build target in workspace.json
Open your `workspace.json` file and add the following things:
1. In `projects.webapp.targets.build.options` add a new entry called `outputPath` with the value `dist/apps/webapp`:
```json
// workspace.json
{
...
"projects": {
"webapp": {
...
"targets": {
"build": {
...
"options": {
...
"outputPath": "dist/apps/webapp"
}
},
```
2. In the `projects.webapp.targets.build.outputs` array add the value `"{options.outputPath}"`:
```json
// workspace.json
{
...
"projects": {
"webapp": {
...
"targets": {
"build": {
...
"outputs": [
"{options.outputPath}"
],
...
},
```
### 6. Customize webpack
The `react-app-wired` script allows you to customize the webpack config of CRA by creating `apps/webapp/config-overrides.js`. Inline comments explain what each section is doing:
```javascript
const path = require('path');
const TsConfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
module.exports = {
webpack: (config) => {
// Remove guard against importing modules outside of `src`.
// Needed for workspace projects.
config.resolve.plugins = config.resolve.plugins.filter(
(plugin) => !(plugin instanceof ModuleScopePlugin)
);
// Add support for importing workspace projects.
config.resolve.plugins.push(
new TsConfigPathsPlugin({
configFile: path.resolve(__dirname, 'tsconfig.json'),
extensions: ['.ts', '.tsx', '.js', '.jsx'],
mainFields: ['module', 'main'],
})
);
// Replace include option for babel loader with exclude
// so babel will handle workspace projects as well.
config.module.rules.forEach((r) => {
if (r.oneOf) {
const babelLoader = r.oneOf.find(
(rr) => rr.loader.indexOf('babel-loader') !== -1
);
babelLoader.exclude = /node_modules/;
delete babelLoader.include;
}
});
return config;
},
paths: (paths) => {
// Rewrite dist folder to where Nx expects it to be.
paths.appBuild = path.resolve(__dirname, '../../dist/apps/webapp');
return paths;
},
jest: (config) => {
config.resolver = '@nrwl/jest/plugins/resolver';
return config;
},
};
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/5e514e0708365d2373a73c2828936eba594789b5)
### 7. Extend the app's tsconfig.json from the base
Modify `apps/webapp/tsconfig.json` to extend the root `tsconfig.base.json`. This is primarily to pickup the typescript aliases from the root tsconfig file.
```json
{
"extends": "../../tsconfig.base.json",
...
}
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/49c515ad8a497c347b1c0292d7fde24bf4d0807c)
### 8. Add tsconfig files for jest and eslint
It's helpful to have separate `tsconfig.json` files for testing and linting. In this instance, the actual typescript settings are identical to the base config, so these tsconfig files will extend the base without modifying any values.
```bash
echo '{ "extends": "./tsconfig.json" }' > apps/webapp/tsconfig.base.json
echo '{ "extends": "./tsconfig.json" }' > apps/webapp/tsconfig.spec.json
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/a70a545d9574bbc300b0a8ace123f75313e9d869)
### 9. Skip CRA preflight check since Nx manages the monorepo.
CRA checks to make sure there are no incompatible dependencies before any scripts run, but the `@nrwl/react` plugin serves the same purpose and requires slightly different versions in order to function correctly in an Nx workspace. Setting this environment variable disables CRA's check.
```bash
echo "SKIP_PREFLIGHT_CHECK=true" > .env
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/cbff423fab73d967bb21d54f2188d77166bd919c)
### 10. Add all node_modules to .gitignore
An `apps/webapp/node_modules` folder will be generated to hold some cache values when a build is run. This cache shouldn't be committed to git, so we tell git to ignore any `node_modules` folder.
```bash
echo "node_modules" >> .gitignore
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/9c02fcda2f39cf3b29ceab75d0c519b9b1b333ba)
## Try Nx
### 1. Try the commands
The following commands are now available for you to try.
```bash
nx serve webapp
nx build webapp
nx lint webapp
nx test webapp
```
The `serve` command will automatically update when code changes, but needs to be restarted if you add a whole new library to your workspace.
`build`, `lint`, and `test` are set up to automatically cache their results. Subsequent runs of `nx build webapp` (without changing any code) should only take a couple seconds.
(No code changes for this step.)
### 2. Create a library
Nx makes it very easy to create isolated collections of reusable code in libraries. Running this script will create a library named `ui-button`.
```bash
nx generate lib ui-button
```
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/d8b0e3ac2b8ca10ff6b24ccfdecc637407a2ff2d)
### 3. Use the library
The new library can be used in your app like by adding this code to `App.tsx`:
```typescriptx
//...
import { UiButton } from '@acme/ui-button';
//...
<UiButton onClick={learnMore}>Learn React</UiButton>;
//...
```
The `@acme/ui-button` path alias is defined in the root `tsconfig.base.json` file.
[View the code changes](https://github.com/nrwl/migrate-cra-to-nx/commit/cfb1d6170c72cfd9355d16fefc045527683fc604)
## Summary
- Create-React-App projects can be migrated into an Nx workspace using existing build and serve processes
- `react-app-wired` allows you to continue using CRA and modify the webpack configuration
- Caching is automatically enabled as part of the migration