Fixing `Error: Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (93)`

Today my React project failed with the following error:

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
Error: Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (93)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v4.14.1
My project was using a very old version of node-sass.

And that's even after running npm audit fix. So this time I ran npm audit fix --force.

The command updated a few projects, node-sass included:

"node-sass": "^7.0.1",

Then I ran the project again, and Webpack complained of a few properties that are now removed. I removed and modified those properties hoping that it wouldn't break anything. I also used https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md as a reference.

When webpack finally ran, it threw this exception:

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
Error: Node Sass version 7.0.1 is incompatible with ^4.0.0.
    at getRenderFuncFromSassImpl ([project path]/node_modules/sass-loader/dist/index.js:165:13)
    at Object.loader ([project path]/node_modules/sass-loader/dist/index.js:79:18)

Just to be sure, I ran npm i again, and it turns out npm did not manage to pull all the dependencies:

% npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: css-loader@6.7.1
npm ERR! Found: webpack@4.39.2
npm ERR! node_modules/webpack
npm ERR!   dev webpack@"^4.39.2" from the root project
npm ERR!   peer webpack@">=2" from babel-loader@8.0.6
npm ERR!   node_modules/babel-loader
npm ERR!     dev babel-loader@"^8.0.6" from the root project
npm ERR!   9 more (eslint-loader, karma-webpack, sass-loader, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer webpack@"^5.0.0" from css-loader@6.7.1
npm ERR! node_modules/css-loader
npm ERR!   dev css-loader@"^6.7.1" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: webpack@5.73.0
npm ERR! node_modules/webpack
npm ERR!   peer webpack@"^5.0.0" from css-loader@6.7.1
npm ERR!   node_modules/css-loader
npm ERR!     dev css-loader@"^6.7.1" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

It's because I'm still using an old version of Webpack. Checking on npm, it seems like it's moved to major version 5. So I fixed that manually in package.json:

    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3"

The next error came from material-ui and React:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: material-ui@0.15.0
npm ERR! Found: react@16.9.0
npm ERR! node_modules/react
npm ERR!   react@"^16.9.0" from the root project
npm ERR!   peer react@"^16.3.0" from @material-ui/core@3.9.4
npm ERR!   node_modules/@material-ui/core
npm ERR!     @material-ui/core@"^3.9.3" from the root project
npm ERR!     peer @material-ui/core@"^3.2.0" from material-ui-pickers@1.0.1
npm ERR!     node_modules/material-ui-pickers
npm ERR!       material-ui-pickers@"^1.0.1" from the root project
npm ERR!   13 more (@material-ui/system, @material-ui/utils, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^15.0.0" from material-ui@0.15.0

I know it's bad, but my project is using two versions of material-ui. The old one was material-ui@0.15.0 and relied on React 15. I went to npm to see what the latest version was:

material-ui
React Components that Implement Google’s Material Design.. Latest version: 0.20.2, last published: 4 years ago. Start using material-ui in your project by running `npm i material-ui`. There are 1522 other projects in the npm registry using material-ui.

The page shows a warning telling me that the project is deprecated. Yes, I knew that. Anyhow, the latest version is 0.20.2 from 4 years ago. I really should end up the migration some day.

So I fixed the material-ui version to 0.20.2, and npm finished installing dependencies. It threw a few warnings, which I'll check if issues come up later.

I run npm start again and get this new error:

/cfg/dist.js:17
    new webpack.optimize.OccurrenceOrderPlugin(),
    ^

TypeError: webpack.optimize.OccurrenceOrderPlugin is not a constructor

According to this GitHub ticket, this feature is enabled by default, so it is safe to remove the line. I ran npm start again, and the error disappeared!

On to the next error:

Error: Compiling RuleSet failed: Exclamation mark separated loader lists has been removed in favor of the 'use' property with arrays (at ruleSet[1].rules[1].loader: style-loader!css-loader)

This is because of a change in how loaders should be listed. According to the doc, an old config like this:

{
  test: /\.less/,
  loader: "style-loader!css-loader!less-loader",
},

Should be renamed like this:

{
  test: /\.less/,
  use: ["style-loader", "css-loader", "less-loader"],
},

Next error:

Error: Compiling RuleSet failed: Query arguments on 'loader' has been removed in favor of the 'options' property (at ruleSet[1].rules[6].loader: url-loader?limit=8192)

So I changed:

use: 'url-loader?limit=8192'

Into:

{
  test: /\.(png|jpg|gif|woff|woff2)$/,
  loader: "url-loader",
  options: {
    limit: "8192",
  },
},

But oddly enough, when running npm start, webpack ran, started the server but threw this error about SASS again:

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
Error: Node Sass version 7.0.1 is incompatible with ^4.0.0.
    at getRenderFuncFromSassImpl ([project path]/node_modules/sass-loader/dist/index.js:165:13)
    at Object.loader ([project path]/node_modules/sass-loader/dist/index.js:79:18)

npm list also lists SASS as using version 7.

But running npm i threw an error involving eslint-loader:

npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: eslint-loader@2.2.1
npm ERR! Found: webpack@5.73.0
npm ERR! node_modules/webpack
npm ERR!   dev webpack@"^5.73.0" from the root project
npm ERR!   peer webpack@"4.x.x || 5.x.x" from @webpack-cli/configtest@1.2.0
npm ERR!   node_modules/@webpack-cli/configtest
npm ERR!     @webpack-cli/configtest@"^1.2.0" from webpack-cli@4.10.0
npm ERR!     node_modules/webpack-cli
npm ERR!       dev webpack-cli@"^4.10.0" from the root project
npm ERR!       3 more (@webpack-cli/configtest, @webpack-cli/info, @webpack-cli/serve)
npm ERR!   7 more (babel-loader, css-loader, terser-webpack-plugin, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer webpack@">=2.0.0 <5.0.0" from eslint-loader@2.2.1
npm ERR! node_modules/eslint-loader
npm ERR!   dev eslint-loader@"^2.2.1" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: webpack@4.46.0
npm ERR! node_modules/webpack
npm ERR!   peer webpack@">=2.0.0 <5.0.0" from eslint-loader@2.2.1
npm ERR!   node_modules/eslint-loader
npm ERR!     dev eslint-loader@"^2.2.1" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/anhtuan/.npm/eresolve-report.txt for a full report.

It looks like eslint-loader got deprecated 2 years ago in favor of eslint-webpack-plugin, and its latest version was 4.0.2.

So I fixed this dependency to 4.0.2 and ran npm i again:

% npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: schoolRegistration@0.0.1
npm ERR! Found: eslint@5.16.0
npm ERR! node_modules/eslint
npm ERR!   dev eslint@"^5.16.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer eslint@"^6.0.0 || ^7.0.0" from eslint-loader@4.0.2
npm ERR! node_modules/eslint-loader
npm ERR!   dev eslint-loader@"^4.0.2" from the root project

eslint-loader requires a newer version of eslint. Makes sense. The latest major version of eslint is 8, but eslint-loade@4.0.2 wants 6 or 7, so I'll give it that.

Then the next error regards karma-webpack:

% npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: karma-webpack@4.0.2
npm ERR! Found: webpack@5.73.0
npm ERR! node_modules/webpack
npm ERR!   dev webpack@"^5.73.0" from the root project
npm ERR!   peer webpack@"4.x.x || 5.x.x" from @webpack-cli/configtest@1.2.0
npm ERR!   node_modules/@webpack-cli/configtest
npm ERR!     @webpack-cli/configtest@"^1.2.0" from webpack-cli@4.10.0
npm ERR!     node_modules/webpack-cli
npm ERR!       dev webpack-cli@"^4.10.0" from the root project
npm ERR!       3 more (@webpack-cli/configtest, @webpack-cli/info, @webpack-cli/serve)
npm ERR!   8 more (babel-loader, css-loader, terser-webpack-plugin, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer webpack@"^4.0.0" from karma-webpack@4.0.2
npm ERR! node_modules/karma-webpack
npm ERR!   dev karma-webpack@"^4.0.2" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: webpack@4.46.0
npm ERR! node_modules/webpack
npm ERR!   peer webpack@"^4.0.0" from karma-webpack@4.0.2
npm ERR!   node_modules/karma-webpack
npm ERR!     dev karma-webpack@"^4.0.2" from the root project

karma-webpack too has changed major versions to 5.0.0.

Next, sass-loader major version 7 required webpack 3 or 4, but I have webpack 5, and sass-loader's latest major version is 13. So I fixed it to 13.

After fixing all these, I started getting a runtime error:

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
ValidationError: Invalid options object. Sass Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'indentedSyntax'. These properties are valid:
   object { implementation?, api?, sassOptions?, additionalData?, sourceMap?, webpackImporter?, warnRuleAsWarning? }

After removing those from my loader config, it complained about outputStyle as well. So I removed it.

After this, there were only one or two errors left:

ERROR in ./node_modules/htmlparser2/lib/WritableStream.js 6:13-37
Module not found: Error: Can't resolve 'buffer' in '[project path]/node_modules/htmlparser2/lib'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
	- add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
	- install 'buffer'
If you don't want to include a polyfill, you can use an empty module like this:
	resolve.fallback: { "buffer": false }
resolve 'buffer' in '[project path]/node_modules/htmlparser2/lib'
  Parsed request is a module
  using description file: [project path]/node_modules/htmlparser2/package.json (relative path: ./lib)

So I checked why I needed this project. It's because I'm using a project called react-html-parser. So I do indeed still need it. So I will install buffer: npm install buffer.

The very last issue was that the SASS was not being included anymore. I searched and searched and could not find what was wrong with my configuration. There was no error, and my config looked just like the example configs I found online. Until I found one comment that stated:

I notice that you are missing style-loader from your webpack config, which I always had to include to work styles properly

My config had style-loader in it, but what if my package was outdated? I check package.json, and it was on version 0.13.0. I check on npm. They're on version 3.3.1. So I fix the version, try again, and lo and behold! It works!

This work only took me the whole afternoon. T_T