<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Benoît Hubert</title>
    <description>The latest articles on Forem by Benoît Hubert (@bhubr).</description>
    <link>https://forem.com/bhubr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F151536%2F4d9dc7ee-3fa0-4b21-ab8d-32b8db70e89f.png</url>
      <title>Forem: Benoît Hubert</title>
      <link>https://forem.com/bhubr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bhubr"/>
    <language>en</language>
    <item>
      <title>Express+React Monorepo Setup with Lerna</title>
      <dc:creator>Benoît Hubert</dc:creator>
      <pubDate>Sat, 31 Aug 2019 20:44:58 +0000</pubDate>
      <link>https://forem.com/bhubr/express-react-monorepo-setup-with-lerna-b46</link>
      <guid>https://forem.com/bhubr/express-react-monorepo-setup-with-lerna-b46</guid>
      <description>&lt;p&gt;&lt;em&gt;Initially published on my &lt;a href="https://benoithubert.net/2019/08/express-react-monorepo-setup-with-lerna.html"&gt;blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changelog&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2019-08-31: added a 5th step (backend-frontend connection, serve React build from Express)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Setting up a basic full-stack JavaScript application is not that hard by itself, but becomes complicated and tedious as you throw in more requirements, such as performing linting and testing before allowing commits.&lt;/p&gt;

&lt;p&gt;I've been investigating ways to do it properly, out of personal interest, and with the aim of teaching good practices to my students. Enforcing strict coding conventions tends to annoy them at first, but since we do it at an early stage of their training, it quickly becomes natural for them to follow good practices.&lt;/p&gt;

&lt;p&gt;In this post, we'll describe how to set up an Express + React application repository. First, let's describe our requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;We'll setup a monorepo&lt;/strong&gt;, using &lt;a href="https://lerna.js.org/"&gt;Lerna&lt;/a&gt;. As the name implies, in a monorepo, you keep all your app's "components" in a single repository. Lerna refers to these components as "packages". Among other things, it allows you to run &lt;code&gt;npm&lt;/code&gt; scripts in all the packages with a single command, for tasks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;starting your app (&lt;code&gt;npm start&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;running tests (&lt;code&gt;npm test&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;or any custom script&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In order to improve code quality&lt;/strong&gt;, and prevent anyone from pushing broken code to GitHub, we'll setup Git pre-commit hooks: &lt;a href="https://githooks.com/"&gt;Git hooks&lt;/a&gt; allow you to automatically perform tasks on specific Git events (pre-commit, pre-push, etc.). We'll set them up using &lt;a href="https://github.com/typicode/husky"&gt;Husky&lt;/a&gt;, in order to perform these tasks on pre-commit events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linting with ESLint (Airbnb coding style)&lt;/li&gt;
&lt;li&gt;Testing with Jest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Additionally&lt;/strong&gt;, we'll set up the backend package in order to use ES6 modules, and use &lt;a href="https://yarnpkg.com/"&gt;Yarn&lt;/a&gt; for dependency management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;We'll break down the following into 5 major steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Repo initialization and Lerna setup&lt;/li&gt;
&lt;li&gt;Frontend app setup, with ESLint/Airbnb config&lt;/li&gt;
&lt;li&gt;Backend app setup, with ESLint/Airbnb config&lt;/li&gt;
&lt;li&gt;Git pre-commit hooks setup with Husky&lt;/li&gt;
&lt;li&gt;Connect frontend and backend apps&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Repository initialization
&lt;/h3&gt;

&lt;p&gt;This part is quite straightforward.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Yarn globally if it's not already done: &lt;code&gt;npm i -g yarn&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create an empty directory and &lt;code&gt;cd&lt;/code&gt; into it&lt;/li&gt;
&lt;li&gt;Initialize a Git repo: &lt;code&gt;git init&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Initialize root-level &lt;code&gt;package.json&lt;/code&gt;: &lt;code&gt;yarn init --yes&lt;/code&gt; (modify &lt;code&gt;version&lt;/code&gt; to &lt;code&gt;0.0.1&lt;/code&gt; afterwards)&lt;/li&gt;
&lt;li&gt;Install Lerna and Husky as a dev dependency, at repo root level: &lt;code&gt;yarn add --dev lerna&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create Lerna config: &lt;code&gt;npx lerna init&lt;/code&gt;, modify the version, and add &lt;code&gt;"npmClient": "yarn"&lt;/code&gt; to the generated &lt;code&gt;lerna.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a global &lt;code&gt;.gitignore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write a minimal &lt;code&gt;README.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the content of the initial &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
.DS_Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;lerna.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"npmClient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"packages/*"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's commit that before moving on! You can review this first commit &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/d2e063a8353e600b3673bc3d38e81bfb0bfe69d0"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend app setup with CRA
&lt;/h3&gt;

&lt;p&gt;We're gonna use &lt;a href="https://create-react-app.dev/"&gt;Create React App&lt;/a&gt; to bootstrap the frontend app. You need to install it first: &lt;code&gt;npm i -g create-react-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before getting any further, let's create a branch. We're doing this in order to break down the steps into digestible bits, but will squash-merge intermediate branches at the end of each major step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; setup-frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's generate the frontend app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;packages
create-react-app front
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then remove useless some files from &lt;code&gt;front/src&lt;/code&gt; that we won't use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;front
&lt;span class="nb"&gt;rm &lt;/span&gt;README.md src/index.css src/App.css src/logo.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have to remove the imports from &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;App.js&lt;/code&gt; accordingly, and we'll replace the JSX returned by &lt;code&gt;App&lt;/code&gt; with a simple "Hello World".&lt;/p&gt;

&lt;p&gt;Let's check that the app works, &lt;code&gt;git add&lt;/code&gt; everything and commit after that! Not of much interest since it's mostly auto-generated stuff, but you can review this commit &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/d2e063a8353e600b3673bc3d38e81bfb0bfe69d0"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom ESLint setup
&lt;/h4&gt;

&lt;p&gt;CRA provides a default ESLint setup. It's under the &lt;code&gt;eslintConfig&lt;/code&gt; key of &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "eslintConfig": {
    "extends": "react-app"
  },
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're gonna change this config, in order to use Airbnb's coding style.&lt;/p&gt;

&lt;p&gt;We first initialize a stand-alone ESLint config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eslint &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we setup ESLint with Airbnb coding style, with the following choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How would you like to use ESLint? &lt;strong&gt;To check syntax, find problems, and enforce code style&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What type of modules does your project use? &lt;strong&gt;JavaScript modules (import/export)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Which framework does your project use? &lt;strong&gt;React&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Where does your code run? &lt;strong&gt;Browser&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;How would you like to define a style for your project? &lt;strong&gt;Use a popular style guide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Which style guide do you want to follow? &lt;strong&gt;Airbnb (&lt;a href="https://github.com/airbnb/javascript"&gt;https://github.com/airbnb/javascript&lt;/a&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What format do you want your config file to be in? &lt;strong&gt;JSON&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Would you like to install them now with npm? (Y/n) &lt;strong&gt;N&lt;/strong&gt; (we'll install them with Yarn)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copy-paste generated &lt;code&gt;.eslintrc.json&lt;/code&gt;'s content to under the &lt;code&gt;eslintConfig&lt;/code&gt; section of &lt;code&gt;package.json&lt;/code&gt; (that's why we chose JSON),&lt;/li&gt;
&lt;li&gt;delete &lt;code&gt;.eslintrc.json&lt;/code&gt; to avoid redundancy,&lt;/li&gt;
&lt;li&gt;install the deps with Yarn: &lt;code&gt;yarn add --dev eslint@^6.2.2 typescript@latest eslint-plugin-react@^7.14.3 eslint-config-airbnb@latest eslint-plugin-import@^2.18.2 eslint-plugin-jsx-a11y@^6.2.3 eslint-plugin-react-hooks@^1.7.0&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;test the config with &lt;code&gt;npx eslint src/&lt;/code&gt;, which reports many errors - most of them due to the &lt;code&gt;src/serviceWorker.js&lt;/code&gt; file,&lt;/li&gt;
&lt;li&gt;create a &lt;code&gt;.eslintignore&lt;/code&gt; file to ignore the &lt;code&gt;src/serviceWorker.js&lt;/code&gt; file (which we won't modify anyway),&lt;/li&gt;
&lt;li&gt;re-run &lt;code&gt;npx eslint src/&lt;/code&gt;, which complains about JSX in &lt;code&gt;.js&lt;/code&gt; files, and &lt;code&gt;it&lt;/code&gt; being not defined (in &lt;code&gt;App.test.js&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rename the &lt;code&gt;.js&lt;/code&gt; files to give them the &lt;code&gt;.jsx&lt;/code&gt; extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd src&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git mv App.js App.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git mv App.test.js App.test.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git mv index.js index.jsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;run the linter again - getting a weird &lt;code&gt;All files matched by 'src' are ignored.&lt;/code&gt; message, which we can fix by running ESLint with &lt;code&gt;npx eslint src/**/*.js*&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fix the &lt;code&gt;'it' is not defined&lt;/code&gt; error by adding &lt;code&gt;"jest": true&lt;/code&gt; to &lt;code&gt;env&lt;/code&gt; section in &lt;code&gt;eslintConfig&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;add &lt;code&gt;"lint": "npx eslint --fix src/**/*.js*",&lt;/code&gt; under the &lt;code&gt;scripts&lt;/code&gt; key&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, we can lint our frontend app by simply running &lt;code&gt;yarn lint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's stage and commit that! Find this commit &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/0c719059f9828f1deb77c6753b5c83ae90288fe3"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that, let's squash-merge the &lt;code&gt;front-setup&lt;/code&gt; branch into &lt;code&gt;master&lt;/code&gt; - done via &lt;a href="https://github.com/bhubr/express-react-monorepo/pull/1"&gt;this PR&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend app setup
&lt;/h3&gt;

&lt;p&gt;This step is gonna be a bit more complicated, so again, we're gonna create an intermediate branch, in order to break it down (after having pulled our &lt;code&gt;master&lt;/code&gt; branch).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; setup-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Simple server creation
&lt;/h4&gt;

&lt;p&gt;Get back to the &lt;code&gt;~/packages&lt;/code&gt; folder, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; back/src
&lt;span class="nb"&gt;cd &lt;/span&gt;back
npm init &lt;span class="nt"&gt;--yes&lt;/span&gt;
yarn add express body-parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's edit &lt;code&gt;package.json&lt;/code&gt; and set &lt;code&gt;version&lt;/code&gt; to &lt;code&gt;0.0.1&lt;/code&gt;, and &lt;code&gt;main&lt;/code&gt; to &lt;code&gt;build/index.js&lt;/code&gt;, before we move on.&lt;/p&gt;

&lt;p&gt;Let's also create a &lt;code&gt;.gitignore&lt;/code&gt; files to ignore &lt;code&gt;node_modules&lt;/code&gt;. That's redundant with the root &lt;code&gt;.gitignore&lt;/code&gt; file, but could be useful if we take out the &lt;code&gt;back&lt;/code&gt; package out of this repo, for stand-alone use. Besides, we'll have specific stuff to ignore on the backend side.&lt;/p&gt;

&lt;p&gt;We're gonna create a simple server in &lt;code&gt;src/index.js&lt;/code&gt;, using ES6 import/export syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ERROR: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, unless we use Node 12 with &lt;code&gt;--experimental-modules&lt;/code&gt; flag, running &lt;code&gt;node src/index&lt;/code&gt; fails with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express from 'express';
       ^^^^^^^

SyntaxError: Unexpected identifier
    at Module._compile (internal/modules/cjs/loader.js:723:23)
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I'm not comfortable with using experimental stuff in production, so Babel still seems a more robust option. We'll set it up before committing anything.&lt;/p&gt;

&lt;h4&gt;
  
  
  Babel setup
&lt;/h4&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://babeljs.io/docs/en/next/babel-node.html"&gt;@babel/node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/babel/example-node-server"&gt;Example Node Server with Babel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's install all we need: Babel, and also nodemon to restart our server on every change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; @babel/cli @babel/core @babel/preset-env @babel/node nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@babel/node&lt;/code&gt; will allow us to run ES6 code containing &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; statements. The doc explicitly advises not to use it in production, but the other Babel tools will allow us to generate a build suitable for production use.&lt;/p&gt;

&lt;p&gt;Then create a &lt;code&gt;.babelrc&lt;/code&gt; file containing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"presets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a &lt;code&gt;start&lt;/code&gt; script to &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "scripts": {
    "start": "nodemon --exec ./node_modules/@babel/node/bin/babel-node.js src/index",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start our server using &lt;code&gt;yarn start&lt;/code&gt;. Hurray! Let's stage and commit our whole &lt;code&gt;back&lt;/code&gt; folder (find the commit &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/f54053b91b4a0ef47ba762af74d212a6be88144f"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Build setup
&lt;/h4&gt;

&lt;p&gt;We'll store the production build in the &lt;code&gt;build&lt;/code&gt; folder inside &lt;code&gt;packages/back&lt;/code&gt;. We could name it &lt;code&gt;dist&lt;/code&gt; instead, but I like being consistent with what the CRA build system does.&lt;/p&gt;

&lt;p&gt;Let's create a build (and create the &lt;code&gt;build&lt;/code&gt; folder) with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx babel src &lt;span class="nt"&gt;-d&lt;/span&gt; build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works! We can reference this command as a &lt;code&gt;build&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; for convenience (&lt;code&gt;yarn build&lt;/code&gt;). The build can be run via &lt;code&gt;node build/index&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "scripts": {
    "build": "npx babel src -d build",
    "start": "nodemon --exec ./node_modules/@babel/node/bin/babel-node.js src/index"
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1",
  },
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we're at it, let's add the &lt;code&gt;build&lt;/code&gt; folder to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tests setup
&lt;/h4&gt;

&lt;p&gt;We'll use these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/visionmedia/supertest"&gt;supertest&lt;/a&gt; which will allow testing the Express routes (integration testing)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; jest supertest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then specify &lt;code&gt;jest&lt;/code&gt; as the &lt;code&gt;test&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's also create a &lt;code&gt;test&lt;/code&gt; folder where we'll put our tests. We'll see later on how to organize our test files inside that folder.&lt;/p&gt;

&lt;p&gt;Let's write a first test, &lt;code&gt;app.integration.test.js&lt;/code&gt;, inside that folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test/app.integration.test.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GETs / and should obtain { foo: "bar" }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toMatchInlineSnapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two important things to note here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;we import &lt;code&gt;app&lt;/code&gt; from &lt;code&gt;../src/app&lt;/code&gt;, which doesn't exists. We indeed have to split &lt;code&gt;src/index.js&lt;/code&gt; into two distinct files.&lt;/li&gt;
&lt;li&gt;see the &lt;code&gt;toMatchInlineSnapshot()&lt;/code&gt; call at the end of the test? Jest will automatically fill in the parentheses with the expected return values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's address the first.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;app.js&lt;/code&gt; file will export the Express app, so that it can be imported from both the test file &lt;em&gt;and&lt;/em&gt; the index file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The modified &lt;code&gt;index.js&lt;/code&gt; file will import it and start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ERROR: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We check that &lt;code&gt;yarn start&lt;/code&gt; and &lt;code&gt;yarn build&lt;/code&gt; still function, then try &lt;code&gt;yarn test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For some reason, we get a &lt;code&gt;ReferenceError: regeneratorRuntime is not defined&lt;/code&gt; if we don't configure Babel properly.&lt;/p&gt;

&lt;p&gt;We actually have to rename &lt;code&gt;.babelrc&lt;/code&gt; to &lt;code&gt;babel.config.js&lt;/code&gt;, and modify its content to (see &lt;a href="https://github.com/facebook/jest#using-babel"&gt;Using Babel&lt;/a&gt; in Jest docs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}}]],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solves the problem. Now the test runs but, of course, fails: no routes are defined in the Express app, so we need to add a '/' route in &lt;code&gt;app.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We still get an error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot find module 'prettier' from 'setup_jest_globals.js'

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:259:17)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which brings us back to the &lt;strong&gt;second&lt;/strong&gt; point. In order to automatically modify code in the test, Jest uses &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt;, which ensures consistent formatting. Obviously &lt;code&gt;prettier&lt;/code&gt; is missing here, so let's install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run &lt;code&gt;yarn test&lt;/code&gt; again: it passes. But if we have a look at &lt;code&gt;test/app.integration.test.js&lt;/code&gt;, we see that Prettier applied formatting that isn't consistent with the Airbnb coding style we chose to follow. Fixing that is as easy as creating a &lt;a href="https://prettier.io/docs/en/configuration.html"&gt;Prettier config file&lt;/a&gt;, &lt;code&gt;.prettierrc.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .prettierrc.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;trailingComma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tabWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;semi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;singleQuote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We remove the code that was added by the previous test inside &lt;code&gt;toMatchInlineSnapshot&lt;/code&gt; call's parentheses, and run the test again. This time the formatting is consistent with our coding style.&lt;/p&gt;

&lt;p&gt;We're done with this, let's stage and commit (see &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/b79f5fa27e1a3606ad9548b5567349e615e5e6df"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  ESLint setup
&lt;/h4&gt;

&lt;p&gt;We'll setup ESLint for Node.js with Airbnb style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; eslint
npx eslint &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's answer the questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How would you like to use ESLint? &lt;strong&gt;To check syntax, find problems, and enforce code style&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What type of modules does your project use? &lt;strong&gt;JavaScript modules (import/export)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Which framework does your project use? &lt;strong&gt;None of these&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Does your project use TypeScript? &lt;strong&gt;N&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Where does your code run? &lt;strong&gt;Node&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;How would you like to define a style for your project? &lt;strong&gt;Use a popular style guide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Which style guide do you want to follow? &lt;strong&gt;Airbnb (&lt;a href="https://github.com/airbnb/javascript"&gt;https://github.com/airbnb/javascript&lt;/a&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What format do you want your config file to be in? &lt;strong&gt;JavaScript&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Would you like to install them now with npm? (Y/n) &lt;strong&gt;N&lt;/strong&gt; (again, we'll install them with Yarn)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then install the deps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; eslint-config-airbnb-base@latest eslint@6.2.2 eslint-plugin-import@^2.18.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a &lt;code&gt;"lint": "npx eslint --fix *.js src test *.js",&lt;/code&gt; under &lt;code&gt;scripts&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;yarn lint&lt;/code&gt; for the first time, we get a few errors. We need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the &lt;code&gt;bodyParser&lt;/code&gt; import in &lt;code&gt;app.js&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;jest: true&lt;/code&gt; under &lt;code&gt;env&lt;/code&gt; in &lt;code&gt;.eslintrc.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, we only have the &lt;code&gt;no-console&lt;/code&gt; left, which will be good enough for now (we could setup a proper logger later). Let's save that (&lt;a href="https://github.com/bhubr/express-react-monorepo/commit/c6b7fef0aa7e21b67d880a4e0b0c3de2b275dc2d"&gt;commit&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  We're done (for now)
&lt;/h4&gt;

&lt;p&gt;That step was long! Don't worry, we're almost done!&lt;/p&gt;

&lt;p&gt;Let's squash-merge the &lt;code&gt;setup-backend&lt;/code&gt; branch into &lt;code&gt;master&lt;/code&gt; via a &lt;a href="https://github.com/bhubr/express-react-monorepo/pull/2"&gt;PR&lt;/a&gt;, then pull &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-commit hooks setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Husky install
&lt;/h4&gt;

&lt;p&gt;We're gonna setup pre-commit hooks with Husky, so that linting and tests are carried out on every pre-commit event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; setup-husky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's get back to the repo root and install Husky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; husky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's commit at this point (&lt;a href="https://github.com/bhubr/express-react-monorepo/commit/70133af1fa2187e4630f226d3817e4ba4d30e39d"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;lint-staged&lt;/code&gt; setup
&lt;/h4&gt;

&lt;p&gt;In each of &lt;code&gt;front&lt;/code&gt; and &lt;code&gt;back&lt;/code&gt; packages, we're gonna install &lt;code&gt;lint-staged&lt;/code&gt;, which as the name implies, lints the &lt;em&gt;staged&lt;/em&gt; files before committing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;packages/front
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; lint-staged
&lt;span class="nb"&gt;cd&lt;/span&gt; ../back
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt; of each package, we add a &lt;code&gt;lint-staged&lt;/code&gt; section. &lt;code&gt;back&lt;/code&gt; and &lt;code&gt;front&lt;/code&gt; differ slightly, by the paths to check.&lt;/p&gt;

&lt;p&gt;What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run &lt;code&gt;yarn lint&lt;/code&gt;, which fixes auto-fixable errors, but prevents for going further if a more serious error occurs.&lt;/li&gt;
&lt;li&gt;stage files again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the &lt;code&gt;front&lt;/code&gt; version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
"lint-staged": {
  "src/**/*.js*": [
    "yarn lint",
    "git add"
  ]
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the &lt;code&gt;back&lt;/code&gt; version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
"lint-staged": {
  "**/*.js": [
    "yarn lint",
    "git add"
  ]
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still in &lt;code&gt;package.json&lt;/code&gt;, add a &lt;code&gt;precommit&lt;/code&gt; script (same for &lt;code&gt;back&lt;/code&gt; and &lt;code&gt;front&lt;/code&gt;) to run &lt;code&gt;lint-staged&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "scripts": {
    ...
    "precommit": "lint-staged",
    ...
  }
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;front&lt;/code&gt; and &lt;code&gt;back&lt;/code&gt; packages, we can test this setup by adding errors to &lt;code&gt;App.jsx&lt;/code&gt; and &lt;code&gt;app.js&lt;/code&gt;, respectively (like declaring an unused variable).&lt;/p&gt;

&lt;p&gt;Then we can &lt;code&gt;git add&lt;/code&gt; these files to stage them, then run &lt;code&gt;yarn precommit&lt;/code&gt;, which should trigger an error. After that, we can revert these files to their previous states, and &lt;code&gt;git add&lt;/code&gt; them again.&lt;/p&gt;

&lt;p&gt;At this point, pre-commit scripts are set up, but we need to actually run them on pre-commit events. Let's commit before getting there (&lt;a href="https://github.com/bhubr/express-react-monorepo/commit/3ac3a5ba315f5ea47f86627adb7a2262078306d3"&gt;commit&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Husky setup
&lt;/h4&gt;

&lt;p&gt;Back at the repo root, let's add a &lt;code&gt;husky&lt;/code&gt; section to &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "husky": {
    "hooks": {
      "pre-commit": "npx lerna run --concurrency 1 --stream precommit"
    }
  }
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's worth explaining what this does. On each pre-commit event, the &lt;code&gt;npx lerna run --concurrency 1 --stream precommit&lt;/code&gt; is run.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx lerna run &amp;lt;script&amp;gt;&lt;/code&gt; will run &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; in each of the packages. We add these flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--stream&lt;/code&gt; in order to get console output from the scripts as it's emitted&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--concurrency 1&lt;/code&gt; to run the scripts from each package sequentially.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the pre-commit hooks are configured, and if there are linting errors, we won't be able to commit before fixing them.&lt;/p&gt;

&lt;p&gt;Let's &lt;code&gt;git add&lt;/code&gt; and commit everything (&lt;a href="https://github.com/bhubr/express-react-monorepo/commit/771fc9ad037c2d7fb8b8b19399895f628f59dd8c"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Hold on, we're not done yet, we also want the tests to be run on pre-commit hooks!&lt;/p&gt;

&lt;h4&gt;
  
  
  Trigger tests on pre-commit hooks
&lt;/h4&gt;

&lt;p&gt;We have to update the &lt;code&gt;precommit&lt;/code&gt; script in each packages's &lt;code&gt;package.json&lt;/code&gt;, to run both &lt;code&gt;lint-staged&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...
  "precommit": "lint-staged &amp;amp;&amp;amp; yarn test"
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionnally, we want to prevent tests to running in watch mode in React app (which is the default set by CRA).&lt;br&gt;
This requires amending the &lt;code&gt;test&lt;/code&gt; script, in frontend app's &lt;code&gt;package.json&lt;/code&gt;. See &lt;a href="https://github.com/facebook/create-react-app/issues/1137#issuecomment-279180815"&gt;this comment by Dan Abramov&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We install &lt;code&gt;cross-env&lt;/code&gt; to have a working cross-platform setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; cross-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And update &lt;code&gt;package.json&lt;/code&gt; accordingly, replacing &lt;code&gt;react-scripts test&lt;/code&gt; with &lt;code&gt;cross-env CI=true react-scripts test --env=jsdom&lt;/code&gt; for the &lt;code&gt;test&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;We make both the back-end and front-end tests fail by making dummy changes to the apps.&lt;/p&gt;

&lt;p&gt;For example, in the React app (&lt;code&gt;App.jsx&lt;/code&gt;), let's amend the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;'s content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Express app (&lt;code&gt;app.js&lt;/code&gt;), let's change what's returned by the '/' route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buzz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we stage everything and try to commit. We end up with an error, which is great!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lerna ERR! yarn run precommit exited 1 in 'back'
lerna WARN complete Waiting for 1 child process to exit. CTRL-C to exit immediately.
husky &amp;gt; pre-commit hook failed (add --no-verify to bypass)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After reverting the apps to their working state, we're all set! Let's commit this (&lt;a href="https://github.com/bhubr/express-react-monorepo/commit/9dd7a2ba79bed26c37d6cd2ba575779634ce40cd"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We can conclude this step by squash-merging the &lt;code&gt;setup-husky&lt;/code&gt; branch into &lt;code&gt;master&lt;/code&gt; (&lt;a href="https://github.com/bhubr/express-react-monorepo/pull/3"&gt;PR&lt;/a&gt; and resulting &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/7dd494875e5caf672dab293111f4b6ec0e31b229"&gt;commit on master&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect backend and frontend apps
&lt;/h3&gt;

&lt;p&gt;In this final step, we're gonna setup two additional things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch data from the backend in the React app&lt;/li&gt;
&lt;li&gt;Setup the backend app in order to expose the React build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First let's create a branch to work on this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; setup-back-front-connection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Fetch data from the backend
&lt;/h4&gt;

&lt;p&gt;Let's start with amending the integration test. We'll fetch data from the &lt;code&gt;/api/foo&lt;/code&gt; endpoint instead of &lt;code&gt;/&lt;/code&gt;. We then have to update &lt;code&gt;app.js&lt;/code&gt; accordingly.&lt;/p&gt;

&lt;p&gt;Then let's head to the &lt;code&gt;front&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;First we'll add &lt;code&gt;"proxy": "http://localhost:5000"&lt;/code&gt; to &lt;code&gt;package.json&lt;/code&gt;. Then we'll fetch the &lt;code&gt;/api/foo&lt;/code&gt; endpoint from the &lt;code&gt;App&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Here's the updated &lt;code&gt;App.jsx&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFoo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setFoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setFoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
Server responded with foo:
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, in the root-level &lt;code&gt;package.json&lt;/code&gt;, we add a &lt;code&gt;scripts&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  "scripts": {
    "lint": "lerna run lint --stream",
    "start": "lerna run start --stream"
  },
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we run &lt;code&gt;yarn start&lt;/code&gt;, Lerna will run the &lt;code&gt;start&lt;/code&gt; script in both &lt;code&gt;back&lt;/code&gt; and &lt;code&gt;front&lt;/code&gt; packages, which means we can launch our full-stack app in a single command-line (and a single terminal window!). Same for &lt;code&gt;yarn lint&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Let's &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/8beb687cfa6f52a24505497865d9de456d7ea98a"&gt;commit&lt;/a&gt; this and move on.&lt;/p&gt;

&lt;h4&gt;
  
  
  Serve the React production build
&lt;/h4&gt;

&lt;p&gt;We're gonna have to amend the &lt;code&gt;app.js&lt;/code&gt; file in the &lt;code&gt;back&lt;/code&gt; package, in order to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compute the absolute path of the &lt;code&gt;build&lt;/code&gt; folder, which is right under the &lt;code&gt;front&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;Check whether we are in a production environment or not. If it's the case:

&lt;ul&gt;
&lt;li&gt;Setup the &lt;code&gt;build&lt;/code&gt; folder as a static assets directory&lt;/li&gt;
&lt;li&gt;Create a wildcard route to serve &lt;code&gt;build/index.html&lt;/code&gt; for all unmatched paths&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the updated &lt;code&gt;app.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Check whether we are in production env&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isProd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isProd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Compute the build path and index.html path&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../front/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;indexHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buildPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Setup build path as a static assets path&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buildPath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// Serve index.html on unmatched routes&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indexHtml&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll now build the backend app by running &lt;code&gt;yarn build&lt;/code&gt;, then move to the &lt;code&gt;front&lt;/code&gt; folder and run the same command.&lt;/p&gt;

&lt;p&gt;Then, going back to our &lt;code&gt;back&lt;/code&gt; folder, let's start the app in production mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production node build/index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visiting &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt;, we should see our React app, up and running.&lt;/p&gt;

&lt;p&gt;Let's &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/d7cba4cdb703bfd74f5f45da51a401952c3a43bc"&gt;commit&lt;/a&gt; this.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;A last &lt;a href="https://github.com/bhubr/express-react-monorepo/pull/4"&gt;PR&lt;/a&gt; (resulting &lt;a href="https://github.com/bhubr/express-react-monorepo/commit/2b224ec6871675936fb02a53969c7e93d3d361ad"&gt;commit on master&lt;/a&gt;), and we're done!&lt;br&gt;
Let's tag that commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git tag initial-setup
git push &lt;span class="nt"&gt;--tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Setting all this up is a bit tedious and took me quite some time, even though I'd already done something similar before!&lt;/p&gt;

&lt;p&gt;So if you don't want to spend precious time, feel free to re-use this setup. I suggest you download an &lt;a href="https://github.com/bhubr/express-react-monorepo/archive/initial-setup.tar.gz"&gt;archive&lt;/a&gt; of the &lt;code&gt;initial-setup&lt;/code&gt; release, instead of forking this repo. This can be used as a starting point for your new project.&lt;/p&gt;

&lt;p&gt;I didn't cover every aspect of a project setup, since my focus was more on the ESLint/Jest part. Among the things that we could do to go further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up Prettier&lt;/li&gt;
&lt;li&gt;Set up a database, with or without an ORM&lt;/li&gt;
&lt;li&gt;Set up &lt;code&gt;dotenv&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know if that might be of some interest to you guys!&lt;/p&gt;

&lt;p&gt;Also, I'd like to hear your thoughts and suggestions on this setup: I'm eager to know about anything you're doing differently, and why!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>express</category>
      <category>react</category>
      <category>monorepo</category>
    </item>
  </channel>
</rss>
