Upgrading old Imba 1 apps to run on modern Node
Tags: javascript, imba, webpack, scss
Published: 2022-12-18 13:16:03

Node has the least stable ecosystem of all the commonly used languages. With Ruby or Python or frontend JavaScript, you can use take a project that's a few years old, and it will generally run just fine. Frontend JavaScript is one of the most stable languages.

With Node, it never happens. Every new Node version breaks pretty much every old package, and all you'll see is a wall of node-gyp errors.

This happened to me as well. Back when I was playing with various frameworks, I discovered Imba 1, and liked it quite a bit. So I built a lot of small apps, with Imba and SCSS. And of course SCSS won't work on latest Node. There was also a hell of webpack plugin dependencies involved, as Imba 1 and SCSS needed some webpack plugins, and I can't just upgrade that to latest version either.

GitHub's `dependabot` also keeps bothering me to upgrade dependencies to fix "security issues". This sounds like a good idea, [except it has about >99% false positive rate overall](https://overreacted.io/npm-audit-broken-by-design/), but the upgrades will absolutely break your apps.

While I was at it, I also did a Cypress upgrade, but that's an easy process of running `cypress open` and using builtin migration tool.

### Dependencies

Before:

```javascript
  "scripts": {
    "dev": "webpack-dev-server --mode=development --content-base dist/",
    "build": "webpack --mode=production",
    "watch": "webpack --watch --progress --colors --display-modules",
    "predeploy": "pnpm run build",
    "deploy": "gh-pages -d dist"
  },
  "dependencies": {
    "css-loader": "^1.0.1",
    "cypress": "^3.4.1",
    "express": "^4.16.2",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "gh-pages": "^2.0.1",
    "imba": "1.5.2",
    "normalize-scss": "^7.0.1",
    "style-loader": "^0.23.1",
    "webpack-dev-server": "^3.7.1"
    "node-sass": "^4.12.0",
    "sass-loader": "^7.1.0",
    "webpack": "^4.26.0",
    "webpack-cli": "^3.1.2"
  }
```

After:

```javascript
  "scripts": {
    "dev": "webpack-dev-server --mode=development --static dist/",
    "build": "webpack --mode=production",
    "watch": "webpack --watch --progress --colors --display-modules",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist"
  },
  "dependencies": {
    "css-loader": "^5.2.7",
    "cypress": "^12.1.0",
    "gh-pages": "^4.0.0",
    "imba": "1.5.2",
    "mini-css-extract-plugin": "^1.6.2",
    "node-sass": "^8.0.0",
    "normalize-scss": "^7.0.1",
    "sass-loader": "^10.4.1",
    "webpack": "^4.46.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.11.1"
  }
```

It took some serious trial and error. The important thing is that I needed to stay on Webpack 4 for Imba 1 to work, so for everything I picked the most recent version that still worked with Webpack 4. I fully expect it to stop working eventually, when Node 30 breaks Webpack 4, and all that code becomes unrunnable, while people can still run frontend JavaScript from the 90s without any issues whatsoever. But at least it fixes it for now.

### `webpack.config.js`

Before:

```javascript
let ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.imba$/,
        loader: 'imba/loader',
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader']
        })
      }
    ],
  },
  resolve: {
    extensions: [".imba", ".js", ".json", ".scss"]
  },
  entry: ["./src/app.imba", "./src/app.scss"],
  output: {  path: __dirname + '/dist', filename: "app.js" },
  plugins: [
    new ExtractTextPlugin('app.css')
  ]
}
```

After:

```javascript
let MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.imba$/,
        loader: 'imba/loader',
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader",
        ]
      }
    ],
  },
  resolve: {
    extensions: [".imba", ".js", ".json", ".scss"]
  },
  entry: ["./src/app.imba", "./src/app.scss"],
  output: {  path: __dirname + '/dist', filename: "app.js" },
  plugins: [
    new MiniCssExtractPlugin({filename: 'app.css'})
  ]
}
```

The plugin package changed, and so did its options.

### Code

For now I upgraded imba-rotn package. [The code](https://github.com/taw/imba-rotn) is available here. [It's also available online here](https://taw.github.io/imba-rotn/).

Now I have about 30 more Imba 1 packages that all need similar fix.