<?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>DEV Community: Jerome Choo</title>
    <description>The latest articles on DEV Community by Jerome Choo (@jeromechoo).</description>
    <link>https://dev.to/jeromechoo</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%2F1840118%2Ff8cc37d8-b319-49be-8deb-9ecb09934228.png</url>
      <title>DEV Community: Jerome Choo</title>
      <link>https://dev.to/jeromechoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeromechoo"/>
    <language>en</language>
    <item>
      <title>A Step By Step Guide to Updating Your Legacy Node.js App in 2024 (v10 to v22)</title>
      <dc:creator>Jerome Choo</dc:creator>
      <pubDate>Thu, 25 Jul 2024 18:57:26 +0000</pubDate>
      <link>https://dev.to/jeromechoo/a-step-by-step-guide-to-updating-your-legacy-nodejs-app-in-2024-v10-to-v22-5h4h</link>
      <guid>https://dev.to/jeromechoo/a-step-by-step-guide-to-updating-your-legacy-nodejs-app-in-2024-v10-to-v22-5h4h</guid>
      <description>&lt;p&gt;Here at Diffbot, we enjoy hacking away at fun new app concepts. Not all of them turn out great, but &lt;a href="https://crawly.diffbot.com" rel="noopener noreferrer"&gt;Crawly&lt;/a&gt; was (and still is) a hit. It passively generates around 15% of inbound organic traffic to &lt;a href="https://www.diffbot.com" rel="noopener noreferrer"&gt;Diffbot&lt;/a&gt;. It's a shame the poor thing hasn't been owned or maintained for over 8 years. Frankly, it's a miracle this thing still builds.&lt;/p&gt;

&lt;p&gt;This week, at the unanimous behest of Diffbot support and dev ops, I take up the challenge of getting this little app patched. The good news is that I did in 2 days. The bad news is that it was still a miserable experience, even for a tiny hackathon project. &lt;/p&gt;

&lt;p&gt;In the hopes of helping a fellow dev, I've organized my notes into a step by step guide. I'll point out some places where I got stuck, but in general will try to stick to the things that worked. Because every project is unique, your mileage will vary. But at least you won't be starting with this useless Google search result. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkzcs1xip7vy2luorulo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkzcs1xip7vy2luorulo.png" alt="Google search results for " width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Crawly is Built
&lt;/h2&gt;

&lt;p&gt;Crawly is an Express app built on the bones of &lt;a href="https://github.com/sahat/hackathon-starter" rel="noopener noreferrer"&gt;hackathon-starter&lt;/a&gt;, a boilerplate package for Node apps. Surprisingly, this project is still alive and well maintained in 2024. But there's no guarantee that the project still uses the same dependencies (it doesn't), and there's a likelihood that even more dependencies would be added (there were). So I abandoned any plans to merge the latest in. &lt;/p&gt;

&lt;p&gt;Crawly's main dependencies are &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express@4.13.3&lt;/a&gt;, &lt;a href="https://www.mongodb.com/" rel="noopener noreferrer"&gt;mongodb@3.6.3&lt;/a&gt;, &lt;a href="https://jade-lang.com/reference/" rel="noopener noreferrer"&gt;jade@1.11.0&lt;/a&gt; (templating), &lt;a href="https://www.passportjs.org/" rel="noopener noreferrer"&gt;passport@0.3.2&lt;/a&gt;, and &lt;a href="https://www.npmjs.com/package/request" rel="noopener noreferrer"&gt;request@2.67.0&lt;/a&gt;. It also included mocha and phantomjs for testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="mailto:Bootstrap@3.3.5"&gt;Bootstrap@3.3.5&lt;/a&gt; is vendorized and compiled at build time.&lt;/p&gt;

&lt;p&gt;The app is dockerized for deployment. Running off a node:10 image.&lt;/p&gt;

&lt;p&gt;Some notable omissions — &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No webpack.&lt;/strong&gt; Bundling dependencies was still pretty cutting edge in 2014. Instead, Express middleware compiled dependencies like SCSS to CSS files at run time. (ew)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No tests.&lt;/strong&gt;  There're some assertions here and there. But I'm not surprised. This was a hackathon project after all. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Upgrade Node v10 to v22
&lt;/h2&gt;

&lt;p&gt;The keystone upgrade. We'll switch Node to v22 and reinstall node modules.&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;$ &lt;/span&gt;nvm use 22.5.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete your &lt;code&gt;node_modules&lt;/code&gt; folder, delete &lt;code&gt;package-lock.json&lt;/code&gt;, then run &lt;code&gt;npm i&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr44nvp7qafqy5sbgdjg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr44nvp7qafqy5sbgdjg4.png" alt="A wall of terminal errors, see below for reproduction of the important bits" width="800" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get used to these messages. We're going to see a lot of it. For now, we can ignore all of the deprecation warnings and focus on the errors, specifcally —&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ERR! code 7
npm ERR! path ......./node_modules/kerberos
npm ERR! &lt;span class="nb"&gt;command &lt;/span&gt;failed
npm ERR! &lt;span class="nb"&gt;command &lt;/span&gt;sh- c prebuild-install &lt;span class="o"&gt;||&lt;/span&gt; node-gyp rebuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on here — one of the modules, &lt;code&gt;kerberos&lt;/code&gt;, is prevented from running a prebuild-install step. &lt;/p&gt;

&lt;p&gt;Modules with a pre/post install step will often fail if their expected version of Node is not available. To get past this, we need to update these packages first to a version that does support Node v22.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you're dockerizing your app, pick a node image and use the version of node it uses. See Step 4: Docker up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 2: Update dependencies in package.json
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://www.npmjs.com/package/npm-check-updates" rel="noopener noreferrer"&gt;npm-check-updates&lt;/a&gt;. It works pretty well!&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;$ &lt;/span&gt;npx npm-check-updates &lt;span class="nt"&gt;--format&lt;/span&gt; group
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate an output like this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusb5xg6yru9a3xj4zuyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusb5xg6yru9a3xj4zuyp.png" alt="4 sections of packages in package.json — Patch, Minor, Major, Major version zero" width="800" height="997"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took the easy road and updated them all at once. Who knows? Could work.&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;$ &lt;/span&gt;npx npm-check-updates &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafhxjef60pyynpvlqsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafhxjef60pyynpvlqsp.png" alt="A wall of terminal errors, see below for reproduction of the important bits" width="800" height="892"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I love how useless these deprecation warnings are. Half of them are nested dependencies and it's impossible to identify the parent dependency without successfully installing it. &lt;/p&gt;

&lt;p&gt;It appears we were able to get past the kerberos preinstall error this time. But &lt;code&gt;node-sass&lt;/code&gt; is still failing a post-install build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ERR! code 1
npm ERR! path /Users/jc/Diffbot/diffbot-crawler/node_modules/node-sass
npm ERR! &lt;span class="nb"&gt;command &lt;/span&gt;failed
npm ERR! &lt;span class="nb"&gt;command &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; node scripts/build.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've run into this issue before. &lt;code&gt;node-sass&lt;/code&gt; is deprecated and replaced by &lt;code&gt;sass&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We'll remove &lt;code&gt;node-sass&lt;/code&gt; and the corresponding &lt;code&gt;node-sass-middleware&lt;/code&gt; packages from package.json, replacing it with the latest version of &lt;code&gt;sass&lt;/code&gt;.&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;$ &lt;/span&gt;npm uninstall &lt;span class="nt"&gt;--save&lt;/span&gt; node-sass node-sass-middleware
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zpdad6mj2czo88v3rjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zpdad6mj2czo88v3rjd.png" alt="npm install works!" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;xcellent! We're on our way. Before we move forward, let's be sure to update our import references in the code.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;node-sass&lt;/code&gt; has been completed replaced with &lt;code&gt;sass&lt;/code&gt;, we'll run a simple find and replace in the project for &lt;code&gt;node-sass&lt;/code&gt; and &lt;code&gt;node-sass-middleware&lt;/code&gt; to ensure all imports for this package are replaced.&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="o"&gt;-&lt;/span&gt;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-sass-middleware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sass&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;h2&gt;
  
  
  Step 3: npm run start
&lt;/h2&gt;

&lt;p&gt;All required dependencies are installed, despite copious deprecation warnings. Let's try to get this app running.&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;$ &lt;/span&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdkp8lnv28j8eojuncu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdkp8lnv28j8eojuncu3.png" alt="Terminal error output from npm run start. Class constructor MongoStore cannot be invoked without 'new'" width="800" height="417"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;var MongoStore &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'connect-mongo'&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;session&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                         ^
TypeError: Class constructor MongoStore cannot be invoked without &lt;span class="s1"&gt;'new'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A class constructor error with  &lt;code&gt;connect-mongo&lt;/code&gt;. This is the first of our build errors. Likely, they won't be the same as ours. But they're all pretty googlable. I'll share the ones we ran into.&lt;/p&gt;

&lt;p&gt;I resolved this MongoStore constructor error with a simple syntax change outlined in this &lt;a href="https://stackoverflow.com/questions/66654037/mongo-connect-error-with-mongo-connectsession" rel="noopener noreferrer"&gt;StackOverflow answer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1c999c1u7ldf172xt95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1c999c1u7ldf172xt95.png" alt="Terminal error output from npm run start. TypeError: dotenv.load is not a function" width="800" height="413"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotenv.load&lt;span class="o"&gt;({&lt;/span&gt; path: &lt;span class="s1"&gt;'.env'&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       ^
TypeError: dotenv.load is not a &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another easy syntax change. I followed the &lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;latest recommended syntax&lt;/a&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="o"&gt;-&lt;/span&gt;  &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2i4uef7tzp9iggn4wr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2i4uef7tzp9iggn4wr4.png" alt="Terminal error output from npm run start. TypeError: sass is not a function" width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;app.use&lt;span class="o"&gt;(&lt;/span&gt;sass&lt;span class="o"&gt;({&lt;/span&gt;
        ^
TypeError: sass is not a &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sass is back. Remember that express middleware I mentioned earlier? When we removed &lt;code&gt;node-sass-middleware&lt;/code&gt;, we also removed the shortcut function that converted SCSS files to CSS files for us in Express.&lt;/p&gt;

&lt;p&gt;These days, it's a little heavy to compile SCSS at run time. Most web projects will use a tool like &lt;code&gt;webpack&lt;/code&gt; to compile and inject references to stylesheets at build time. All that is served at run time are lightweight static files. &lt;/p&gt;

&lt;p&gt;I'm not in the mood to install and generate a webpack config to patch a tiny legacy app. The middleware wasn't doing much. The only output was a single &lt;code&gt;main.css&lt;/code&gt; file generated from a &lt;code&gt;main.scss&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;We'll write a simple script to do this.&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="cm"&gt;/**
 * Compiles main.scss to main.css
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compileScss&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scssFilePath&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="nf"&gt;join&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;public&lt;/span&gt;&lt;span class="dl"&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;css&lt;/span&gt;&lt;span class="dl"&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;main.scss&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;cssFilePath&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="nf"&gt;join&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;public&lt;/span&gt;&lt;span class="dl"&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;css&lt;/span&gt;&lt;span class="dl"&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;main.css&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 if the SCSS file exists&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scssFilePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Compile SCSS to CSS&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scssFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sourceMap&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;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expanded&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Ensure the output directory exists&lt;/span&gt;
          &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cssFilePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&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="c1"&gt;// Write the compiled CSS to a file&lt;/span&gt;
          &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cssFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Couldn't generate main.css. See compileScss in app.js.&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="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;e&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll stick this function in &lt;code&gt;app.listen()&lt;/code&gt; so it runs once when express starts.&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="cm"&gt;/**
 * Start Express server.
 */&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&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="nf"&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;port&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="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;compileScss&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Express server listening on port %d in %s mode&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&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;port&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onwards!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw3qfvrzfy0a383uazd0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw3qfvrzfy0a383uazd0.png" alt="Terminal error output from npm run start. TypeError: expressValidator is not a function" width="800" height="421"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;app.use&lt;span class="o"&gt;(&lt;/span&gt;expressValidator&lt;span class="o"&gt;())&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        ^
TypeError: expressValidator is not a &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another syntax issue. We'll get rid of this package altogether. It was included as part of  hackathon-starter, but the original project owner never wrote any validation logic with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall &lt;span class="nt"&gt;--save&lt;/span&gt; express-validator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F015016tipnd760l60jxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F015016tipnd760l60jxk.png" alt="Terminal error output from npm run start. Pointing to CSS class " width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Express started! But we're not out of the woods yet. The &lt;code&gt;compileScss()&lt;/code&gt; function we wrote failed to build the final CSS file. The .404 parsing error above is a simple fix. Class names cannot start with numerals.&lt;/p&gt;

&lt;p&gt;While we're still seeing a bunch of deprecated package and syntax warnings, the app works. So&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy1cuyfvkhr41gr9rmt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy1cuyfvkhr41gr9rmt3.png" alt="This is fine dog meme. The dog's face is replaced with a screenshot of 99+ console errors." width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Docker up
&lt;/h2&gt;

&lt;p&gt;Our last major dependency to work out is Docker, and by extension, the separate but dependent &lt;code&gt;mongodb&lt;/code&gt; container.&lt;/p&gt;

&lt;p&gt;The Dockerfiles are pretty straight forward. Let's get the easy stuff out of the way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# FROM node:10
FROM node:22-bullseye-slim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# image: mongo:4.4
image: mongodb/mongodb-community-server:5.0.24-ubuntu2004
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that instead of simply going with &lt;code&gt;:latest&lt;/code&gt; I chose specific images to make it less likely to break inadvertently on future version bumps. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;node:22-bullseye-slim&lt;/code&gt; image runs Node v22.5.1. In hindsight I would've figured this out before I got the app running on my local machine. But it's not a breaking change to go from 20.3.1 to 22.5.1.&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;$ &lt;/span&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;22.5.1
&lt;span class="nv"&gt;$ &lt;/span&gt;nvm use 22.5.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;package.json&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&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="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"22.5.x"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For good measure we'll also create a &lt;code&gt;.nvmrc&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Drew, our dev ops lead, has thankfully maintained our docker setup over time. So there wasn't much in the way of Docker updates to make. &lt;/p&gt;

&lt;p&gt;My initial &lt;code&gt;docker compose up&lt;/code&gt; led to an infinitely restarting mongo container with an AuthenticationFailed error. There wasn't clear guidance anywhere, but I was able to fix this by adding &lt;code&gt;authSource=admin&lt;/code&gt; to the mongodb URL (&lt;a href="https://stackoverflow.com/a/73645846" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xmw4ik9upkiqjiqnklo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xmw4ik9upkiqjiqnklo.png" alt="Screenshot of Crawly's landing page" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isn't she beautiful? Except...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wssvl5ks621bk37u450.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wssvl5ks621bk37u450.gif" alt="Gif of clicking the form submit button leading to a 404" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the console —&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/home/node/app/node_modules/mongoose/lib/model.js:545
 throw new MongooseError&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Model.prototype.save() no longer accepts a callback'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       ^
MongooseError: Model.prototype.save&lt;span class="o"&gt;()&lt;/span&gt; no longer accepts a callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alas, callbacks out. Async in. But it was way too much work to refactor the code to use async functions, so I migrated all callbacks to use promises instead. (&lt;a href="https://stackoverflow.com/questions/75586474/mongoose-stopped-accepting-callbacks-for-some-of-its-functions" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The was the single most time consuming step of this entire project. Every model CRUD function had to be updated. This means going through all the model functions listed in the &lt;a href="https://mongoosejs.com/docs/models.html" rel="noopener noreferrer"&gt;Mongoose docs&lt;/a&gt;, finding them in the project, and replacing the callbacks with promises.&lt;/p&gt;

&lt;p&gt;Here's an example of one.&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;// crawl.save(function(err) {&lt;/span&gt;
&lt;span class="c1"&gt;//     if (err) {&lt;/span&gt;
&lt;span class="c1"&gt;//         // Error&lt;/span&gt;
&lt;span class="c1"&gt;//     }&lt;/span&gt;
&lt;span class="c1"&gt;//     else {&lt;/span&gt;
&lt;span class="c1"&gt;//         // Success&lt;/span&gt;
&lt;span class="c1"&gt;//     }&lt;/span&gt;
&lt;span class="c1"&gt;// })&lt;/span&gt;

&lt;span class="nx"&gt;crawl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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="c1"&gt;// Success&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Error&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have lift off. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqa6ne1z21ao00filk19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqa6ne1z21ao00filk19.png" alt="Crawly's form submit success page" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;Keep in mind that despite how I've laid this guide out, my actual experience involved over 50 open tabs of research and comfort hugs with my dog. And it wasn't even a huge project!&lt;/p&gt;

&lt;p&gt;If you've been given the unfortunate task of updating a legacy project, I hope this helps.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
