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.2node_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 atpreact-cli
- Search for
html-entities
starting atwebpack-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.
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
andvite
are much faster thanwebpack
, 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, butvite
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!