Sigh... Another post like this. Sure, it works well enough for the example shown in the article, but won't work well beyond this. Bundlers, package managers and other tools were created to address problems people saw in medium-large projects for websites with a lot of traffic. And as soon as the project has dozens of files and even just two or three external libraries, this becomes unmaintainable. Not to mention minimizer/TypeScript/Babel etc that are important for development or distribution.
(Did I mention that import maps was only supported in only Firefox 3 months ago?)
People think they are smart and come up with ideas nobody thought of before. "This seems so simple, why don't people use this?" I'm sorry, that's not the case here. I have been doing web development as a hobby and professionally for well over a decade and have seen too much of this.
"Sure, it works well enough for the example shown in the article, but won't work well beyond this."
Sigh...the entire bloody point of the author is to use this for light projects, to scale the sophistication of the setup gracefully. With very obvious benefits: easy to understand, not linked to any setup so it works forever, interoperable and transferable.
Typescript isn't universally important for development. It has its advantages for large projects with many developers but it's in no way essential. Most web projects don't use Typescript and the very idea that it's a must-have only a few years old and quite opinionated.
Likewise, Babel isn't important either. You don't need to use some futuristic JS feature on your simple project, you can just stick to well supported ones, thus not needing Babel.
"I have been doing web development as a hobby and professionally for well over a decade and have seen too much of this."
I've been doing web development since 1996, so that makes for 27 years, should such obnoxious statement make anyone's opinion more important. If you need to piss on the idea of somebody scaling a web architecture proportionally to actual needs, you should reconsider who is the "smart" one.
I think the criticism is exactly of that ability to scale though. This setup is ineffective but manageable at the individual scale, but it's going to get more complicated as soon as anyone else is involved, or if the project lives longer than six months and needs to be updated, or if you wanted to add any dependency more complicated than a single file.
The other side of it is it's not really clear what the author is gaining here. They're still reliant on NPM package structures, and they're still pulling in third party dependencies. They're just doing it in an overly complicated way.
In contrast, this is what I'd do to get to the same point the author does in this example: (I'm going off the top of my head here, and I don't have a computer to check this, but it should just work.)
mkdir myproject/ && cd myproject/
npm init # although I think just doing echo '{}' > package.json is enough here
npm install -D vite
npm install solid-js
# write some actual code
$EDITOR index.html
npx vite
And now you've got basically everything that the author has, but you didn't need to write your own shell script to download modules, you don't need to do all the import mapping yourself, and it's much easier to graduate from this simple setup if you ever do need to.
My objection is that the author is quite clearly describing this as a bottom-up, small scale approach. Criticizing it as an inadequate approach for something much larger is unwarranted, as nowhere was the claim made that this scales up infinitely.
What is gained? No build step, as the article also clearly mentions. Your alternative approach goes against the goal of the author. Which is to not have a tool chain. "You can also do this by installing these 17 tools and 30 dependencies" is quite missing the point.
I don't disagree that it's small scale approach, it's just the language of "bottom up" and "scaling gracefully" that I disagree with. The setup in the article will work only at very small scales, and then you'll probably have to rewrite most of it. The setup I provided works at very small scales as well (arguably better), but can be progressively updated as needed (but only as needed - for example, there's no JSX support for now, but it could be added later if it became necessary).
And in a situation like this, I don't know that I understand the value in avoiding a build step simply for the sake of being able to say you don't have one. This isn't one of those situations where you're saving time by removing the build step because it's not actually building anything here, just rewriting a few paths and adding essentially the same import map. It's probably even quicker overall because it does the reload for you.
Likewise, you're overstating what tools are actually necessary here. It's not "17 tools and 30 dependencies", it's two: one (NPM) to manage dependencies, and the other (vite) to provide the dev server and set the imports up correctly. Everything apart from that is up to you to install as you wish.
> Likewise, Babel isn't important either. You don't need to use some futuristic JS feature on your simple project, you can just stick to well supported ones, thus not needing Babel.
I would say even many moderately complex sites/apps have no need for [shiny new feature X]. These days new JS features tend more towards nice-to-have than they do essential. Back in the days when jQuery was ubiquitous it was a different story but things have improved quite a bit.
I think a lot of Babel is for people who haven't kept up with caniuse statistics and don't realize that the "low water mark", the "well supported baseline", has moved to something very close to ES2021 or more recent. To be fair, Babel is explicitly targeting some of those developers that prefer ignorance and don't want the mental overhead of actually knowing what browsers support and like having "just use the presets!" attitude. I think some of them would be surprised how extremely little most of the standard presets do in 2023 because there are increasingly few things to downlevel.
I have especially long been of the strong opinion that you never need Babel and Typescript. There's nothing that Typescript supports that it can't downlevel itself and tslib is a much tinier runtime dependency (if you choose to have Typescript import it rather than embed it in place) than any of Babel's runtimes (including their core-js dependencies) even when a bundler is tree shaking most of it out today (because caniuse statistics say yagni).
It still amuses that for instance the create-react-app "best practice" in its Typescript template is to use Babel for type stripping and downleveling and delegate the Typescript compiler only to type checking. No wonder people find modern pipelines bloated. To be fair, I get why CRA likes the conceptual simplicity that both of their core templates use the same Babel presets and pipelines given to them Typescript is still the opt-in "extra".
(Also, I have no problem with esbuild doing my Typescript type stripping and running tsc as a separate pass in esbuild pipelines, but esbuild isn't pretending to do a lot of unnecessary downleveling in 2023 and adds no further runtime beyond the parts of tslib it bundles for you. It's mostly just Babel's extreme complexity that I find redundant and unnecessary and its labyrinth of presets that don't actually do much in 2023 but give the impression that they do.)
Es6 arrow functions are a good example of this. They have been around for a long time and work in most browsers, but people learned they need babel to transpile them out for internet Explorer. People dropped ie support but the knowledge "we need babel for browser compatibility " remained an entrenched fact.
Yeah, it's relevant to remember that arrow functions were defined in ES2015 (eight years ago) and like I said most browsers people are using are caught up through at least ES2021. The nice thing about the ES2015 year-based nomenclature (as opposed to the people still calling it "ES6") is that you can do a quick reasonable first approximation of caniuse statistics off hand with "is that standard at least two years old?" Arrow functions are old.
Here's another thing: if you want to grow from this exact setup, use deno. It has support for import maps and don't require a bundler or a separate compilation step for typescript
Why scale “gracefully” though? The boilerplate of bundlers and package managers isn’t difficult or time consuming in practice. Sure it’s a lot of code and bloat but it isn’t actually hard.
I’ve been doing it professionally for 20 years, and I agree. Modern front end development with TypeScript, Vite, Preact, and even the much maligned npm are so much better than anything that preceded them for building complex front end applications.
I like having a build step for code that I write. I build C, I build Go, I build C#. I don’t ship debug builds of those things.
I don’t know why I’d want to forego all of the niceties that a modern TS build brings and also ship what is essentially a debug build of JS to the browser.
Sure, for a really simple web page, I’ll just slap a script together. But for anything real, hell yes, give me a good build mechanism.
I think the difference lies is how pleasant the tooling/build process are. In the case of C, Go, C#, and other non-web languages, there are comparatively few gripes — the most common being “building takes a long time” with Rust and Swift for example, which is a fairly mild problem. The negative parts of the experience for these languages more often than not get fixed.
With JS, it seems like many of the negatives are much more sticky and refuse to go away. Not sure why. Perhaps it’s related to how that ecosystem has a tendency towards cyclical reinvention of the upper layers while foundational/structural issues get considerably less attention, and so they get swept under the rug more often than they’re fixed, leading them to rear their heads every so often to remind everybody of their existence.
> I think the difference lies is how pleasant the tooling/build process are.
> With JS, it seems like many of the negatives are much more sticky and refuse to go away. Not sure why.
Spot on. I think there is a quality/cultural problem around the javascript ecosystem, but I'm also not sure why it persists. If I had to hazard a guess, I suspect that it has to do with what javascript programmers are usually trying to build. Those things are mostly visual, and the audience cannot see the quality or lack thereof easily, and outputs do not often live long. These incentives steer people to create fast and not worry so much about the soundness, sustainability, or longevity of their solutions.
I made a comment to a colleague recently that javascript tooling is a 'labyrinth of complexity'. That is my main gripe with all of the 'stuff' that comes with the front end. It all feels overcomplicated and thrown together.
While you may like having a build step, it is not necessary and some people don't like it. I've been building commercial data warehouse apps for >30 years and am very happy that our apps don't have a build step. Current app is a multi-million dollar Fortune 500 client app. No build step.
> $ echo '{}' > package.json && npm i --save-dev typescript vite preact
> added 17 packages, and audited 18 packages in 1s
You're off by two orders of magnitude. I get not wanting a lot of transitive dependencies, but you can get a modern toolchain without having a lot of transitive dependencies.
And you can go even smaller if you're fine with a slightly less user friendly (but still modern, and also very fast) build tool that's used at the core of Vite:
Webpack is the real offender and while vite is cool it isn't really a replacement for the decade or so standard, and looks like it requires a semi modern browser.
I'll probably try it out some time for a home project, but for anything serious it's a no go.
Perhaps, but JS tooling is waaaay better than it used to be.
Vite and Turbopack are way easier to use than Webpack, and faster than the next best thing, Parcel.
npm supports lockfiles. Yarn goes further in that you no longer need a million files in node_modules; or pnpm uses hard links to prevent duplication.
That said, typechecking Typescript is unfortunately slow. esbuild (as used by Vite) can strip out type signatures quickly, but can't check them. Rescript is very fast, but is a very different language than TypeScript or JavaScript, namely ML with braces.
The person I was responding to wrote "Modern front end development with TypeScript, Vite, Preact, and even the much maligned npm are so much better than anything that preceded them for building complex front end applications." which implies that modern front end is an improvement over what previously existed.
That person then wrote "But for anything real, hell yes, give me a good build mechanism." which implies that he creates real, high quality applications.
But my experience is that all front end web applications are all sub-par, so it doesn't really matter if a SPA uses a bundler or not, it doesn't affect quality when it is all shit anyway. So more power to the guy who decides to not use the bundler.
In the end, I agree with Alan Kay, the web was created by a bunch of amateurs
Figma and Discord come to mind as being exceptionally well implemented front end applications. They're even more HN-friendly because they both use Rust for performance-critical code.
The author is pretty clear that their intention is to use this as a simple first step to creating an app without the hassles of bundlers, they don't seem to be advocating that one would create "medium-large" projects like this. The word "incremental" is mentioned in the first sentence.
Nor does their message come across as "why don't people do this" to me.
> Until recently though, I wasn’t sure how to make this step feel incremental.
Seems like they genuinely just found a neat way to do a thing and wanted to share it.
> People think they are smart and come up with ideas nobody thought of before.
I think you're projecting your thoughts about some other thing on to this article... this one is a "this is how I like to do things and I found a new thing that helps do it that way" post.
The tone of the article is really not like what you're suggesting.
The last couple days there's been a lot of negativity towards the build step, but it's like everyone's forgotten the historical context that made the build step so popular to begin with.
I'll give credit to the post about the fragility of certain build tools long-term in the npm ecosystem, but I don't think that's a reason to shrug off build tools period. We just need better, more stable ones (and I think we're starting to finally get there).
The historical context is web development became popular and developers from other disciplines moved over and brought their practices from those other areas of programming with them. We compile apps for the desktop, we should compile apps for the web too. They brought their complexity with them and forced it onto web development instead of stopping to consider if that was a good idea. Now we have developers who never knew how things were before transpilers were created and now think that this is how it has to be and that this is the best way.
Have you worked with old, medium to large sites filled with jQuery and custom ad-hoc scripts? In the past year I helped maintain a site exactly like this - it's a huge pain. So many problems that should've been caught sooner are noticed far later, leading to long feedback loops that cost time and money.
Sure, I would agree that the current JS ecosystem has its issues, but work can happen at either compile/design time, or at run time. Shifting work from one step to another has trade-offs that may or may not matter for a given team or product.
For small hobby projects? The scale makes these problems pretty insignificant, so handling more at runtime ain't so bad. But the number of possible problems multiplies as your codebase increases in size, and by solving these problems sooner, you spend less time overall dealing with them.
Typescript was still 0.x "public preview" and I was knee deep in a codebase that was a massive amount of jQuery scattered across mostly inline script blocks in a huge number of ASP.NET templates many of which were "components" subcluded by other templates (meaning who knows how many final inline DOM-blocking script blocks per final output page). I had helped invest a ton of effort into an AMD infrastructure to start to modularize all those inline script blocks, but the conversion was pretty slow going (AMD modules were a pain to write by hand) even though the clear performance win of it helped keep it a clear priority project. Typescript even in 0.x made all of that so much better and easier if for no other reason that it made writing and managing AMDs so much simpler (and type checking helped code quality so much as bonus).
A lot of compile time tooling didn't fall out of the sky because they were solutions looking for problems. They solved real problems at the time. It's amazing to think how few developers today remember "the bad jQuery days" and "server-side template inline script block hell" and AMDs (good riddance, though they too solved important problems in their time). I don't think they can understand how much "our compile times are slow" is a better problem to have. I'm not sure if I envy some of them having missed some of the worst of those past problems.
> We compile apps for the desktop, we should compile apps for the web too.
I don't think this is true at all. The key reason you see build steps are to solve problems that you don't even have to worry about in desktop apps. If you have an app on the web, its bundle size needs to be small so that it downloads over the internet in a few hundred ms or so. So you get a minification step. You want a good type system, you end up with a build step. You want broad compatibility with older browsers? You end up with polyfills. Need to do some asset processing? You end up with some scripts that have to run at build time.
Build steps aren't some arbitrary complexity people make them out to be. They solve performance and compatibility issues, which impact real users in the real world. Running full-blown desktop apps over HTTP comes with a different set of problems compared to any local native app.
Of course most of this isn't important for small side projects. But for many, side projects are a way to learn about different technologies they might end up using for larger projects or in a professional context.
I’ve been doing web development for more nearly 25 years. It isn’t unmaintainable. How do you think we built large websites in the days before compiling/transpiling was a thing?
>How do you think we built large websites in the days before compiling/transpiling was a thing?
You don't really compare web development 25 years ago and now, do you? Then the most complex front-end was having two forms. Also people wrote operating systems in ed but don't think one will even consider giving up their IDE/editor for ed because people could build complex software in past with that.
> Then the most complex front-end was having two forms
You have no clue what you're talking about. In the late nineties we had just about every bell and whistle working that I see in websites today, hardware limitations permitting. Some of it did not work well because client browsers were slow but it was all there: full interactivity through Java applets, VRML, media control API etc. Websites in the nineties were not two forms and a table tag. My masters project was embedding a voice recognition engine for interactive web search.
Yeah we didn't do SPAs and instead implemented interactivity locally. That was a good thing that you threw in the garbage for a fad.
It seems odd to bring in Java applets and similar technologies to the discussion when the original point was that web development shouldn't need a build step. And isn't the whole point of SPAs to implement local interactivity? I.e. treat the client as a separate application (just like you would with an applet) and move session logic out of the server?
If anything, I think it's remarkable how far we've graduated from that point: many features components and features that we used to have to build by hand are now directly implemented in the browser; Javascript is significantly easier and nicer to use, even without having to apply a build step (even just splitting scripts into separate modules is now supported natively!); and features that previously required potentially insecure plugins to be enabled are now controlled by the browser, giving users much more ability to control what their browser is doing or not doing. Even if you do want more complex development with build steps, with tools like Parcel and Vite, that's usually pretty simple at this point (certainly simpler than the last few Java builds that I've seen).
It seems like you're complaining that everything is worse now because it's possible to have stupid amounts of complexity these days, but it's also a lot easier to have no complexity at all.
Not sure we're even on the same page if your argument on "sites were as complex back in the good old days" is embedding a literally distinct program on site, which quite ironically also happens to include its own complicated tooling and building.
Sure, you can run optimized JavaScript in your browser. At least you can smugly tell your users about your elitist belief when they mention that your scripts don't run on safari, because you've mistakenly used an API that was only available in Chrome and you didn't ship a polyfill, or if your code is larger than it has to be because it's not minified.
> People think they are smart and come up with ideas nobody thought of before. "This seems so simple, why don't people use this?"
So, in your opinion how do things improve then? People see how painful some tools are and so they try to improve things. Some times it works, some times it doesn't.
But can't you see? Overengineered blog / todo list clearly shows that JavaScript frameworks are totally useless and we should all be using jQuery instead. My own custom framework is totally up to the task and we shouldn't be trusting <big corp> as the maintainer of common frameworks. The browser is a bad tool anyway and we should all go back to using text only web pages.
(Did I mention that import maps was only supported in only Firefox 3 months ago?)
People think they are smart and come up with ideas nobody thought of before. "This seems so simple, why don't people use this?" I'm sorry, that's not the case here. I have been doing web development as a hobby and professionally for well over a decade and have seen too much of this.