My frontend tools odyssey

I actually wanted to use Preact for my pet project. Several build-tools and frameworks later, I stuck with the things that I know mostly. Read on, if you are interested in a non-comprehensive evaluation...

It has been quite and odyssey, trying to figure out which tools to use in the frontend for my project Gachou.

Preact CLI / Tailwind / Storybook

I started with preact-cli and tailwind, and I wanted to use Storybook for developing components in isolation. Then I encountered…

Dependency conflicts with webpack!

Storybook uses a different webpack version than preact-cli. Having both libraries in the same project leads to fascinating problems, because they pull in lots of different dependencies. Different versions of the same package. For instance, the preact-cli dev-server suddenly failed with an error in the browser-console.

Uncaught TypeError: AllHtmlEntities is not a constructor

This happens, because the package html-entities is present in different incompatible versions in the dependency tree.

> yarn why -R html-entities
└─ gachou-web-ui@workspace:.
   ├─ @storybook/addon-docs@npm:6.4.8 [a3186] (via npm:^6.4.8 [a3186])
   │  ├─ @storybook/builder-webpack4@npm:6.4.8 [9e85e] (via npm:6.4.8 [9e85e])
   │  │  └─ webpack-hot-middleware@npm:2.25.1 (via npm:^2.25.1)
   │  │     └─ html-entities@npm:2.3.2 (via npm:^2.1.0)
   │  └─ ...
   ├─ ...
   └─ preact-cli@npm:3.3.2 [a3186] (via npm:^3.0.0 [a3186])
      └─ webpack-dev-server@npm:3.11.3 [e4681] (via npm:^3.11.2 [e4681])
         └─ html-entities@npm:1.4.0 (via npm:^1.3.1)

Package managers like npm and yarn solve such conflicts, by placing one library in the root node_modules directory, and another version inside the dependent packages. In my case,

  • node_modules/html-entities was version 2.3.2
  • node_modules/webpack-dev-server/node_modules/html-entities was version 1.4.0

The webpack-dev-server needs version 1.4.0, but that is not the version that is injected in the page, because webpack looks for it in the uppermost node_modules directory. That’s why, it uses version 2.3.2.

As workaround, I added some extra code to preact.config.js:

  • Search for preact-cli starting in the project root.
  • Search for webpack-dev-server starting at preact-cli
  • Search for html-entities starting at webpack-dev-server
  • Add an resolve.alias to the config, providing the correct path.

This seemed to work at first, but I faced similar problems soon enough. In the end, abandoned preact-cli.

Webpack has a huge dependency tree, which greatly increases the probability for such problems.

But, what if I could have similar features with…

No dependencies

I decided to try wmr.dev, which is a new, advanced build system for Preact based on Rollup. The great thing about wmr is that it is pre-bundled. It comes as a single 2MB javascript-file with no dependencies. It is also pretty fast, because it targets ESM modules and does not do any bundling. The dev-server output looks almost like the original source-code, so source-maps are not needed (according to the developers). I am not sure if this is true, but my very simple tests worked very well.

But when I wanted to use keycloak.js, it wasn’t working so well anymore. The issue I was having with Keycloak was similar to this issue with node-html-parser. I took away the impression: wmr does not work well with common-js packages. But to be honest: I cannot reproduce the problems right now. I may be wrong.

The bottom line is: Rather than diving into the bugs and trying to find out exactly how to solve them, I decided to test the next tool.

vite.js

That tool was vite.js. It is a build-system developed by Evan You, the author of vue.js. Like wmr it is based on Rollup, also targets ESM modules. Non-ESM libraries are converted to ESM before loading processing them further.

It does have dependencies, but I haven’t experienced any conflicts yet. And it is just as fast as wmr. Honestly, when I saw vite I never wanted to return to webpack again.

I started using vite with Preact and Tailwind. And tried to implement my first user story: The Login.

As a user I want to be able to log in. And I want to be able to log out again. The logout button should be in a dropdown menu in the top-right corner of the page.

screenshot with dropdown menu

I could probably have implemented this dropdown myself. But I could also have taken the easy way and used a component library like react-bootstrap.

Amazingly, Preact and react-bootstrap seemed to work together. I hadn’t expected this. But just when I started to become confident, I encountered TypeScript errors.

It had something to do with React-Portal, but I haven’t taken exact notes. I am sure there is a solution to it, but after all those trials-and-errors, I wasn’t in the mood of further investigation.

I abandoned Preact and switch to React, which I know well from work and which I could expect every React-library to work with.

vite / openapi-client-axios

I encountered one more issue with vite: In our last projects at work, we used openapi-client-axios to generated TypeScript types from the backend’s OpenAPI spec.

I tried to use it with vite, but got the following error:

Error: Build failed with 1 error: node_modules/@jsdevtools/ono/esm/types.js:1:9: ERROR: No matching export in “browser-external:util” for import “inspect”

I believe this is because axios supports Node.js and browsers. There might be some Node.js code mixed with browser-code. For some reason is no problem for webpack, but when vite tries to generate ESM-code from the Node.js (common-js) code, it fails.

I didn’t dig deeper here, but simply chose a different library: oazapfts. I will integrate this library in a way that it is simple to replace, just in case.

Conclusion

My main takeaways from this odyssey are:

  • Modern build tools like wmr and vite are much faster than webpack, especially when it comes to running dev-servers.
  • Preact is a nice framework. Small. Looks solid. But React has a much larger community. A lot of libraries are developed for React. They may coincidentally work with Preact, but if you want to get something done fast and without much hassle, choose the original.
  • Finally, wmr is and interesting, but vite seems to be more mature.

As always, what you choose depends on your situation: How much pressure do you have? How large is the project? Can you try new things or do you have to play it safe?

I am going to take the safe road with Gachou. Not because I have external pressure, but I would like to see some results before the next photo-calendar is created… before next Christmas!