Dusting Off a Neglected JavaScript Project
5/19/2023
In my first post, I described choosing React as the JavaScript library and then Next.js as the framework for this blog. After a few posts, I did what I knew I would do all along: stopped writing. What new problems lurk today, 15 months since my last post?
Browserslist: caniuse-lite is outdated
What is browserslist? It's a tool that, in this case, tells React what browsers I want to work with my site. React takes that into account when outputting JavaScript. I didn't configure browserslist, so while it's in my project as a dependency, I'm not using it. There are documented reasons for keeping it updated, though. Let's do what we're asked to do in the warning message:
npx browserslist@latest --update-db
Deal With npm audit Results
Running npm audit tells you about known vulnerabilities in packages your project is using. Applying the suggested npm audit fix got me down from 13 vulnerabilities to nine.
Some of the vulnerabilities want me to install a newer version of @mdx-js/loader@2.3.0 and caution that it is a breaking change. That package is what loads MDX data from local files and renders it as HTML, which is pretty important to me, because I wanted to write my blog using Markdown. To upgrade it, I ran:
npm install @mdx-js/loader@2.3.0
That got me down to four remaining vulnerabilities. They seem to involve upgrading Next.js itself. So, let's try:
npm install next@12.3.4
Now we're down to zero vulnerabilities... and the site is completely broken. 🤦♂️
Undocumented Change in Next.js
Upon running npm run dev, I got Module not found: Can't resolve 'fs'. I went down a rabbit-hole, thinking that webpack needed to be told not to load the fs module when things are happening in the browser. I even managed to get it to not load fs by updating my next.config.mjs file as follows:
const config = {
reactStrictMode: true,
webpack: (config, { isServer }) => {
if (!isServer) {
// don't resolve 'fs' module on the client to prevent this error on build --> Error: Can't resolve 'fs'
config.resolve.fallback = {
fs: false
}
}
return config;
}
}
export default config
But, all that really did was take me to another error: TypeError: Cannot read properties of undefined (reading 'split'). This one was much harder to understand. The message referenced this line in @nodelib/fs.scandir/out/constants.js:
const NODE_PROCESS_VERSION_PARTS = process.versions.node.split('.');
So process.versions.node is empty, and well it should be, when code is executing in the browser and not server side. After many attempts to get webpack to ignore that module, too, when !isServer, I realized that only my posts weren't loading - the rest of the page was. So that meant the error was probably in my pages/blog/[post].js file. The code looked right, the things in getStaticPaths and getStaticProps only happen server side. getStaticPaths calls another function that reads from the filesystem, but that wouldn't be executed in the browser, so no big deal. Or is it? I moved that function into getStaticPaths and the problem was resolved. It would seem that the newer version of Next.js now needs all server side code to be inside functions like getStaticPaths.
Warning: No "main" or "exports" field defined
This was showing up for next-mdx-remote, and I found a GitHub issue referring to this very problem. So I assumed I needed to update next-mdx-remote, and decided to try the latest version.
As is almost always the case, upgrading the latest version solved one problem and introduced another. next-mdx-remote@4.1 wound up being the newest version I could upgrade to.
Forgetting the Deploy Process
Not having posted anything in 15 months, I couldn't remember how to deploy, and I didn't write it down anywhere. It turns out, my process is this:
-
Run
npm run build. -
Run
npm run export.This writes all of the static content for the blog into a folder called
out. -
Sync the contents of the
outfolder to the S3 bucket from which the site is served:aws --profile [PROFILE NAME] s3 sync . s3://[ORIGIN BUCKET]