Migrating from one framework to another can sometimes be a laborious experience, especially if you have a chunk of functionality that needs to be used in both applications during the migration process.
With a large codebase it may take a while to complete an incremental migration. Monorepos allow you to move portions of your application piece-by-piece, and continue to deploy the application under one domain and from a single code repository.
In this guide you will deploy a monorepo using Yarn workspaces and the following components:
- A
create-react-app
application - A Next.js application
- A common library containing a utility function shared between each application
Before diving in, let's look at the monorepo structure we will create:
apps/ frontend/ nextapp/packages/ site-info/
Each of the 2 folders in apps
will be Yarn workspaces and any folder in the packages
folder will also be a workspace. Each workspace will have its own package.json
file with dependencies and everything will be installed and linked in the root node_modules
when the yarn
command is run. For the purpose of this guide, the term workspace will be used to describe each of these folders.
- Set up the monorepo root with Yarn
- Create a workspace for a Create React App application
- Create a workspace for a Next.js application
- Create a shared library workspace with a utility function
- Use the function inside both applications
- Connect all the pieces with Yarn workspaces
- Test the monorepo locally
- Deploy to Vercel
- Configure the Ignored Build Step on Vercel
README.md
file to deploy.Create your monorepo folder from the command line and initialize it.
mkdir yarn-monorepocd yarn-monorepoyarn init
Choose all the default values for each prompt, except for private
which you should mark as true
. The default is false
and Yarn workspaces only work with private projects. This will create a package.json
file that looks like this:
{ "name": "yarn-monorepo", "version": "1.0.0", "main": "index.js", "license": "MIT", "private": true}
Create the apps
folder to contain the workspaces for all applications.
mkdir appscd apps
Create the frontend
workspace by running the following command inside yarn-monorepo/apps
:
yarn create react-app frontend
This creates a create-react-app
application inside the frontend
folder.
From the folder, yarn-monorepo/apps
, run:
yarn create next-app nextapp
This creates a Next.js application inside the nextapp
folder.
Create a new packages
directory for code that will be shared within the monorepo. After that, create a new site-info
folder in the packages
directory and initialize it with yarn
. You can create any number of packages here to share code amongst multiple applications.
mkdir packagescd packagesmkdir site-infocd site-infoyarn init
You will now create a function that you can use in both the create-react-app
and the Next.js applications. This function will output the site title and subtitle.
Create an index.js
file inside yarn-monorepo/packages/site-info
with the following content:
const PROJECT = { title: 'Site Title', subtitle: 'My great monorepo',};
export function getSiteInfo() { return { title: PROJECT.title, subtitle: PROJECT.subtitle };}
Replace the content of yarn-monorepo/apps/nextapp/pages/index.js
with:
import Head from 'next/head';import styles from '../styles/Home.module.css';
// Import the shared function into the Next.js applicationimport { getSiteInfo } from 'site-info';
export default function Home() { let siteInfo = getSiteInfo(); //Define a variable to get the values return ( <div className={styles.container}> <Head> <title>{siteInfo.title}</title> <meta name="description" content="Generated by create next app" /> <link rel="icon" href="/favicon.ico" /> </Head> {/*Output the site title and subtitle to the screen*/} <main className={styles.main}> <h1 className={styles.title}>Welcome to {siteInfo.title}</h1> <p className={styles.description}>{siteInfo.subtitle}</p> </main> </div> );}
Replace the content of the yarn-monorepo/apps/frontend/src/App.js
file with:
import './App.css';
// Import the shared function into the `create-react-app` applicationimport { getSiteInfo } from 'site-info';
export default function App() { //Define a variable to get the values let siteInfo = getSiteInfo(); return ( <div className="App"> {/*Output the site title and subtitle to the screen*/} <header className="App-header"> <h1>{siteInfo.title}</h1> <p>{siteInfo.subtitle}</p> </header> </div> );}
Add the following to the package.json
file in the root of yarn-monorepo
to tell Yarn about your workspaces:
"workspaces": [ "apps/*", "packages/*"]
From the repository root directory, yarn-monorepo
, run the following in order to install and connect all packages:
yarn
Add the following content to the package.json
file at the root of yarn-monorepo
:
"scripts": { "start": "yarn --cwd apps/frontend start", "next": "yarn --cwd apps/nextapp dev", "dev": "npm-run-all --parallel start next"}
Add the npm-run-all
development dependency by running:
yarn add --dev -W npm-run-all
Run the following at the root of yarn-monorepo
:
yarn
npm-run-all
so that you can run multiple projects in parallel locally. This is not needed in production.Then, run the following command to start both the frontend
and the nextapp
applications locally:
yarn dev
npm-run-all --parallel start next
which runs yarn --cwd frontend start
(create-react-app
application) and yarn --cwd nextapp dev
(Next.js application) at the same time. You can now browse to http://localhost:3000
and http://localhost:3001
to see each application being served separately from the same repository.You will now link a Vercel Project to each frontend site that you would like to have a Deployment for. In this case, it will be for:
- the
frontend
folder - the
nextapp
folder
Let's deploy by using git
.
First we need to remove the git
repository from the frontend
and nextapp
folders, as this comes by default when setting up those frameworks and with a monorepo you only need one repository for all the workspaces. Run the following command in both the yarn-monorepo/frontend
and yarn-monorepo/nextapp
folders:
rm -rf .git
Set up git
from the root yarn-monorepo
by running:
git init
Add a .gitignore
file at the root:
touch .gitignore
Paste the following content:
node_modules
Inside your Git hosting provider account that is connected to Vercel, create a git
repository.
Connect it to your yarn-monorepo
folder using by running git remote add origin [yourGitRepoURL]
in the root folder and push your changes:
git checkout -b maingit add .git commit -m "first commit"git push origin main
Deploy both applications to Vercel from this same repository by creating a new Vercel Project with Git twice and selecting the repository from the Import Git Repository section. Use the following configuration for each Vercel Project:
- For the
apps/frontend create-react-app
application, choose Create React App as the framework and apps/frontend as the root directory - For the
apps/nextapp Next.js
application, choose Next.js as the framework and apps/nextapp as the root directory
Once each Project is deployed, you will see 2 sites that look like the following:
Since you have 2 Vercel Projects connected to the same repository, a git
push with a change to any part of the repository will cause a Deployment to be triggered in both Projects.
It would be better for a Deployment to be triggered in the create-react-app
Project only when a change happens in apps/frontend
and similarly for the Nextjs Project, when a change happens in apps/nextapp
. This is possible with Vercel by configuring the Ignored Build Step option inside the Git section of the Project Settings.
For each Project, set the Ignored Build Step to git diff HEAD^ HEAD --quiet .
and click Save.
The reason why you set the directory that you would like this command to return true
on to .
, referring to the root folder, is because you have configured the root of the Project to be the application's folder such as apps/frontend
or apps/nextapp
.
In this guide, you completed the following tasks:
- Created a monorepo with a workspace for your applications under
apps
and a workspace for your shared code underpackages
- Deployed the monorepo on Vercel as 2 Projects with their own Deployment URL
- Configured the Ignored Build Step setting on each Project so that Deployments are triggered in each Project only when changes in the Project's folder happen
To learn more, please review the following links: