Bare minimum modern frontend setup. Not a library or solution, just a starter template for myself, as I've grown tired of the node_modules
black hole being 100 times larger than the entire project codebase.
- Preact (1:1 React experience with smaller bundle)
- Global store using
Jotai
- SASS
- Esbuild (Blazingly fast bundling/re-building)
- Compatibility defaults from Vite and no Babel used -
'es6', 'chrome87', 'firefox78', 'safari14', 'edge88'
- Gzip/Brotli/Both output encoding
- Built-in chunking (at least in the js department, though I'm not sure about CSS)
- Re-build simple caching to cut time even further
- Env vars substitution
- Live reload and partial Hot Module Replacement (CSS only)
- Linter (not a heavy eslint)
- Prettier
- Tested with chakra-ui to ensure react backwards compatibility (lib not included)
To use with React
:
- Add
react
,react-dom
- Remove aliasing in
esbuild.config.js
- Remove preact paths,
jsxFactory
,jsxFragmentFactory
andjsxImportSource
intsconfig.json
Build time:
- Gzip, No chakra ; yarn build ->
270ms
; actual build ->57ms
- Gzip, With chakra ; yarn build ->
340ms
Rebuild time:
- Gzip, No chakra ; initial yarn build ->
270ms
; changes ->15ms
And it could be even lower with optimizations, but with such absurdly low metrics, there's just no point.
"dependencies": {
"jotai": "^2.10.0", // 1.2 MiB
"preact": "^10.22.1", // 1.8 MiB
"preact-iso": "^2.6.3", // 68.0 KiB
"preact-render-to-string": "^6.4.0" // 964.0 KiB
},
"devDependencies": {
"@types/node": "^22.5.1", // 2.3 MiB (@types in general)
"esbuild": "^0.24.0", // 9.7 MiB
"picomatch": "^4.0.2", // 116.0 KiB
"prettier": "^2.7.1", // 10.8 MiB
"quick-lint-js": "^3.2.0", // 11.6 MiB
"sass": "^1.79.3", // 5.5 MiB
"typescript": "<=5.2.0" // 38.6 MiB
}
Additionally, there are some child dependencies totaling 2-3 MiB
, and that's it. There are only 17 directories in the node_modules folder, so you could literally read the source code of all of them in one day. 👀
I haven't compared the output bundle size with other build tools yet since the codebase is too small to draw any real conclusions, but I'll probably add that in later.
It's worth mentioning that I had to write some custom build-related code to get esbuild to handle what seemed like trivial tasks at first glance—things I was used to getting out of the box from CRA, Vite, and Webpack. Esbuild was missing essential parts here and there, and there aren’t many well-written and optimized plugins to fill the gaps. Moreover, I wanted to include as few dependencies as possible. So, I had to dig through what's available and piece together a 'regular' web development environment step by step. It was fun, and more importantly, an insightful experience as I learned things I never would have with all those pre-built tools.
Esbuild isn't 'production-ready' in the sense that it frequently ships breaking changes. However, it's highly agile with its custom plugin feature. You need to be prepared to get your hands dirty in exchange for fast build speeds and a somewhat immature ecosystem. For me, it's been worth it, and I hope to extract even more value over time.
Also shoutouts to tsoding and his React exploration video for making me rethink how bad it all is in webdev land.
yarn start
yarn build