Frontend Heresy: No Vite, No Webpack — Dragging React Back to the HTML Era as an Anti-Engineering Practice
Anti-engineering React practice? Writing UIs by including React directly in HTML? That's heretical enough. Toolchain? HMR? Don't need them — load dependencies by hand, control the browser cache yourself. Why bring in a whole engineering stack for a simple interactive page? This trade-off is pretty “aloof”.
目录10 个章节
Preface
I've been busy with renovations and developing new products lately, so I haven't had time to update this blog. The consequence of rapid iteration is that the architecture hasn't kept pace with feature growth, and I now have a faint sense that things are slipping out of control. Over the past few days I've also slowed down the pace to think through the overall plan.
I'm also taking the chance to organize my notes — without putting anything out I feel uneasy 🤣
Alright, back to the topic. Why is the title “Frontend Heresy”? In today's highly engineered frontend world, tools keep proliferating, and everyone is saying stop updating, I can't keep learning. I'm going the opposite way:
- Don't use Vite
- Don't use Webpack
- Don't run a dev server
- Don't do HMR
- Don't maintain node_modules
Drop React straight into an HTML file and write the UI!
This sounds a lot like still using Dreamweaver to write web pages in 2025, hahaha 🤣
This article records an anti-engineering development practice that can be called “frontend heresy”.
Phase 1: Runtime JSX
At first, I used the most primitive, and most “heretical”, way of using React.
<script src="react.development.js"></script>
<script src="react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
function App() {
return <h1>Hello World</h1>;
}
</script>
The characteristics are obvious:
- No Node needed
- No npm / pnpm needed
- Open the browser and you can write React
- JSX is compiled in the browser in real time by
babel-standalone
I have to say, this approach is actually pretty satisfying to write with (flees
- Extremely low cognitive load
- No toolchain anxiety
- HTML is the entry point, what you see is what you get
But the downsides are equally obvious:
- Dependencies are huge, easily several MB
- JSX runtime compilation is extremely slow
- Once the page gets complex, load time visibly increases
Even this simple app of mine took half a minute to load locally 🤣
In fact, this usage is React's official early demo + teaching-level usage, later explicitly marked by the official docs as: Not recommended for production
I've also written an article about this before: Including React and JSX in HTML
Practice also proved that this approach can only be used for local demo testing — it simply cannot be shipped as production.
Phase 2
gulp + babel, I only want JSX compilation
I chose a tool that looks very “retro” today: gulp.
This tool is simple, but very useful. I've always liked it a lot, and you can see gulp's footprint in many of my projects:
- ASP.NET Core Dev Notes: Managing Frontend Static Files with NPM and gulp
- Bringing NPM and gulp into a Django Project to Manage Frontend Assets
- Back to Basics! Building Interactive Web Apps with Alpine.js — Ditch node_modules and webpack!
The usage looks like this:
Explicitly add the jsx components to the processing list, in order
const jsxComponents = [
"Alert.jsx",
"Toast.jsx",
"Login.jsx",
"Register.jsx",
"ChatView.jsx",
"DetailView.jsx",
"App.jsx"
];
I gave up automatic dependency analysis, which in modern frontend is almost “original sin”. 😂
But in a project with clear boundaries and a controllable scale, it is actually the most controllable approach.
gulp does a few simple things here:
- JSX → JS
- multiple files → one bundle
- minify
gulp.task("concat:jsx", () => {
return gulp.src(jsxComponents, { base: "." })
.pipe(babel({
presets: ["@babel/preset-env", "@babel/preset-react"]
}))
.pipe(concat("dist/js/app.bundle.js"))
.pipe(terser()) // Use terser for minification
.pipe(gulp.dest(paths.root));
});
No loaders, no plugin hell, no configs fighting each other.
The final artifact is just one file: dist/js/app.bundle.js
The Final Form
After the build, the entire application's entry point is an extremely plain HTML file.
<script src="lib/react/react.production.min.js"></script>
<script src="lib/react-dom/react-dom.production.min.js"></script>
<script src="lib/axios/axios.min.js"></script>
<script src="dist/js/app.bundle.js"></script>
A few things I really like:
-
All dependencies are explicit
-
React doesn't need JSX to run
-
Browser cache is under my own control
<script> (function () { const scripts = [ "dist/js/app.bundle.js", ]; const v = new Date().getTime(); scripts.forEach(src => { document.write(`<script src="${src}?v=${v}"><\/script>`); }); })(); </script>
Why?
The reason for doing this is actually simple: my backend needed a simple interactive page, and I neither wanted to create a new Next.js/Vite frontend project for it, nor did I want to use backend template rendering + HTMX/Alpine.js.
-
The former's problem is cost:
For a page with very clear functional boundaries, bringing in an entire frontend engineering stack means extra maintenance of a project structure, a set of build configs, and a whole toolchain lifecycle. That cost, for this requirement, is excessive.
-
The latter's problem is expressive power:
Backend template rendering with HTMX or Alpine.js is indeed lightweight, but when the page starts to have more complex state transitions, component reuse, and logic composition, I quickly start “manually simulating a component system”. Rather than twisting around in template syntax and directives, I'd rather just use a component library I'm already very familiar with and whose mental model is stable enough (the React ecosystem).
So the question became:
Can I use only React's “expressive power”, without bringing in the entire engineering system behind it?
This is exactly the starting point of this “frontend heresy” approach.
Value
What does this “frontend heresy” approach solve?
In one sentence: how to get a sufficiently comfortable interaction layer without introducing extra engineering complexity.
Specifically, this approach achieved a few things:
- No need to maintain a separate frontend project
- No need for a dev server, HMR, or complex build configs
- No need to bear the long-term cost of a full frontend engineering stack for a small page
- But you can still:
- Use component-oriented thinking
- Manage clear state and interaction logic
- Write structurally clear, maintainable UI code
This isn't about chasing the lightest possible stack, but about chasing: a match between complexity and the scale of the requirement.
When the requirement is simple enough, engineering itself should be something that can be dismantled, restrained, or even refused.
Trade-offs
👍 What I gained
- Extremely low cognitive load
- An extremely stable build process
- No runtime build dependencies
- Very suitable for:
- Admin systems
- AI consoles
- Internal tools
- WebView / embedded pages
❌ What I actively gave up
- HMR
- Automatic code splitting
- Full TypeScript pipeline
- The dividends of the ecosystem plugin landscape
Wrap-up
What I did is actually simple: peel away complexity layer by layer, until only the layer the business actually needs remains.
I don't recommend everyone do this, but I'll keep making some anti-engineering attempts. Going against the grain in the AI era is actually pretty interesting 😄
_EOF_
Frontend Heresy: No Vite, No Webpack — Dragging React Back to the HTML Era as an Anti-Engineering Practice
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
开始开发一个新博客了,复古风Metro风格,顺便diss一下js
emmm 我原本的博客是用wordpress搭建的,当年七牛云还是免费时用它做的CDN,但是现在收费了,如果维持目前的博客流量的话每个月都要支付不少费用,于是只好把七牛云给停了= =,这也导致我博客里面很多图片都访问不了,页面布局也出问题了,不想折腾了,而且wordpress用起来总觉得不顺手,还是自己做一个吧~ 计划 最近刚好在学SpringBoot啥的,本来想用springboot搭建一个博客
2022-07-18 · Web前端 · 约 1 分钟
使用微软官方的IE虚拟机测试上古网站
下载地址:https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/ 虚拟机默认密码:Passw0rd!
2021-12-18 · Web前端 · 约 1 分钟
Vue2.x项目整合ExceptionLess监控
前言 一直以来我们都是用Sentry做项目监控,不过前段时间我们的Sentry坏掉了~~(我搞坏的)~~ 但监控又是很有必要的,在sentry修好之前,我想先寻找一个临时的替代方案,同时发现网上关于ExceptionLess的资料少得可怜,ExceptionLess官方的文档也不是很完善,翻了好久文档和源码,于是有了本文…… 关于ExceptionLess 写.NetCore的同学应该不会陌生,这
2022-03-23 · Web前端 · 约 1 分钟
使用国内NPM镜像源提高速度
NPM介绍 npm(全称 Node Package Manager,即“node包管理器”)是Node.js默认的、以JavaScript编写的软件包管理系统。 npm可以管理本地项目的所需模块并自动维护依赖情况,也可以管理全局安装的JavaScript工具。 但是由于npm的源在国外,所以国内使用起来动辄10kb/s,甚至根本下载不了,所以使用国内镜像源替代官方源就很有必要了。 国内源 淘宝np
2022-02-25 · Web前端 · 约 1 分钟
讨论
共 0 条加载评论中…