cra-to-next
Migrate a React application created with CRA to Next.js
Example
# This plan was created using the guide from https://nextjs.org/docs/app/building-your-application/upgrading/from-create-react-app
constants:
cleanup_files:
- src/index.tsx
- src/index.ts
- src/index.jsx
- src/index.js
- public/index.html
- src/reportWebVitals
setup:
# Make sure node_modules is in .gitignore or else all of the node_modules dependencies will get added to the commit
- name: edit_file
arguments:
path_to_file: .gitignore
edit_prompt: |
this is a .gitignore file. Please add node_modules to the list
- name: run_terminal_command
arguments:
command: npm install next@latest
- name: run_terminal_command
arguments:
command: npm install postcss autoprefixer
steps:
# Step 2: create Next.js configuration file
- name: Create Next.js configuration file
tools:
- name: create_file
arguments:
path_to_file: next.config.mjs
file_contents: |
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './dist', // Changes the build output directory to `./dist/`.
}
export default nextConfig
# Step 3: update the tsconfig.json file
- name: Update the tsconfig.json file
tools:
- name: edit_file
arguments:
path_to_file: tsconfig.json
edit_prompt: |
This is a tsconfig.json file. Update it with the following configurations:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": ".",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"strictNullChecks": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"./dist/types/**/*.ts"
],
"exclude": ["node_modules"]
}
# Steps 4 and 5: create root layout
- name: Create root layout
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.css$'
path_to_directory: src
returns: css_files
- name: find_content_in_file_with_ai
arguments:
path_to_file: public/index.html
find_context_prompt: |
find the title and description meta data and return the values in the following format:
{
"title": <title>
"description": <description>
}
returns: index_meta_data
- name: create_file_with_ai
arguments:
path_to_file: app/layout.tsx
create_content_prompt: |
start with the following Next root layout:
```
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'React App',
description: 'Web site created with Next.js.',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
```
Add imports for the following CSS files:
{{ css_files }}
Update the Metadata object with the following information:
{{ index_meta_data }}
#Step 6: create postcss.config.js file
- name: Create postcss.config.js file
tools:
- name: create_file
arguments:
path_to_file: postcss.config.js
file_contents: |
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
#Step 7: create the entry point files
- name: Create the entry point files
tools:
# create server side entry point file
- name: create_file
arguments:
path_to_file: app/[[...slug]]/page.tsx
file_contents: |
import '../../index.css'
import { ClientOnly } from './client'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return <ClientOnly />
}
# create client side entry point file
- name: create_file
arguments:
path_to_file: app/[[...slug]]/client.tsx
file_contents: |
'use client'
import React from 'react'
import dynamic from 'next/dynamic'
const App = dynamic(() => import('../../App'), { ssr: false })
export function ClientOnly() {
return <App />
}
# Step 8: update static image imports
- name: Update static image imports
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.(tsx|ts|jsx|js)$'
returns: react_files
- name: async_each
items: '{{ react_files }}'
each_item:
item_name: react_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ react_file }}'
edit_prompt: |
If this is a JSX or TSX React file, then make the following changes. Otherwise, do NOT make any changes to this file.
If you see any image imports like the following
```
import logo from '/logo.png'
```
Please update the import path to be a relative path given that this file path is `{{ react_file }}` and the path to the public directory is `/public`
```
import logo from '../public/logo.png'
```
If you see any image tags that use the image object from an import like this:
```
<img src={logo} />
```
Please update the src to use the image object "src" property like this:
```
<img src={logo.src} />
```
# Step 9: update environment variables
- name: Update environment variables
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.env$'
returns: env_files
- name: async_each
items: '{{ env_files }}'
each_item:
item_name: env_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ env_file }}'
edit_prompt: |
Change all environment variables with the REACT_APP_ prefix to NEXT_PUBLIC_
# Step 10: update scripts in package.json
- name: Update scripts in package.json
tools:
- name: edit_file
arguments:
path_to_file: package.json
edit_prompt: |
this is a package.json file for a CRA application. We are migrating the application to Next.js. Please add the following scripts:
```
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
```
- name: edit_file
arguments:
path_to_file: .gitignore
edit_prompt: |
this is a .gitignore file for a CRA application. We are migrating the application to Next.js. Please add the following ignores:
```
# ...
.next
next-env.d.ts
dist
```
# Step 11: cleanup
- name: Cleanup
tools:
# remove CRA specific files
- name: async_each
items: '{{ cleanup_files }}'
each_item:
item_name: cleanup_file
tools:
- name: delete_file_or_folder
arguments:
path_to_target: '{{ cleanup_file }}'
# remove CRA specific dependencies
- name: run_terminal_command
arguments:
command: npm uninstall react-scripts
Last updated