Hacker News new | past | comments | ask | show | jobs | submit login
JavaScript Gom Jabbar (frantic.im)
597 points by disadvantage on July 2, 2023 | hide | past | favorite | 281 comments



This is actually pretty funny. I coded javascript for a solid ~18 years (I stopped about 3 years ago) and the majority of the concerns in this list are from the past 10 years. What I find glaringly absent, which would have been present if this were written in 2013, is the absence of polyfills.

What other things that were JS nightmares in 2013 have largely ceased to exist? (Only to be replaced by this funny list.)

This is my favorite part: "You stop to count how many tools and parsers work on your codebase: TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser. You are not sure if you missed any. You are not sure if you want to know. The level of pain is so high you forget about anything else."


Grunt, Gulp, CoffeeScript, IIFE, overridden undefined, with, closures to create private fields, modified prototypes, variables global by default, call-site-this, automatic conversions for comparisons...

Ah yes, over a decade of JS.


Overridden undefined?

Omg, that’s awesome. I think anyone feeling like a corporate mindless drone should sneak that into a code base.

And I thought overriding toString() was naughty.

In my defense, on my personal projects I have started using var instead of let/const, snake_case everything, don’t use semicolons, manage my objects with my own prototypical inheritance, and am fucking around with my own shitty Canvas2D widgets. Turns out ditching the DOM and using a Turing complete language still beats the crap out of wrestling with the DOM even if you have to reinvent things like word wrap and text areas.

Oh! And there’s not a framework in sight.

The funny thing this is, my productivity and error rate have way improved. Prob coincidence but I do actually enjoy it much more.

Take that ChatGPT!

edit: I actually write web assembly by hand too. Binary even. And have my own little shim in wasm to override its type safety, put code in my heap space pure von Neumann style, and have my own program counter so I can jump and goto. Can’t wait to start doing self-mutating code.

I know this sounds like I’m being sarcastic here- I often actually am- but I kid you not my error rate has plummeted and its become a blast to program again.

My internet actually slowed to dialup speeds lately so I’m only going to MDN or Stack Overflow if I really have to as well.

‘Modern javarscript’? Hahahaha.


undefined couldn't be minified. If you assigned it to an undefined variable early on, any minifier could easily convert it to yet another single-character variable name.

undefined became U (for example). An 8-byte or more reduction per reference. What can I say? Size used to matter. (Been doing JS since 1996.)


If you allow it I think most minifiers nowadays use `void 0` for undefined as it’s smaller.

Though I should try this, using a variable alias for undefined and null would maximize minification.


this list feels just a short jump from “we didn’t start the fire”


Inspired by it: We're gonna build a framework

https://www.youtube.com/watch?v=Wm2h0cbvsw8


I am so glad you shared that. I've never seen it before and it made me laugh so hard I cried.


The only change in lyrics is “it’s been burning us since…”


"It's been burning, since IE was turning"


I kinda miss CoffeeScript, to be honest. I also miss ExtJs.


I have done things with Ext JS that now take me forever with React + MUI. I miss it too.


Aren't there commercial ExtJS-like frameworks built on top of React? Kendo UI commes to mind.


It really depends on what you're missing from ExtJS. Yes, there are some frameworks oriented towards more desktop-like UI components. Some of them even do layout, maybe even non-view stuff (Kendo seems to do at least the former).

But there are other degrees of ExtJS nostalgia:

- Being allowed to do everything in a desktop-like manner, and not having to bother too much with either mobile or more stylized web applications, even in enterprise contexts. No technical issue, no technical solution.

- Doing that in a simple manner. Even contemporary (> v4 or even v3) ExtJS might not be "ExtJS" in this regard, as the framework part got a lot more complex. First with their own weird tooling, nowadays with the worst of both worlds.

- Not having to touch HTML and CSS. Early ExtJS allowed you to do most things with heavily nested JS literal objects. With angular/react/etc. it's all separate syntaxes, most of them with angle brackets.


I'm also a bit pissed that in the past 10 (or more) years we still haven't gotten good established components in the browser that do even half of what ExtJS could do (and still does).

We may have some by 2050 thanks to https://open-ui.org

Browsers did pour billions of dollars and hundreds of thousands of man-hours into a lot of bullshit though :(


CoffeScript is pretty much alive. It even has JSX support now. Although lacks types and tooling.


var that = this


I always favored `self = this`, personally


Careful not to overwrite global self!

Oh the foot guns of `this`


dealing with IE6 nightmares


The IE6 debugger, specifically, which Did Not. Especially when it was a very specific IE6 crash bug that did not occur in any other context. Drawing vml polygons on maps.


error on line 0


I second @golergka about callbacks.

The BIG pain point for me, though, looking at my 10-year-old JS, is that it's all made of "classes" built up by modifying SomeFunction.prototype, which then get wrapped in a self-invoking anonymous function and returned as an object, just so you can call `new SomeFunction()` ... `SomeFunction.actualFunction()` as if SomeFunction were a class. That and also the lack of arrow notation; modifying Function.prototype itself to use .apply() to bind events to scope (or else just an endless abyss of .bind(this) in event callbacks)...


Today I don't even write promises anymore. Using fp-ts and piping data through Task and TaskEither monads feels so much better and easier to write and maintain.


I know what most of those words mean, but I have no idea what they mean in that order. This feels symptomatic of the general state of Javascript, where I've not written any for a year or so and am now wildly out of date.


People often complain about how complex it is, but it’s really just a matter of passing endofunctions through transplainer pipelines so that you can asynchronously hydrate the islands.


Seriously, once you understand the ui as a superposition of entangled complex-valued eigenstates that only collapse into place once an observer visits your page, frontend development becomes so much easier.


Why would you ever even need to pass an endofunction through a transplainer pipeline? There are far more efficient ways to do async island hydration in Elm.


The thing is — I'm actually quite stupid. I don't even understand what a monad is. I just FP because it's a good tool. So, here's an example. I'm building an automatic storyteller on top of GPT-4 — it's a toy project to build the LLM-based functional library. Here's how the code looks, with comments: https://gist.github.com/golergka/3fdc6b9cf9717bd1c0b315925a8...

This is literally 20 lines of code, and it doesn't take that much to learn to read it easily. When I originally implemented LLM-based applications in Python, it would make about 10 times more, and all the components wouldn't be as modular. I can change the functionality of this code in a very drastic way with minimal code changes and with safety of completely statically type checked code.


Thing is: you don't read it easily. It's basically a custom DSL bolted on top of Javascript that hides actual functionality beneath an Everest of abstractions.

That is, it's a yet another library trying to force Haskell/Haskellisms into Javascript and claiming with no proof other than emotions that it's so much better and more readable than something.

Here's an actual readable version of that:

    try{
      return getTurnPromptMessages(state, action)
        .map(mkCCRequestFromMessages)
        .map(addSchemaToRequest)
        .map(handleChatCompletion)
        .map(extractFirstCompletionChoice)
        .map(extractChatCompletionMessage)
        .map(decodeSchema)
        .map(detectLocation);
    } catch (e) {
      mkMessageError(e);
    }
It can be further simplified. For example, you don't need two separate functions to extract the first chat completion message etc.

This version:

- uses existing language constructs

- can be immediately understood even by the most junior devs

- is likely to be 1000 times faster

- does not rely on an external dependency that currently has 143 issues and every two weeks releases a new version adding dozens of new methods to things

Note: one thing I do wish Javascript adopted is pipes: https://github.com/tc39/proposal-pipeline-operator


Your version doesn't work.

* all but the first results are not arrays, so the `.map` function doesn't apply

* doesn't handle async operations

* catches ALL exceptions here, whereas my code only handles statically typed and well-defined errors

* doesn't include the GPT-generated message and messages from the first steps in the error

* doesn't include retry functionality

I appreciate this argument and time you've taken to read my code and write this counter-argument. Please don't mistake my direct code for animosity, I clearly see that you're a smart person even though I think you're wrong about this.

Also, the fp-ts doesn't add any runtime performance overhead here. It's a couple of extra function calls for a call that has an async operation that likely takes 30 seconds (GPT-4 is slow). Obviously, if I was writing code that runs thousands of times per second, I would not use FP.


> Your version doesn't work.

It does.

It was also somewhat tongue-in-cheek, and a five-second copy-paste of your code.

> all but the first results are not arrays, so the `.map` function doesn't apply

Unless you return arrays from all functions.

Not that different from wrapping every result into seventeen layers of functional abstractions. What do you think flow or flatMapEither does?

> doesn't include the GPT-generated message and messages from the first steps in the error

Of course it does. That's what the catch is for.

Or you could use an additional map if you want.

> Also, the fp-ts doesn't add any runtime performance overhead here. It's a couple of extra function calls

Of course it adds runtime performance overhead. Any additional function call adds a performance overhead. And in your case it's dozens of functions wrapping trivial functionality.

> Obviously, if I was writing code that runs thousands of times per second, I would not use FP.

Then why use it here? If the alternative is more readable, more traceable, has better stack traces for errors, doesn't require an unstable ever changing dependency...


> Unless you return arrays from all functions.

But that's not... what they actually do?

> Not that different from wrapping every result into seventeen layers of functional abstractions. What do you think flow or flatMapEither does?

It changes what functions return without having to adapt them to particular use-case.

> Of course it does. That's what the catch is for.

To achieve that, the catch has to assume that the functions throw exceptions with particular data. This cannot be enforced with type system, and once again, tied implementation of these functions to this particular context where they're used.

> Of course it adds runtime performance overhead. Any additional function call adds a performance overhead.

The function call overhead is a couple of dozens nanoseconds at best. And we're talking about a remote call that takes 30 seconds to complete and costs $0,05 per OpenAI's API.

The overhead you're talking about is 0,0000001% in time and I think a few orders less in cost.

> If the alternative is more readable

It's not. An alternative that would actually have all the same functionality would be 4 times as long and more importantly, much more complex to change in a meaningful way.

> more traceable, has better stack traces for errors

But that's the point: we don't need stack traces. We don't need exceptions for errors that we know how to handle.

That's like complaining that a GC-based language doesn't have a tool like valgrind to handle error allocation and deallocation issues.

> doesn't require an unstable ever changing dependency...

I've never had a breaking change from fp-ts and don't expect it to ever happen because of the nature of the library.


Really? I feel like Javascript has been more or less the same since we got `class` keyword. People have been using “FP” words like monad or Either in Javascript for more than 10 years. They weren’t mainstream then and they aren’t mainstream now even if you see them written in an HN thread.


Supporting ie6, ie7, and ie8 separately while developing on firefox just so we could use firebug.


I'm so glad Internet Explorer/Edge/Trident is Officially Over. If you told me in 2010 that in 10 years the worst browser I'd have to support was Safari/Webkit... I'd be overjoyed.


One thing (only thing?) I honestly miss about IE5.5-8 is how amenable the engine was to polyfilling. It wasn't fast, but you could do almost anything with the right polyfill technique.

No sessionStorage? Use window.name. No (then-) modern CSS? Use CSS3PIE [0]. IE doesn't support the transform CSS property? Use an *.htc behavior to convert the transform to a matrix filter.

It was madness, and it was beautiful in a Cthulhu kind of way.

[0] http://css3pie.com/


I was on the "fuck ie6" train. I had to write some support for ie6 in like 2015, I almost quit the job.


Replacing headers with a little Flash applet so that you can use whatever fonts you like, rather than being limited to whatever the user had installed.


Callback hell, and a general lack of types.

I have has a misfortune of spending today writing a test assignment for a company that still uses vanilla JS, without promises or declaration files. Felt right back in 2012 when I first tried node. Worked around the requirement of using JS by utilising JSDoc, but still — it was much worse than I remembered.


For future reference if you ever need to do it again, @callback is roughly equivalent to @typedef but for defining function types, and @template is generic type params for both. It’s not a good TS replacement whatever anyone might tell you, but it’s a reasonable approximation of what you might need in a pinch.


Prototype.js monkey patching every prototype it could get its mitts on


are polyfills solved just with core-js ( https://vived.io/fascinating-story-of-core-js-frontend-weekl...), or is it because people don't support as many different browser engines these days?


Every time I start up a new JavaScript (well, TypeScript) project, I go through the usual routine.

Usually it's a front-end project, so I'll pick my framework. Usually React, although I've been wanting to try out Svelte.

Next my bundler, which used to be create-react-app, or some other Webpack wrapper. Today, Vite is the best choice because it works pretty well without much configuration, and it supports all of the major frameworks which is quite nice.

I'll be sure to install and configure the TypeScript compiler, which is usually copy-pasting from a template. I always make sure to target the latest well-supported version of JS and use ESM modules, because I like being on the bleeding edge.

Next up I setup linters -- eslint + prettier. They do a good job. I have to configure eslint so that it plays nice with Prettier, and I also have to configure eslint for TypeScript and add any other plugins that the project might need, e.g. those for React. I usually like to setup some kind of pre-commit hook to run Prettier and eslint before committing, which saves time.

Additionally, I always install my IDE extensions and try to create a .devcontainer file or add list of recommended extensions so that both myself and others can setup their IDEs in the future. I tend to not configure eslint much and just use off-the-shelf configurations because I don't care about the style, I just want consistency in the code and mistakes to be caught.

Next up I setup my unit tests, usually jest or vitest or similar. Lots more configuration for TypeScript and whatever, and also usually a set of eslint rules.

Then I want a CSS framework. I like tailwind, so I install that and styled-components and twin.macro so that it all works nicely with React. Fonts and icons are often needed too, so I install a plugin for Google Fonts and whatever font library.

Anyway, after about a day of doing the above I'm ready to program. Why is it so much work? Why isn't there something that just works for 90% of the use cases? So many people are using Vite + TypeScript + [React|Vue|Svelte] + [eslint|prettier] + [tailwind|bootstrap] + [jest|vitest]. Why isn't there some non-configurable library that just does everything for me?


> Anyway, after about a day of doing the above I'm ready to program

And you know all of this. I, as a lowly backend dev + operations guy have tried to get into these stacks for a few times over the years and honestly, in many cases, I just failed. Or I got some tool chain going, but I felt like I had zero control over it and the slightest wobble of anything would just cause it to fall apart and I wouldn't be able to fix it.

I dunno, I just recently made the decision to consider most if not all of this JS stack as a blocker for what I want to do. Then I setup some flask application with jinja2-based server side rendering like back in the day. It doesn't look as modern or shiny (and currently rather ugly due to a lack of any CSS, but I've been told I should stick with pure modern CSS, so let's do that :) ). But it is a blast how much functionality you can get done quickly in that stack.


Fwiw, I think a lot of that is familiarity. I'm trying to create a Python backend right now, and it's something I've done before, but still every time it feels like a pain - what are the best practices for dependencies now and how do I install everything, how do I set up a server, how do I get it to work with SSL/TLS, where should I be putting my assets and my templates, how do I get them to link together, how do I get this into a container, etc, etc.

But I think that's just a familiarity thing. I know what I'm doing when it comes to frontend development, so it's not an issue to get a new project off the ground, but backend development - and particularly backend development in Python - is something that I only touch occasionally, and therefore have to futz around with every time.


I would agree partially. My python experience wasn't even as actual web applications until 3-4 weeks ago and mostly used python for scripting and such. But sure, this means that I know things like dependency management, deployment and similar topics around the language.

But this is also where I'd disagree partially: The backend world moves a lot slower and feels a lot more settled to me. Sure, I'm relying on experiences as a sysadmin and a python developer, but: (i) If you need a VPS, you still have the 4-5 choices you had for years, Hetzner (Cloud by now), Digital Ocean, Linode, AWS Free Tier. (ii) SSL-Fronting had the same answer for I think 10 - 15 years by now. Front it with an Apache or Nginx proxy with Lets Encrypt. LE was the biggest change there. (iii) The ancient good old python3 -m venv + activate + pip is still very much valid and recommended. I'm currently trying out poetry, but even that uses venvs and pip in the background. (iv) And then assets, templates, and even production deployment guidelines are mentioned e.g. in the wonderful quickstart of Flask [1]. And there are several really solid and stable development tools around there for linting, formatting, typecheckind. VSCode for example recommends them quickly.

Most of this has been stable for years while being carefully improved. On a similar page, I haven't been working as an active java developer in like 6 years. I can still readily understand pretty much all java builds in the company because the tooling is just stable.

The 2-3 tries I had to get into the JS ecosystem meant I had to reset most of my knowledge because all of the frameworks, toolings had been deprecated, replaced, rewritten and anything else.

1: https://flask.palletsprojects.com/en/2.3.x/quickstart/


I'm not sure the backend world moves all that more slowly, it's just if you're in it, you know which new parts to accept, and which to ignore. To take Python as an example, my impression as a newcomer is that Flask is pretty outdated at this point — why not use async/await and FastAPI instead? And are you sure you should be using pip/venv/requirements.txt still? Poetry and PDM both have lockfiles — surely that's better?* And yes, there's lots of recommendations for linting and formatting, but which should I actually be using? Is Black best? Or Yapf? Ruff seems to be the new hotness, is that the recommendation now?

I'm sure the answers to you are fairly obvious (and in fairness, a lot of them are fairly obvious to me), but that's often the same feeling I get when people ask similar questions about the frontend ecosystem. Like, if you're not worried about doing anything complicated, pretty much all the libraries that I use on a daily basis also provide a `.min.js` download on the GitHub page, and you can just pack those into a folder and get started writing your code. If you need a bundler, just install NodeJS, and then run `npx vite` in a folder with some HTML files in it, and you'll be up and running in no time.

* My point here is to be sarcastic, but this is one of those things that genuinely surprises me about the Python ecosystem every time I have to interact with it: the default way of installing dependencies is completely insufficient for creating at least halfway consistent builds, and every alternative seems only designed to deal with the happy path.


All of them have little command line programs. You have to run specific commands, in a specific order. Each one does... things. Many things, grabbing stuff from all over the Internet. You have no idea what any of these other things are, but there sure are a lot of them. Do you need them? Dunno, guess so, but where do they come from? Your directory tree starts growing many leaves and branches. But wait, you made a small change, you have to run something else to make it pick up the change and re-something the whozit or your application throws inscrutable errors. You start to despair, so you begin reading documentation. All of the documentation is cheery and bright, telling you how wonderful this or that package or tool is, so now you feel like a moron because you simply don't understand what's happening.

You give up and become a pea farmer.


You have two linters. This is insane. This alone is insane. Everything else is admittedly way worse, but even the smallest bit of the javascript ecosystem tooling choices is full of pain.


Is it? Prettier isn't so much a linter as a formatter, and I think most language ecosystems separate out formatting from linting - e.g. Rust's Clippy vs rust-fmt.


Rome for the win! It’s a thousand time faster than eslint and it does formatting too.

It doesn’t have as many rules, but you wanted to get rid of all the cruft anyway, so that’s a feature, not a bug.


What Rome tried to do it, is being all in one tool, linting, formatter, bundler, test runner, etc, but they got only the first two before running out of funding, now it's community maintained.

I want to migrate a project I have, but I fear that it will get abandoned and in the future I will need to migrate away from it again.


Wut? When did they run out of funding? The last half year has seen two major updates. If this is the pace they set when run by the community I can totally live with it.


I have no idea how true this is, but the source of the claim seems to come from here:

https://github.com/rome/tools/discussions/4302

"But in short, the company Rome Tools ran out of funding, so the core team of last year are no longer working on the project."

Of course this also seems to be second-hand information, as there is an "Anyone feel free to correct me" disclaimer at the end of the message above.


I've head about Rome, but I've never tried it. My main fear there is that it dies like so many other dev tools with low adoption do.


This is how your comment sounds:

I’ve heard Java teams use SonarCube/SonarLint, checkstyle, findbugs, and PDM in various combinations together. I guess the Java ecosystem is insane and full of pain.

I hear Go programmers use gofmt and go vet. I guess the Go ecosystem is insane and full of pain.

I hear Rust programmers use clippy and rustfmt. I guess the Rust ecosystem is insane and full of pain.

I hear Python programmers use flake8 and black. I guess the Python ecosystem is insane and full of pain.


If you're unfamiliar with Prettier, this gives an overview of why you should use it with eslint: https://prettier.io/docs/en/comparison.html


He may have 3 bundlers. Webpack as a direct dependency, then esbuild and Rollup, because Vitest uses both IIRC.


I think you're misreading that - the poster used to use webpack via create-react-app, and now they typically use Vite. And while yes, Vite does wrap other tools, it does so fairly opaquely - you shouldn't need to dive into the details unless you're writing your own plugins.


This is why I no longer develop for the front end. It’s too much.


I just copy my TypeScript starter directory over, and change the name in package.json, although admittedly I'm only ever doing back-end stuff -- couldn't you set something up like that for yourself?


This. The whole comment feels like self-inflicted damage. We have a special repository for various template projects and when we need to create a new project we copy one from there. Sure, it's not bleeding edge, but also not legacy as we bump dependencies from time to time and sometimes replace tools with newer ones.

I admit, it would be nice to have something like Maven Archetype to have things a bit more formalized, but for most of the time a good old copy-paste works well enough.


If you wanted something extra fancy you could even set up a Yeoman generator that accepts input parameters and builds out the starter project based on those.


That’s interesting, might give that a whirl, thanks


I love watching people reinvent Visual Studio or IntelliJ IDEA, badly.


What does this comment mean?


Proper IDEs will set up a lot of the "new project" boilerplate for you, wire up compilers, linters, etc...

People still using text editors like EMACS or VI need to do this themselves, often through some random mish-mash of unique and special text templates, scripts, and copy-pasting from previous projects.

Then unironically they'll proudly proclaim to be productive because of all the tooling they've successfully set up over many days of effort.


The boilerplate is nice for “a vue project” but it starts to fail when you want “a vue+ts project that includes our internal components library, auth, terraform, uses tailwind, etc.” It doesn’t take long to set this up by hand, but automating it makes it less prone to human error - which would be harder to catch in CR because the changes will typically be massive.

But if you CR the Yeoman generator, every project’s initial commit can start from a known-good state since all you need to do is provide it the project name and location.


doesn't npm create do this for you?

Like I can do `npm create vue` and I get a relatively nice and functioning Vue setup with most of the config already done. I agree it's a lot of boilerplate and random shenanigans, but also the apps we make for the web are more than they were. And you can absolutely write JS without all the tools, even with ESModules. But we don't do that much because turns out those tools actually do something. Do they do it in the cleanest way? No. Things could always be better. But they do it.


It does to some extent, and it's much better than it was a few years ago. In Vite's case, it'll create a nice template project with your framework of choice, optionally TypeScript, a linter, and I think also unit tests.

You still need to do additional configuration for your linter, and in my case (I did this last weekend) a lot of configuration for styled-component and twin.macro.

Even though it's easy to create projects, it does nothing for maintaining them. Updating all of these dependencies _can_ be painful. eslint rules are not very easy to configure, there are a lot of helpful rulesets out there which ideally would be bundled with the library they pertain to. For example, it would be nice if eslint saw I was using React and automatically applied recommended React rules, and the same for other libraries.


Maybe create a stub project with all the above you like and check it into github.

When you start a new project, clone it and rename some bits and you should be set.


FWIW, I have a side project, confgen https://github.com/erikpukinskis/confgen, which tries to help with this.

Assuming it’s an app (and not a library) to get what you are describing you would run:

    npx confgen@latest @app vite dist:app typescript eslint prettier react
Unlike create-react-app the idea is you can keep running that command, adding other runtimes and presets, and it will keep working. That’s the sense in which it’s “idempotent”.

It’s somewhat opinionated (vite, react only) for now. But I’d be happy to see pull requests for other stacks so long as things don’t get too complex.

It’s also pre-1.0 but I’ve used it on dozens of projects and it’s somewhat stable.


There are tons of those tools, you were just too busy doing all this work yourself to step back and search for them :)


Do you have any examples? I'd love to take a look!


Angular kinda does this; typescript+eslint+testing+framework are set up out of the box. I think sveltekit as well.


This is why I use Next.js for everything I do, even if I don't need SSR. All of this is set up, with options, when creating a new project.

I've also looked into asp.net lately, and it seems to have just as many moving parts, only difference is that most of it is first party.


I mean, it sounds like you're just trying to create complicated applications. That's not a bad thing, my day job is also about trying to build complicated applications, so I also install a very similar set of tools. But that's worth doing, because there is added value in each of these tools.

If I were trying to do something less complicated, I'd just install less stuff. For example, I don't normally setup devcontainers or Google Fonts, and if I need icons, I might later on install some generic icon SVG library. And if it's just a small project, I probably won't add ESLint or testing. I often skip tailwind as well if I can - it's not bad, but CSS (+SCSS) is built into Vite so it's just less stuff to configure.

But each of those choices has a good reason, otherwise you wouldn't be using it. Tailwind makes writing CSS a lot quicker, linters help us catch more mistakes, devcontainers make it easier to get everyone on the same page, Typescript is incredible for so many reasons, and bundlers handle a lot of the minutiae of getting the right source code into the right destination.

And a big part of a software developer's job is looking at a list of things like that and knowing why each component is there in the list, and whether the value it adds is worth the complexity it adds. For example, in your list, I'd probably drop styled components and the macro toolchain, because tailwind on its own is good enough, and it's pretty easy to write your own components if you need to encapsulate styles somewhere. But you might be doing that a lot, so it might be a different tradeoff for you.

Which comes back to your question: why isn't there something that does everything? Well, because everything for the two of us will look different. You're using React and possibly Svelte, I'm mostly using SolidJS. You're using devcontainers, I'm not. You're using tailwind and styled components, I'm using tailwind and CSS/SCSS modules. A lot of people don't use tailwind at all.

The alternative is something more like Ruby on Rails where everything is preconfigured, but there are no choices any more - you use the tools and architecture as provided, and can't opt in or out of any parts. You don't get to try out Typescript until the framework authors have allowed it, for example. There are a lot of benefits to that style of framework, but it has issues as soon as you try to step off the beaten track. Like with anything, it's a tradeoff.

I think the other reason it's not that popular is that the current state of affairs isn't that complicated. You give a big list of things, but how hard is it to configure them? For a lot of stuff, the defaults will be good enough (for Typescript, I pretty much always just use the result of `tsc --init` but with isolated modules turned on). And the rest you've already configured - you can just copy the configuration from a previous project over. If you wanted to formalise that, you could create a template repo (and potentially publish it and get it to work with `npm init`), but that presumably depends on how often you're creating new projects.


This is a great comment!

I _love_ all of the tools that I mentioned. Like you said, I use them because they add value. I also use them because I want to learn them -- I like trying out new tools/libraries with personal projects, since I don't do much front-end at work.

> And a big part of a software developer's job is looking at a list of things like that and knowing why each component is there in the list, and whether the value it adds is worth the complexity it adds.

This is a great piece of insight. It's something I'll have to think about.

> I think the other reason it's not that popular is that the current state of affairs isn't that complicated

I do think that most not in the front-end space would disagree, especially considering how fast the ecosystem hops on something new.


The setup can be automated with bash script or "npm init <template-name>" or unzip from a template archive



There kinda is?

$ npm init vite


This is yet another case of people saying "JavaScript" when they mean "a bunch of Node ecosystem junk". Right out of the gate:

> It’s time for your test. You are sitting in front of a computer. The test is simple: you have to open a package.json file and read it.

And it continues in that vein. For all the stuff mentioned, there's actually almost nothing that has anything to do with JS per se.


About what percentage of JavaScript developers don't use NodeJS?

You are right that JavaScript !== NodeJS, but the majority of people would understand what the author meant.

It wouldn't hurt the author to be a bit more precise, but they aren't really wrong either.


> About what percentage of JavaScript developers don't use NodeJS?

I'm always surprised by developers who prefer to use Node on the backend.

I used Node for a small project. Never again.

No typing, requiring a couple of dependencies just to get poor, half-assed typing that doesn't really work anyway.

Poor dependency management, although this is probably not the fault of the tool, it's the fault of a poor ecosystem dominated by junk.

A primitive execution model, requiring hacks around hacks to get around the fact that the execution model is based on single-thread async execution.

Speaking of execution, slow execution too.

Limited IDE help (due to lack of typing). Difficult debugging tooling. No standardisation of anything.

The people using Node know that there's alternatives like Go, and yet they still patch on band-aid after band-aid and engage in drama.

Using Node for the backend is a special kind of hell.

I don't even like Go all that much, but it's a world of difference having strong static typing, nice dependency management, good tooling, simple debugging, no setup costs.

Someone upthread made the point about how they might burn a day just setting up a new Node project. A new Go project might take a few minutes from inception to "hello world".


Poor typing isn't a Node issue, it's a JavaScript issue. Use TypeScript, install @types/node, and you're ready to go. The rest of what you say is true. Although I actually do enjoy using Node for quick one-off scripts and small dev tools


My complaumtnis that typing shouldn't be optional.

With Node, not only is it optional, it's a third party dependency.


Again, that's not Node. It's JavaScript. You experience the same typing issues in any environment which runs JS (browser, embedded system, etc.).

If you want a good type system then you need to change languages and treat JavaScript as a compilation target. That's what most "JavaScript" professionals have been doing for years. Install the TypeScript compiler and a single dependency to give you Node-specific types and you're set


That's like complaining that Linux kernel doesn't have a GUI because GUI shouldn't be optional for an operating system.


> That's like complaining that Linux kernel doesn't have a GUI because GUI shouldn't be optional for an operating system.

Really? That's your defense of both not having type-checking AND not having optional type-checking builtin?

All common languages implementations, other than Node with JS, either have type-checking or have optional type-checking builtin.

Node and JS stand alone by having no type-checking, nor having optional type-checking builtin.

Node is uniquely low-quality in this respect.


All other operating systems implementations have GUI, and Linux doesn't.

Seriously though: modern JS ecosystem is not a "language" or a "framework". It's a kernel. You can choose your own language, whether it's Typescript, Coffescript, Purescript, Clojurescript, Reason or one of it's sublings, Elm, or pure JS. Of course, like with Linux, this can be a good or a bad thing for different users and circumstances: personally, I like Linux, but I don't want to handle all of this complexity on my own desktop.

And just like with Linux, you have to choose your own implementations for everything: testing library, strings, dates, templating library, state management, web server, etc.

If you're comparing the barebones Node and vanilla JS to other languages and frameworks, you're not making a valid comparison. You can't pretend that something is inferior just because it's modular.


> All other operating systems implementations have GUI, and Linux doesn't.

You "two other", right? I've used many that didn't have a GUI.

> Seriously though: modern JS ecosystem is not a "language" or a "framework". It's a kernel.

That's not how it's pitched.


> You "two other", right? I've used many that didn't have a GUI.

Good point, however, I don't think it makes the analogy invalid. You can replace "GUI" with "init system" or any other thing that separates OS kernel from a full-fledged OS.

> That's not how it's pitched.

There's truth in it. However, I think that the problem here is that we might have different expectations of what a "language" is. For some, it should be a complete package with all libraries and tools built-in — like go or Python. Racket even comes with it's own standard IDE. For other languages, like C, not even standard library is something expected, it's very basic and it's implementations are platform-specific.

Yes, if you take the basic Node, it will not have Typescript included. And for a developer that comes from a different background modifying your "language/framework" is something so weird and out of the ordinary that you don't really do that often. So you might inclined to judge Node ecosystem by your habits, but that's a mistake.

Just as with leftpad, developers from other ecosystems were in shock to find out how many small dependencies does a typical Node project have — because including a dependency is an expensive thing in their experience! But with Node, it's not. I can build and run a typical Node project with hundreds dependencies ~10 minutes after I clone a repo, but it takes me a few hours to configure the right version of Python, requirements and native C/C++ libraries for any significantly complex Python project that has a lot less.

So, instead of comparing the "type checking" out of the box, compare two reasonably sized projects after a year of active development by 5-10 person teams. And from my personal experience, a modern Typescript project would eliminate a lot more failure conditions at compile time than any other mainstream language.


That's ironic, because as a fullstack developer, I don't want to touch Go exactly because of it's lacking type system and how it manages dependencies.

Typescript has the best type system among modern mainstream languages, and although you're right that Node is not well suited for CPU intensive applications, the most part of backend work is IO bound, where async/await works perfectly — waiting for reply from the bd looks and works much more natural than with Go's primitives.


Typescript type system is both powerful and lacking, and with a syntax that is horrendous to do anything complex. It gets even worse than regex in the "write-only" direction. And you can do black magic but at the same time very basic things are still not possible. I would argue that the Python type system is actually better because you can build on it with regular Python instead of typescript weirdness and because you can use it at runtime. The fact that typescript does not support any kind of reflection makes it very limited for a script language. Rust type system on the other hand is also limited in refection but it is not a scripting language so it's more acceptable, and at least it integrates very nicely with features such as pattern matching and control float which you don't have in TS. TS also has a way too complex option list which is becoming nearly as annoying as ESLint to configure, with basic safety disabled by default and rules that are just annoying and add no safety whatsoever in the "strictest" config.


Can you please provide examples of what do you consider "write-only" types? Because so far what you've described is the exact opposite of my experience as a Typescript developer.

As far as reflection goes, I see how it could be useful with other languages with less powerful type systems, for example, to build a deserialiser. But with Typescript's type inference I just never felt the need to reach for a crutch when I can use a proper solution.


> Typescript has the best type system among modern mainstream languages,

I wouldn't call something the best when it's disabled by default, even after considering the fact that it's neither part of the language nor the platform, and needs multiple dependencies in order to run, at which point it has worse type-checking than every other language.


TS's type system is nice but to call it "the best type system among modern mainstream languages" is a bit of an overstatement.


I would say TypeScript is second only to Rust


Check out Scala's type system. I don't think you'll miss anything that TS can offer there.


> No typing, requiring a couple of dependencies just to get poor, half-assed typing that doesn't really work anyway.

I'm not sure when this experience was. I've used TypeScript for years. About 5 years back it was okay, but it was very hit-or-miss for a given library to have types.

Today, I haven't had that problem. Every library I use has _great_ types, and many libraries are even written in TypeScript.

Anyway, all I'm saying is that you might want to give it a second change. TypeScript and the ecosystem has greatly improved. I hate working without static typing (Python, JS, and Ruby are pain), but TypeScript is really quite great.


Hello there - that's what I've been doing lately.

Applications by and large do, but when you're writing a library you want to at least start without the usual bs.

JSDoc for type information works great as a crutch in this initial period.

EDIT: ok, now I recalled that I use Node's built-in test runner for tests. But I still don't have a package.json as well as any dependencies.


Right, the ecosystem is not a valid critique of the language, got it.


Try writing any JS without a bundler that uses package.json. I mean really, try it. Until ECMA codifies a package manager or bundler in the official specs, package.json is de facto part of JS.


> Try writing any JS without a bundler that uses package.json.

I have, and I continue to. It's not hard.

To give one example: Firefox, a serious desktop application by any measure, was written in JS from the very beginning. (Yes, really. A combination of JS and C++, at least—and, nowadays, Rust, too; not unlike the way that Emacs is written in Lisp, where that means a combination of Lisp around its C core.) That's hundreds of thousands of lines of JS we're talking about, and it predates Node and all of the bundler/package.json stuff that you are implicitly arguing is somehow unavoidable. Firefox is an existence proof that that's not true (and also happens to be a higher quality app than anything I've ever seen the Node community offer as example to serve as testaments to their methodology, including anything to do with Electron, which cribs the same Greenspun, Emacs-style architecture that's behind Firefox).

I worked on the JS docs on developer.mozilla.org in the early days of the site. (Also before Node ever existed.) I did this because I wanted people to understand JS. It's a much nicer—and more thoughtfully designed—language than it gets credit for. It pains me, therefore, when I see people refer things as JS when what they should be saying is "stuff associated with the kind of software of dubious quality that developers who decided to rally around NPM have been putting out into the world for the last decade—and more often than not actually goes against the natural grain and spirit of the language".


> I have, and I continue to. It's not hard.

I also write JavaScript code without NodeJS and package.json. It's not hard when the code is simple. But it doesn't scale. For a complex code, I want a linter, I want automated tests and coverage, I want to split the source code over many files... NodeJS is the standard requirement for all of these.

> Firefox, a serious desktop application by any measure, was written in JS from the very beginning. (Yes, really. A combination of JS and C++, at least

At the very beginning, this web browser started under the name "Netscape", and JavaScript didn't exist yet. Mozilla forked out of Netscape in 1998, and there was little JS in the source code at this time.

> it predates Node and all of the bundler/package.json stuff that you are implicitly arguing is somehow unavoidable.

Firefox doesn't use the standard bundlers of the Node ecosystem, but it's because it has its own build systems and bundlers. It's a beast that needs 30GB of disk to compile, with a custom build system written in shell, Perl and mostly Python, with many tests systems (including for "mochitest" JS code).

For instance, among the dozen of linters that Firefox uses, there is eslint, which a normal JS project would install through a package.json.

> JS. It's a much nicer—and more thoughtfully designed—language than it gets credit for.

JS was notoriously designed and implemented in a rush, because Netscape was under pressure from Microsoft. It also suffered from legal constraints that block the adoption of some Java concepts. Once LiveScript/JavaScript was born, its evolution was chaotic since the browsers war prevented any consistent progress of the language. After it settled, Ecmascript did enhance the language at a fast pace, but it cannot fix the many inconsistencies and design flaws.


> At the very beginning, this web browser started under the name "Netscape", and JavaScript didn't exist yet. Mozilla forked out of Netscape in 1998, and there was little JS in the source code at this time.

I have no idea what point you are trying to make here. Firefox—not Netscape—has been a JS-driven app since its very first day of existence. (Netscape Navigator 6.x, which has nothing to do with Netscape of the early-to-mid 90s, is the same way—but that's beside the point: I said Firefox, and that's what we're talking about.)

> Firefox doesn't use the standard bundlers of the Node ecosystem, but it's because it has its own build systems and bundlers. It's a beast that needs 30GB of disk to compile, with a custom build system written in shell, Perl and mostly Python, with many tests systems (including for "mochitest" JS code).

I don't know what Firefox's build system looks like now, but at the time that Node debuted (2009), Firefox 3 was the latest release, with Firefox 4 development underway. It did have (and always had) a pretty gnarly build system made of shell scripts, Perl, autotools, et cetera... the same as almost anything that involved reliably compiling a large project with C/C++ across many distros (not to mention other platforms), which was the entire reason behind it. The use of JavaScript, however, had nothing to do with that; there were no JS bundlers. You brought symbols in scope by adding a script element. You still can.

This is also how WebKit's inspector is written to this day, last I checked (~6 months ago or so).

> JS was notoriously designed and implemented in a rush

Again, no idea what point you're trying to make here. JavaScript was done in a rush. It's also thoughtfully designed—certainly more than it gets credit for—and more than other languages that had more time (and less of an excuse). And it remains pretty nice, popular misconceptions notwithstanding (and not helped by self-loathing/self-sabotaging developers from the GitHub era like the author of the submitted article).

> But it doesn't scale. For a complex code, I want a linter, I want automated tests and coverage, I want to split the source code over many files... NodeJS is the standard requirement for all of these.

Hard to cover this succinctly given how much weird stuff is packed in here.

Hundreds of thousands of lines of code of higher quality (and subject to harsher requirements) than the Node fanclub has ever produced is proof that JS scales.

Testing is a basic engineering concern and common across the industry and across all languages. It's a completely orthogonal issue.

Lint as much as you like if that's what you want. Neither Node nor the Node way of development are in any sense a requirement.

For having source code "split [...] over many files", whether you use Node or not (or follow their fads) is neither here nor there...


> opens dev tools > types `console.log("this is impossible without a package.json")`

To my astonishment, it worked, without a package.json file.

I definitely prefer using npm for any non-trivial front end, but let's be real: JS is an integral part of the web stack. You can even inline JS inside a <script> tag on an HTML file. It's not that hard.


I do sometimes wonder how many of the critics have only ever worked on Angular frontends and such. The frontend for my little site https://bongo.to doesn't use Node or NPM at all. Just a script tag, like you said. It's very simple and easy to use JS this way, and I wish people would learn to do this before learning how to write a SPA in the framework du jour.


`<!-- prettier-ignore -->`

You run prettier though? How do you download and run it - it seems to require Node.


you can run it with the `npx` command if you didn't want to install it. another way, which is the one I'm using here, is via the VSCode plugin. enabling the "format on save" option with prettier as the default formatter will format any file it can, which is very handy!


You know we used to write javascript before JSON existed, right? Let alone node and package managers.


I’ve been writing JS my entire career and never wrote a package.json file. I’m not sure what tool would even use it.

But then again, I’m a happy, sane person who only writes client-side JS.


> I’m a happy, sane person who only writes client-side JS.

I've never written backend javascript. I've used and fought all the tools mentioned


how do you manage large projects?

what happens if your project has tens or even hundreds files, how do you get that to client without any sort of bundler?


Why would the project have hundreds of JS files? Usually I might have something like main.js which handles universal page elements like the search bar in a site-wide navbar, then, if necessary, a few this-specific-page.js files which handles elements which are specific to this page or site section. If any libraries are needed, try first to just link them in using CDNJS or the like, so no need to store them locally or bundle them in our own scripts - I know there are downsides to relying on external CDNs for such things but in practice it just works. Easy peasy.

But first, I try to avoid using JavaScript in the first place when not strictly necessary. This means server-side rendering as much as possible rather than doing the glacial "load an almost entirely blank page, load giant JS blobs, then load the page content via AJAX and hope that nothing goes wrong in that process, sorry slow connection users, non-standard browser users, and search engine bots" approach which thankfully is finally starting to see some pushback.


Here's what the person you're responding to said:

> I’ve been writing JS my entire career and never wrote a package.json

And you replied:

> how do you get that to client without any sort of bundler?

Please connect the dots for me.


You can use modules directly in the browser and it will load them in fine. You don't need to use a package manager do to that: https://byexample.xyz/javascript/ECMAScript2015/modules/#dir...

I have never used a package.json file in my 10+ year writing javascript & typescript. We don't have nodejs installed on our workstations or servers. A lot of work has gone into that build chain, and I have no idea what it is doing (apart from something something bazel & monorepo) but it works.

At home I use Deno and it is a joy.


I’ve done it since the mid-1990s. It really isn’t that hard.


Deno. Write code in TS. Built in linter and formatter.

Bundle with packup: https://packup.deno.dev/


If that fries your pickle, whenever anybody says JavaScript, I think they really mean ECMAscript.


Is that distinction really significant? I know JavaScript is a trademark owned by Oracle, but in practice it is used interchangeably with ECMASCript.


They absolutely do, and I honestly get annoyed when ECMAScript gets misnamed. If you're putting a virtual machine with pseudocode into my browser, I want your applet gone.


[flagged]


None of these semantics actually exist. Javascript is the language, and it was released as an implementation first, then a standards body worked on a specification for it. For various reasons (bickering, trademark), the specification was called ECMAScript. ECMAScript is the specification for Javascript. That's it. There's nothing clever to be had here, it's just odd historical trivia.


I'd just like to point out that the parent is a variant on the GNU/Linux copypasta: https://stallman-copypasta.github.io/


I'll allow it. Downvote removed


I always thought, inaccurately, that Javascript was simply the 'navigator' object and a few other objects, glued into the namespace.

I did not know that it was standardized, though .. duh .. it would have to be I now realize.

TY for the interesting comment @Freedom2, it's informative for me.


Um yes.

It's a critique of the JavaScript ecosystem.


> the JavaScript ecosystem

We just covered this.


What tools/package managers/linters do you consider part of the JavaScript ecosystem?


There's nothing mentioned in the submitted article that isn't part of "the JavaScript ecosystem"—because everything it mentions is the product of the outgrowth of Node, NPM... and that subtree exists within the JS ecosystem. But to narrowly focus on that subtree and say it's "a critique of the JavaScript ecosystem" is like visiting McDonald's and passing off your experience as a meaningful critique of the ritual of ordering food and eating it, or writing an angry blog post about the chicanery of some nincompoop your cousin knows while implying that this is what you should expect when you interact with anyone else named "Steve". It's a shameless generalization that's both stupid and unnecessary.

If you have a grievance against The Node Way of software development and you want to air it publicly, then have enough of a sense of awareness that that's what you're doing—and say as much when you do it.


> because everything it mentions is the product of the outgrowth of Node, NPM... and that subtree exists within the JS ecosystem.

Where subtree constitutes ~90% or more of the ecosystem.


Yeah? Have you measured it?

Aside from that, do you have anything meaningful to say about the points actually raised? Let's take your claim as a given. If it were 2003 instead of 2023 and people kept bringing up, say, problems with Windows but refused to speak about them in those terms—instead insisting on framing with a generalization about "computers"—would that have been acceptable on the basis that 90+% of the world is using Windows? It plainly wouldn't have, and that's true for a case where we actually know that we were dealing with numbers of 90% or more, and not just lazy attempts at retorts that are fired from the hip and by a reasonable guess probably won't actually hold up under scrutiny, anyway.


> Aside from that, do you have anything meaningful to say about the points actually raised?

You didn't raise points. You went off on a rant by completely dismissing the tongue-in-cheek article about tooling issues in the frontend space as something about "node-only".

All the points the author raised are:

- about frontend aka client-side

- about javascript ecosystem

And this ecosystem is ubiquitous. Much more ubiquitous than "no, this is not frontend, I do client-side and I don't use it".

> If it were 2003 instead of 2023 and people kept bringing up, say, problems with Windows but refused to speak about them in those terms—instead insisting on framing with a generalization about "computers"

See? This is not a point. This is argument by analogy. You're pretending that this analogy is valid (it isn't) and you're expecting me to argue with you.


> this ecosystem is ubiquitous

I wrote a perfectly lucid response which you ignored completely. Your choosing to ignore it, or to read it as if it means something other than what it does, does not mean that I don't have a point (wat).

> Much more ubiquitous than "no, this is not frontend, I do client-side and I don't use it".

Who are you quoting (and what is it even supposed to mean, besides)?

> you're expecting me to argue with you

Nope.


> I wrote a perfectly lucid response which you ignored completely.

I wrote why, and you definitely literally ignored what I wrote.

> Who are you quoting (and what is it even supposed to mean, besides)?

I'm very shortly representing what you wrote. So it's for you to answer what this means.

> Nope

Yup. Otherwise you wouldn't resort to bad analogies.

Anyway. This is going nowhere.

Adieu.


> I'm very shortly representing what you wrote.

No, you aren't—and the point at which you are attempting to explain what it is that I really meant or was thinking (explaining me... to me) is the point at which you have stumbled upon a strong indicator that you have lost the plot. Viz:

> Yup [you are expecting me to argue with you]


I appreciate the playful tone, it's good to be reminded of these pain points after the first few layers of skin and nerve endings have burned away.

On the flip side, I can throw a hungry junior dev with a new macbook into the deep end, and they can be productive within a day. They don't have to know anything about containers, .net, nginx, or the top 100 most common command line tools. When they hit an issue they can just google it.


On the flip side, I can throw a hungry junior dev with a new macbook into the deep end, and they can be productive within a day.

Indeed. The irony is that the trade off you’ve made means that you can throw a senior dev with 20 years of experience building things that run in browsers, and he wont be up and running in a day.

He’ll be fighting all the unnecessary layers of complexity to modify this ship-in-a-bottle with the fiddly tools provided, knowing that he could have built the entire ship in a few days if he could just touch the thing with his hands.

At least that’s what I feel like dropping into Modern Frontend gigs after sprinting along on my own projects that use javascript, html and css.


Add to that any traditional server side template rendering like Jinja or Django templates, and you can implement probably 90% of today's SPAs in simpler terms and actually working browser staples like the back and forth buttons.


yet the devil lies in that last 10%


If your project doesn't actually need anything more complex than basic JS, html and css, you don't need those layers of complexity: you can create a new package.json based project and be productive in 5 minutes.

However, if you are thrown into an existing projects that does have all of these things, it's usually because they're actually necessary.


> However, if you are thrown into an existing projects that does have all of these things, it's usually because they're actually necessary.

That is almost never true.


Everyone's experience different. Of course, if you're building a static blog, you don't need React on the front-end. However, my experience was mostly with interactivity-heavy applications, where all of these tools are not only indispensable, but often arguably not heavyweight enough.


> Everyone's experience different.

This is such nonsense. Not everything is subjective or "an experience". There is objective truth is the world and the objective truth is your previous statement is almost never true. Unless you're operating at FAANG levels, that is, which almost nobody outside of FAANG is.


At which point they'll spend the next day or three smushing something together that they'll regret for the next ten years, and then write something like this. The cycle continues.


The juniors I know will go:

“Let me create a framework to handle this complexity”

Blissfully unaware that it would take them months to write that, and it would be obsolete the next day, because part of the problem is too many frameworks.


> When they hit an issue they can just google it.

Now they chatgpt it.


And get unreliable results from a stochastic parrot


I regularly find chatgpt to be better than googling for code related stuffs.


I think that speaks more to how much Google search result quality has plummeted over the years more than its suitability for the task.

> regularly

The trouble lies in the credible sounding results that are in fact subtly (or less subtly) nonsense.

It's a bit like old W3schools but instead of poor practices, its authors were half-in-the-bag


I’ve no problem distilling those! I find stackoverflow and co to be of worse signal:noise


Edit: this is getting a lot of downvotes but it is important information. ChatGPT with GPT 4 ($20/month) is an artificial intelligence that can save hours of your time and help you debug things you couldn’t without it. It really understands code.

While I will take a 4 point karma hit from downvoters who don’t know how to use ChatGPT, this information is very important to share with all programmers.

>stochastic parrot

This is incorrect. In the context of learning JavaScript, ChatGPT with GPT 4 ($20/month) can analyze any error if you give it the error and the code, or you can just describe what’s wrong and give it the code you wrote and it will analyze it and tell you how to correct it, even if your code is the first time anyone has done that. It might take it two tries but it’ll figure it out. It obviously understands what you tell it and follows your instructions pretty well.

Limitations: the code you give it has to be small; ChatGPT doesn’t scale to larger codebases.

Second limitation: if you happen to be a world expert in something, then it might have trouble understanding - haha, just kidding: if you are the best human expert in the world, ChatGPT is still smarter than you and can still fix errors you can’t fix.

Rather than a stochastic parrot, it’s the best debugger on the planet.

In fairness you are correct that ChatGPT is unreliable.


"I followed the instructions and it said I didn't have grunt installed. Now I'm an old guy so I didn't really know what grunt was and my grunt files weren't right or something. So I googled a bit and I found out what grunt was. Grunt's... I still don't really know what it is." --Joe Armstrong, https://www.youtube.com/watch?v=lKXe3HUG2l4

The other day I ran `gem install wayback_machine_downloader`. I never liked Ruby the language enough to get into its ecosystem, but I note that said ecosystem has from an outside perspective remained remarkably stable. gem is still the thing to use (dear god Python what became of you), Rails is still around... I'm waiting to work on a new project with a complex enough front-end that justifies more than 0-30 lines of JS, then I can be happier with HTMX instead of whatever giant framework is most popular these days.


This is not about javascript, this is about npm.

I detest npm and avoid it at all costs preceisely because of all this junk (personally I use Deno, but at work we use something like bazel with a monorepo that means we don't need npm), but I find Javascript/Typescript a lovely language to program in and it is my absolute number 1 goto language for anything.

It makes me sad when people say "javascript sucks!" but actually they mean that using npm to build react applications suck. Modern Javascript/typescript is an absolute joy to code in.


I agree. I am working on a video game and decided to use no dependencies (at all!). It has been such a joy to code.


I’ve been writing a bunch of GitHub actions lately and immediately fell into the habit of just using someone else’s action in each step.

I went back and rewrote almost everything to remove dependencies and I just write little shell scripts to do what I need rather than relying on someone else’s little shell script that hasn’t been touched it 2 years.

The fewer dependencies, the better I can sleep at night.


https://github.com/cmctec/ci-workflows/blob/main/.github/wor...

This is my shared workflow which I apply to few dozens of projects in my company. Works like a charm! Extremely simple and understandable script. Build times are mere seconds (when cache works).

I tried to understand this whole github actions stuff but decided that I don't need all that complexity.


It feels as if JavaScript (and its ecosystem) has left us all with PTSD that makes us unable to appreciate the comedy on this post. So much “serious” discussion around a funny piece. Feel free to dissect it as you may, but keep in mind its true intent: humour.


Just because it’s humorous doesn’t mean it’s not serious.


I will be honest, the first ecosystem I started in was node, and I absolutely think that those that I learned later had their insane share of issues too.

Haskell has proven very hard to use cross machine, installing it on MacOS in 2019 was painful, the ecosystem is painful to handle, there's a huge macro/extension confusion, language isn't very retro compatible while you can generally expect 2010 JS to work in 2023 out of the box.

Even creating a full fledged docker image, codespace/gitpod-like proves difficult, the base one provided by GitHub kinda sucks and has issues.

C has proven generally okay to work on most platforms but the language is honestly complex and the sheer amount of knowledge of systems (in all possible meanings of the word), produces non-portable code that doesn't fit most usecases of general programming.

I could go on, but everyone who has tried several languages knows that we all suffer and will always suffer with several shortcomings in all kind of ecosystems.

Php has always been one that I've never got to setup a project in less than few days.

Elm is the less painful but the ecosystem suffers from its own degree of benevolent dictator's state and rate of development.


This is pretty much why I go to great pains to use Go for everything, even if it's not the best fit. It has minimal yak shaving


Is C complex? It's probably the one language that I can keep in my head regardless of usage frequency. Parts of modern JavaScript syntax evaporate from my memory easily and I write that language daily.


I guess it's not so much the language that is complex. Indeed, it's pretty simple for the most part (although there are archaic warts few people ever need and modern features that sometimes feel like C versions of C++ features). But the result has some emergent complexity because of the simplicity and lack of guarantees. When every line coupled with an antagonistic (i.e. optimizing) compiler has the potential to bite you and you no longer think about the apparent semantics of your code, but rather the semantics guaranteed by the C abstract machine that no one actually really knows, I guess the result is not very simple anymore.


I wouldn’t say it is complex, but since it is relatively low-level it doesn’t insulate from a lot of things that other higher level languages handle for you. Like the fact that an int has different sizes depending on the compile target. Or that one must remember to call this one function before calling this other function, otherwise Bad Things Happen (but it might only be visible way later, in production).


I'm a polyglot developer who likes to think they're comfortable in a wide range of programming paradigms and languages across both frontend and backend.

This is pretty much exactly my reaction any time I see a package.json longer than ~20 lines.


stairs glaringly at the new Angular front end we're developing that has four seperate front end components, each with package.json files of 200+ lines

Speaks out loud, hoping to keep the demons at bay.

“I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.”

cries


Very in tune with the reference of the articles title.


Same. But commenting to make an off-topic remark: the link in your profile is blocked by uBlock Origin and leads down a rabbit hole of strange websites. Since I never used hackernewsers I can't tell if it's working as expected, tbh


Huh. Thanks for the heads up. Used to be a useful service but apparently the domain expired and was replaced by spam.


[Old school JS developer reading the article and suffering PTSD and flashbacks]

I must not fear.

Fear is the mind-killer.

Fear is the little-death that brings total obliteration.

I will face my fear.

I will permit it to pass over me and through me.

And when it has gone past, I will turn the inner eye to see its path.

Where the fear has gone there will be nothing.

Only I will remain.

[Finishes reading the article and realizes they survived, but now all sweaty]


JavaScript tooling it bad. So many half-ready choices. I tried to set up TypeScript project for last few days. It's a major pain. I originally wanted to use multi-module project: 1 node.js server, 1 webapp and shared code. I spent too much time trying to figure out all those things, TypeScript moduleResolutions and whatnot just to throw it all away. To hell with it. Yesterday I tried to understand how would I generate type-safe server code from OpenAPI spec. No way. zod, yup, ajv, wtf, but just dumb simple openapi generator which can generate code even for Ada, but node.js does not exist.

I love TypeScript, I love node, but I so much hate all the associated tooling. It's incredibly terrible. I don't want to make a single choice. I want a single build system which does everything good enough. I want a single "Spring Boot" framework which does everything good enough. I want a single linter, which built into my IDE and does not require me to exclude my dist folder. I don't want to configure my TypeScript compiler, it should be smart enough to configure itself. I don't want to spend days reading about project references, npm workspaces and other stuff. I want to create few folders like I do with maven and it's just works. I don't want to browse 10 different libraries for typings (why is it even needed for typescript???). I want things like JSON parsing and validation to be built into language or stdlib.

I hate go language. But their tooling is so right that I can withstand all those `if err != nil` every second line.


[dead]


It is client API. I was talking about server API. For example express.js or fastify-based.


[dead]


Thanks for pointers. I'm afraid, that's a bit wrong direction. I'm talking about spec-first development. This project generates spec from sources.

For now I think I'm going to use zod, as it seems popular enough and pragmatic enough.


What would be the minimal but modern setup to develop web apps that use javascript to good effect in conjunction with an agnostic server stack.

I am intrigued by "less js is more fun" approaches like htmx and alpine.js but that still leaves a range of options on how to organize things and some may bring you dangerously close to what OP describes.


Almost all of the painful stuff in that post is due to migrating from tool to tool. (“Both main and browser fields are present”, “This has something to do with the migration from requires to imports”, “Subcommands calling npm even through you switched to yarn and then pnpm”, “Some scripts still use watchman … There’s also this gulp-based script that nobody has the guts to replace”, “There’s also moment.js … you have to migrate to date-fns”, “these packages are way behind [current] … you should upgrade them … [you] have tried that before and you know how much suffering it brings”, “resolutions … a suffering you choose to avoid dealing with package upgrades”, “jest … depends on some babel packages while the rest of your app is transpiled by a mix of esbuild and swc”.)

Ironically enough, the last paragraph of the article? About hating node while refusing to switch to bun or deno? That kind of decision might have prevented some of the pain mentioned in the previous paragraphs.

I don’t have an object-level answer for your question, and I’m not trying to mislead you into thinking it’s possible to actually have a minimal setup for JavaScript web apps - it’s always going to be painful. But with a commitment to maintaining minimalism you can pick a stack to start with and mostly keep it that way. The grass might be greener on the other side, but the fences are made of razorwire!


I would also love some sincere answers to this question. I'm mostly a back-end person, but would love to start building some front ends that don't look quite so 1997-ish. But each time I think, "Gosh, I should learn whatever the current thing is," a) it's different than the last current thing, b) it seems to be pretty volatile in terms of frequent changes, and c) smart people have some really good critiques of things that are fundamentally wrong with it. And I feel like I've been having that experience for a decade.


Just find a basic CSS library and use server side templating in whatever your preferred language is.

As systems evolve, they always get more complex. Web front ends are evolving to keep up with users, app archetypes, and business needs. People choose tribes to identify with, angular vs react vs vue. People are ambitious and pushing their own frameworks while tearing down others. Its just programmer politics, no different from windows vs linux vs osx.

I learned react, stuck with it, and it has worked out.


Same situation.

Had to choose a test for an interview. Some UI required.

Ended up using Blazor Server, got it done..


Just a .JS file. Oh, modern. Sorry, nothing but unnecessary complexity and suffering is allowed in modern dev environments.


Was meant to be a serious question :-)

There must be a sweetspot of tools and designs that helps organize a modest code base to get the benefits of reusability and readability without too heavy a penalty.

Imho frontend people gladly walked into the trap of "excess complexity" as this elevated this niche into a "serious" business. Whenever some aspect of tech doesnt make sense, follow the money and this usually clears things up.


Native DOM APIs are a lot nicer than they used to be. Just JS will work just fine as long as you're comfortable building a whole UI yourself. You can sprinkle on Typescript for static types (which I wouldn't do without for any serious project, myself), esbuild for bundling, then serve it how you like.

The issue you might run into as you scale up is managing the state and synchronization of a large, complex UI. This is where having a reactive, declarative interface can help out a lot - which is why you arrive at React and tooling around that, or something much like it. That's where most large UI projects end up, frontend or backend.


Don't know if it's still a good approach but a few years ago I used Preact with htm without any build tools for a project. No compilers, bundling or package managers, on my part. (Preact and htm were, of course, pre-compiled and bundled so that might be a turn-off with this approach.) The Preact devs provided CDN links to add to your app but I decided to just download the two JS files and host them with the app's files. My only gripe back then was that the bundle for the Preact hooks library somehow had a CDN location hard-coded so I had to decide between using the CDN but having hooks or using class-based components but having it all local.


> Native DOM APIs are a lot nicer than they used to be.

You must be joking, Mr. jrajav :)

Native DOM APIs are just as bad as they always were. Because they are stuck in the 90s era of heavy imperative APIs.

There are a handful new additions that are somewhat nice, but all of them either underdesigned, or with warts you need to be aware of (querySelector, querySelectorAll and native fetch come to mind).

Building a UI from scratch with them is just as cumbersome and awkward as it was in the early 2000s, and you'll end up re-implementing half of jQuery at least in the process.


I think React via Vite.js is pretty great. Takes a few seconds to get started with very few direct dependencies. It is fast and easy in my experience. For an API server, use whatever you like. If you want SSR, check out Remix or Nextjs... but that is going to be a little bit more complicated.


The best experience with frontend JS I've ever had is the following setup:

1. Use npm. Well, I didn't try yarn, probably it doesn't matter.

2. Use vite. It sets things up good enough and pulls only 15MB dependencies. Tiny!

3. Use TypeScript. I can't imagine writing untyped code.

4. Use eslint to complement typescript checks. Takes some time to set it up first time. Use default rules, they're good.

5. Use prettier to format code. I use vscode and with corresponding plugins, it just gets out of the way. It's good thing to have and works with minimal setup.

6. Use react. Well, it's pretty much standard nowadays and things are mostly fleshed out. But it's pretty complex so beware of steep learning curve. But once you learn it, it's not going anywhere. At this point I consider react a fundamental knowledge, worth spending time to learn.

7. For state management use react-query (yes, that sounds strange).

8. Use built-in to vite methods to access CSS (I think it's called module CSS).

9. Don't add any more dependencies unless you absolutely feel like it. Don't add CSS frameworks or things like that, just write your CSS by hand.

This was the least pain setup I ever had and I consider it to be minimally viable.


> 1. Use npm.

Better use pnpm, faster for those that don't have 1 Gbps uplink and live outside the usa.

> 3. Use Typescript

Better use jsDoc, d.ts files are scary and are really complex, you need a typescript wizard la matt pollock just to tell you are mistakenly trying to concatenate a string and int.

> 5. Use prettier

yes use prettier but don't forget to configure eslint to work with prettier otherwise you are going to have a bad time.

> 6. Use react

Use whatever fits your problem but if you are going to really use rect then do it with Next.js, no point in still using CRA/CRACO

> 7. state management

Avoid using state, try to solve every problem with pure functions, if you must use state then consider redux/react-query

> 8 & 9.

You should still recommend stylelint, specially if you are going to write css by hand otherwise don't just use tailwind, tailwind is bootstrap with extra batteries (change my mind).


> yes use prettier but don't forget to configure eslint to work with prettier otherwise you are going to have a bad time.

Can you elaborate? I'm using eslint and prettier with pretty much default settings and never had it conflict with each other. My impression was that they work on different aspects. May be there're some overlapping eslint checks, but they're not enabled by default (or I didn't stumble upon them yet).


Depends a lot on what you are doing but mostly stylelint is the one that make me look on configuring eslint/stylelint for prettier...

https://prettier.io/docs/en/integrating-with-linters.html


> Better use jsDoc, d.ts files are scary and are really complex

Why would you use d.ts files and not just... .ts files?


When you want to integrate a javascript module that isn't annotated with types... types in a dynamic language like javascript are complex once you start doing really abstract things like generics the fun of typescript ends, also there is a recent push to abandon typescript mostly fueled by svelte fan base but nevertheless typescript is really complex, easy to shotgun yourself.


The whole point of explicit complexity of Typescript is to prevent you from shotgunning yourself from implicit complexity of Javascript.


And thats why it isn't worth, you are adding complexity to a problem that doesn't need to be complex, jsDoc is the best of both worlds, type safety, zero complexity and it works with typescript (if you still really want to use it).

Personally i think typescript isn't going to be around much time on the frontend side, maybe on the backend by some people that still believe in adding another compiler layer to their build time.


Angular is "batteries included". Many applications I have worked on have just angular as the single dependency, everything else is business logic written just for that app, so you don't need package.json since there are no other dependencies to manage.


I’m going to be learning more about HTMX & friends myself.


I'd suggest taking a look at Deno it has most of what you need, batteries included.


There are projects attempting to do more things. I've really enjoyed Parcel (https://parceljs.org). But it won't handle things like linting or unit testing, which you may or may not want. Vite is also pretty popular (https://vitejs.dev/), and it has a test runner.

Thing is, most of the problems described in the post aren't related to low-JS front-end libraries like HTMX or alpine. You can write React without a linter, bundler, build tool, unit testing, or linting (or dependency manager, for that matter!). But with any of these projects at scale, you start wanting more:

- If you want to write unit tests in JS, you need to choose a test runner (probably Jest or Vitest -- until the built-in node testing module becomes more common).

- If you want linting, you need a linter (probably Eslint). If you want type safety, you need a type checker (probably Typescript).

- If you want to create smaller JS files to ship to production and to automatically handle assets, you need a bundler.

- If you want to use new language features while supporting old browsers, you need polyfills.

- If you want to use all these things together, you need something to bring it together (like Webpack).

So it really depends what you need! You may not need any. But as you can imagine, in many professional projects with multiple developers it's very nice to have unit tests, linting, and type checking :) (And you start caring about end-user performance a lot more, in which case optimizing the shipped bundle is important.)

Take all that, and then compare to a language like Rust, which has most of the "ecosystem stuff" built-in. In Rust, you get the test runner, the linter, dependency manager, type checker, and documentation tool all included. Easy! Thankfully, Rust doesn't have to care about whether users support modern language features (because it compiles down to lower-level code ahead of time), or whether the binary shipped to the client is optimally organized for downloading immediately over the internet.

It's a problem in JS because A) you have to care about more problems than many other languages since JS needs to load instantly over the wire in a web browser, and B) there is a huge amount of choice and not a lot of standardization in web tools. (And what standardization there is (Node, npm), there are still competitors trying to even further reduce the pain points.)

I think that in ten more years, we'll be in a better place, because there is push back (like this post!) against these problems, which will encourage more tools trying to solve the explosion of tools. Which seems counterintuitive, but these tools were created to solve very real problems. So I see it as a pendulum which has swung too far, but will likely swing back to a more balanced place. And you see that with tools like Vite gaining popularity.


Just js is evergreen.


>The type is set to module. This has something to do with the migration from requires to imports. Why do we have to care about this, again? The extensive pain you’ve experienced trying to importing ES5 modules from ESM modules and vice versa overwhelms you again.

Would anything truly have been lost if Node simply ignored ESM?

The half-measure seems, abstractly, worse than announcing that Node was all-in on ESM, deprecating CJS by a certain LTS release, as the end-user has no real notion of the ultimate destination of ESM in a Node project; what is the struggle for?.


Jarred says it best: https://bun.sh/blog/commonjs-is-not-going-away

- 75% of NPM is CommonJS

- It’s better for lazy loading / cold start outside the browser than `await import(…)`


ESM has nice things too, like top-level-await and strict mode by default. Explicit imports/exports are better for autocomplete when TS is unavailable.

I think the ESM slowness can eventually be compensated for but it will need spec changes. Possibly the defer import proposal.

But yeah, CommonJS is basically never going away.


Progress, the one thing JS has too much of, too quickly, without stabilizing for quality.

There are a number of benefits (see the link below). We could argue JavaScript shouldn’t be isomorphic, as it barely does its job well on either end. Node might in fact be better off without the ‘pollution’ of client-side packages, but well…

https://www.reddit.com/r/node/comments/rby64z/why_esm_what_d...


> Progress

It's lack of quality.

When you have a badly designed layer, you have a lot of problems to progress over. And each bit of progress creates a whole lot of new problems you can solve with further progress.


Thing is, Browser JavaScript projects tend to implicitly rely on CJS hacks, such as Jest, as the article points out, or, and correct if I'm wrong, most popular HRM implementations.


I think it has to do with Node.js using Chromes JavaScript engine called V8. So whatever V8 does, node.js must do too.


So many of these points feel like superficial pains that are really quite optional. So many things don’t actually matter beyond offending our sensibilities.


They're painful because nobody is willing to argue the "business justification" for cleaning up tech debt, so your management asks you to hack away at the next feature instead. We've inherited a mess that slows us down in ways we can't produce metrics for, so we can't explain with pretty graphs how much more effective we would be if we cleaned up our config and tooling.


At a previous job where I had to deal with this stuff, I was able to make the case for an “update task” every six or twelve months, where we’d update all of the dependencies, change the config files that needed to be changed, etc.

This would require a full-regression test, but this employer was in the business of doing these fairly frequently since they were super risk averse, and so adding another full regression test that only happened every six months or so was no big deal.

We’d update a ton of stuff, inevitably break some obscure feature when used in IE11 (which at the time, they still supported), so we’d add a polyfill or chuck a dependency through babel and problem solved. Then nothing for 6–12 more months.

This was annoying, but not nearly as annoying as taking inventory at a grocery store or dealing with bad customers at a restaurant. It’s just work, and we were paid to do it.


Not everyone has a choice to not make these decisions. They inherit a project that is already mired in scripts, tools, and dependency hell.

If your CI fails because of eslint is it really something superficial and optional?


They become pain points when you didn't write them, which is implicit in the article. Picking up somebody else's code always sucks, but JavaScript has a way of making it so much worse. There are so many elements, many of which aren't libraries but instead transform your code. If you don't know any one of them you can be completely lost, especially if it is so outdated that you can't get it to work.

You could write a similar story for any language, but JavaScript embraces all of them at once.


I'm not sure if they are all optional, since half of the pain comes from dependencies of dependencies, where you have very little control (esp in the npm world where you can't override resolutions).


You can override the dependency of a dependency in npm.

https://docs.npmjs.com/cli/v9/configuring-npm/package-json?v...


JavaScript IS the gom jabbar


JavaScript is the gigantic man-eating worm that we all rely on for our spice.


To be fair, as already mentioned in other comments, it's the JS ecosystem. Writing plain vanilla JS in a text editor is still a pleasant experience. (However, this is deemed impossible, nowadays.) Having said that, I do get the comedy.


JavaScript is the little death that brings total obliteration.


If this is a reference to the Bene Gesserit test of humanity, then the gom jabbar is not the device that causes the pain. The gom jabbar is the needle with a poison tip held to the neck of the test taker. It’s just a poison weapon. Alia kills the baron with a gom jabbar.


It's 2023 and NPM still doesn't support a comma after the last item in a list, and no comments. It's still stuck to the same old JSON version that it used on day one.

Also, I started with `grunt` before using `gulp`. And I used `bower_components` to build a website. I try not to remember too much though. There is only so much that therapy helps.

I just do Rust now. It's not perfect by any means but at least there is design there.


> It's 2023 and NPM still doesn't support a comma after the last item in a list, and no comments. It's still stuck to the same old JSON version that it used on day one.

Because that's the only version of JSON. It never changed: https://www.json.org/json-en.html


https://spec.json5.org/

Maybe not by the original people, but still a superset. And a more useable superset.


There are multiple supersets of JSON with various degrees of adoption. Adopting anything else but JSON would probably break innumerable tools that rely on the package.json format.

Note: the stable version of json5 spec was only released in 2018.


# Parsing JSON is a Minefield

"The conciseness of the grammar leaves many aspects undefined. On top of that, several specifications exist, and their various interpretations tend to be murky."

https://seriot.ch/projects/parsing_json.html


It gets worse: parser differences can create security risks

"An Exploration of JSON Interoperability Vulnerabilities"

https://bishopfox.com/blog/json-interoperability-vulnerabili...


I tell myself the only reason they grow into these monstrosities is because they were successful projects but I know this is just a coping mechanism.


> Oh, dear jest. […] Properly configuring it with ESM and TypeScript was a PhD science project.

No kidding, I had to do this recently. It was a trek and a half.


Same here. Once I thought the nightmare was over another team's dependent project's jest started failing for a different reason.


I didn't like the Netflix dramatization, but I'm waiting for the next post about python and optional requirments.txt :)


And here I was thinking the first thing about version was going to mention that v0.x.x (major 0) semver packages are considered "unstable" and every update to the version string, even minor or patch numbers, is considered a major update, by the logic that determines whether or not to update the package/which compatible highest version to install


I still think it is funny that javascript has nothing to do with java except marketing


Sorry I pulled my hand out at “left-pad”.


> double-escaping JSON-formatted arguments

God how I hate anything to do with command line


What a nice Deno promo :).


I have a new side project and I started coding it in Deno just to try something now, but not too far from the tree.

Not having to worry about setting up TS, bundling, linting is a breath of fresh air. No node_modules, just a depts.ts file to manage my imports. This also means no yarn, NPM or PNPM to decide.

It still has a learning curve sometimes because some tooling is not mature enough, but it's nice figuring out that I don't need PM2 just a systemd service to keep the process alive.


I've said it before, but the node build tool ecosystem looks like any project in any language where no one was around to tell a bright young developer "no"


> Every time you modify dependency list, some of the dependencies print out screens-worth of messages to your console, asking for donations, warning about breaking changes.


TS and NodeJS is has become my fav for web.


Have you played around with the Lit library for defining UI components / custom web elements? It’s pretty slick.


I love Alex Kotliarskyi’s writing style.


> There’s left-pad, the legendary tiny package that broke all internet, collectively causing the amount of pain and drama comparable to the destruction of Alderaan.

Mind blown. Awesome.

It's like a stand-up comedy routine delivery.


It reminds me of the end of Neo’s “tears in the rain” monologue when he says “Now I know what a TV dinner feels like”


Neo?


The timelord.


On an unrelated note, should I be concerned if a British style police box seems to have appeared in a random location in my town?

...and it's red?

...and there is a line of tiny skulls on stakes near it?

...and until I checked Google Street View I could swear it was blue when I drove past?


According to the lore it’s fine as long as you hit 88mph


Only if there’s VHS cases on top of it


I really don't know anything about Dr. Who.

All I know is allegedly, according to Google today, in this particular timeline, the Tardis is not supposed to be red.

And I remember this, from the VHS era: https://www.macintoshrepository.org/3913-daleks


What is this thread.

I am thankful for it.

Edit: I too remember the Daleks game. <3 A round of Member-Berries for all of us! <3


Typescript is the JS life-saver.


TypeScript doesn't solve any of the issues mentioned in the article


It just solved the "untyped" problem, and it's more than enough.


Yes! TypeScript is fantastic, but you still do need the pain of the JavaScript ecosystem to do much with it.


And adds its own layer of weirdness.

Just one simple example: you must write `import { name } from "./file.js"`.

Not `"./file.ts"`. Why js? Because TypeScript developers are stubborn that their thing is just a layer on top of JS so they refuse to change ".ts" to ".js" in the generated output. This is just wrong approach. But here we are, importing things from "./file.js" which doesn't even exist.


if `import { name } from "./file"` doesn't work for you, something's up with your setup


I don't know the details, but I think there's some new-sh flag or something in TypeScript that requires the `.js` extension.

I don't know if they're pushing that to be the default or what.


If you use ESM modules, they won't resolve files without extensions.


Ah! That must be it. Yeah, super weird that you _have_ to put `.js` when that only exists at runtime


Every time I get close to being tempted to try out JavaScript again for anything beyond basic DOM manipulation, I read something like this and slowly back out of there, trying to avoid any eye contact.


This so accurate it hurts. And it's also super funny. Good job :)


As a Java developer, why the hell does Javascript still doesn't have a equivalent of Gradle or Maven? An extensible build tool that does it all and uses sensible defaults?


One issue with JS is completely different environments. There's very little in common between node.js and browser environment. For node.js you technically don't need a build system at all. For browser: it depends. Until recently you had to bundle your frontend into a single or few large files. Right now you technically can develop a frontend without a build system either, at least when it comes to your code, without dependencies.

Second reason is quickly moving APIs. Common.js, AMD, ESM. Those are foundational APIs and they were changing every few years. Just similar Java example: java modules were introduced in Java 9 and even today maven (AFAIK) does not utilize those at all. But java modules were infinitely more compatible with old code.

Third reason is TypeScript. It does require a "stripping types" step which could be counted as a compilation.

Fourth reason is community. I don't really know what's so special about JS community, but they deliver new tools and frameworks at alarming speed. There's no single source of truth. You can't really do anything with this chaos. Google develops angular, but it's not popular. Facebook develops React and it is popular but people still use other frameworks like vue from small companies.

10 years ago I thought that with time things will settle down. Now I'm not so sure.


Am I the only person who actually still kinda like gulp?


This COBOL will keep feeding us until proper GPT tooling arrives making the whole hands-on coding side of work obsolete.


Yeah, these are pain points for engineer, but not for any product, so there is no priority and space to improvement.


This is the world I live in. Loved every word of it :)


This was delightful.


What a wonderful piece. Phenomenal writing


it's not just javascript.


[flagged]


I have to disagree. The ecosystem is what it is because the hipsters left it and it became the spiritual successor of Java’s enterprise-y mindset.

When I think of JS hipster I think of CoffeeScript, Elm, ClojureScript and all the other trendy stuff from a decade or so ago. JS borrowed enough stuff from them to be tolerable and now everything is React and Webpack plug-ins.


Not just techbro/hipsters: programmers have huge egos, when in reality they are just mediocre tradesmen. Like your typical construction worker. There are 10,000 hammer swingers for every architect, but those 10,000 think they are all in the top-10. So we end up with egos and factions creating a tidal wave of mediocre tools, each with just enough fan base to grow large enough to be cancerous. Too few architects with experience at the helm (and trained by the old guard), unfortunately, is the problem.


The article was fine until this part near the end:

> engines prominently lists node. And while you hate it with the depth of your soul, you are not going to Bun or Deno because you know this will not stop the pain. This will only make the pain worse.

Deno will make the pain worse?

Nearly every complaint in the article could have been solved by using Deno.

- Package.json, no such thing for Deno (not unless you go out of your way to infect Deno with it)

- main, browser, and fs don't matter in Deno since Deno's APIs are based on browser APIs.

- type, module, requires, and imports doesn't matter in Deno since it shares the same import API as browsers.

- scripts, doesn't matter since all Deno projects have the same tools built-in (benchmarker, bundler, compiler, formatted, linter, task runner, test runner, etc...)

- watchman doesn't matter since deno has watch support built in

- dependencies doesn't matter anywhere near as much because Deno comes with a standard library

- left-pad doesn't matter because it's part of the language

- moment.js doesn't matter since you can just use the browsers built-in Temporal api

- resolutions, dev-dependencies don't matter for the same reason that dependencies doesn't matter

- eslint doesn't matter since deno has a linter

- postcss matters less because modern css is great

- jest doesn't matter because deno includes a test runner

- no need to work out typescript installation with your dependencies because deno includes typescript and has less dependencies

The only things not solved by using deno is version and name, which are universal concerns amongst all projects, not just the js ecosystem.


> Package.json, no such thing for Deno (not unless you go out of your way to infect Deno with it)

Yeah...this always felt like a bug in Deno. ¯\_(ツ)_/¯

> scripts, doesn't matter since all Deno projects have the same tools built-in (benchmarker, bundler, compiler, formatted, linter, task runner, test runner, etc...)

AND...you therefore can't do anything outside of the box in a well-defined way. Oops.

Example: How do I run just the main server and not a worker? How do I seed the database?

> dependencies doesn't matter anywhere near as much because Deno comes with a standard library

Sigh. Yeah. Really. You said that.

OK, using the standard library, please:

- Parse Excel files, modify them, and rewrite them to disk.

- Load and modify a PNG and write it out as a JPG. Be sure you scale it down using a Lanczos kernel.

> eslint doesn't matter since deno has a linter

One of the most powerful eslint rules for TypeScript is the detection of dangling promises. A quick glance at the deno lint rules doesn't see anything that will handle this critical lint rule.

And OOPS, adding eslint to the project in a standardized way isn't possible because there's no package.json!

... I could go on.

Sorry, but Deno fanboying is so last year.


> > scripts, doesn't matter since all Deno projects have the same tools built-in (benchmarker, bundler, compiler, formatted, linter, task runner, test runner, etc...)

>

> AND...you therefore can't do anything outside of the box in a well-defined way. Oops.

>

> Example: How do I run just the main server and not a worker? How do I seed the database?

That doesn't really make sense. If you're trying to do anything in a well-defined way, you're going to need a box. The box is the definition.

------------------------------------------------------------------------------------------------

> > dependencies doesn't matter anywhere near as much because Deno comes with a standard library

>

> Sigh. Yeah. Really. You said that.

>

> OK, using the standard library, please: [...]

I'm not going to be able to do these in a comment here, but I can briefly tell you how I would go about doing them.

> - Parse Excel files, modify them, and rewrite them to disk.

Use streams API to create a pipeline (input -> modify -> output).

If by Excel files you mean CSVs, then I can stream the whole thing, making modifications and saving while I'm still streaming in the file.

If by Excel files you mean an xlsx file, then I tweak the pipeline to (input -> unzip -> modify -> rezip -> output).

> - Load and modify a PNG and write it out as a JPG. Be sure you scale it down using a Lanczos kernel.

First I'd make sure I have the encoder and decoder settled. If you have a specific encoder in mind (e.g. ImageMagick + specific settings) then you can box that up by compiling it to web assembly. If you don't have a specific encoder in mind then it doesn't really matter what you use. If you have a specific encoder in mind, then same thing. If you don't, you can always use the JS standard Canvas API which you can load an image into then pull out raw pixel info.

If you want to do the whole thing from scratch, you can do it like the Excel way and create a pipeline using the streams API and TypedArrays.

------------------------------------------------------------------------------------------------

> > eslint doesn't matter since deno has a linter

> One of the most powerful eslint rules for TypeScript is the detection of dangling promises. A quick glance at the deno lint rules doesn't see anything that will handle this critical lint rule.

>

> And OOPS, adding eslint to the project in a standardized way isn't possible because there's no package.json!

Linting for floating promises is tricky to accomplish (ESLint doesn't get it quite right).

Depending on the code, you can get stuck in the halting problem. To solve it correctly, you need to write a compiler/solver that has access to the relevant type information.

This is something that the typescript project itself has been investigating and once solved would be added as another strict rule (e.g. noImplicitOverride, etc...).

If you don't care about correctness and want any heuristic solution, then use any heuristic solution.


ESLint does an amazing job in detecting floating promises. I've not had it miss one, ever. When adding this to a project, I've discovered multiple accidental bugs due to a missing "await" keyword--bugs that were extremely subtle and intermittent in many cases.

The only thing it can't do is determine that you actually did handle the promise later. Which is fine. It's a LINTING RULE, and false positives are the name of the game.

What's BAD is when you accidentally miss handling a promise at all. It's an invisible error without the linting rule.

Your other comments...don't even make sense. You're going to build a Lanczos filter by hand? Or you're only going to ... compile ImageMagick to WebAssembly?!, ... an implementation which is tremendously slower (nearly unusably so for large images) than that of Sharp:

https://www.npmjs.com/package/sharp

... which is simply an import away?

No, what you're doing is called "motivated reasoning." You've concluded that Deno is the best, and you're reinterpreting all of my complaints in convoluted ways to support your predetermined conclusion.

Standard fanboy behavior. Or troll behavior. I cite Poe's Law as why it's impossible to tell the difference.


Not a fanboy. But I'll go through my reasoning anyway.

----------------------------------------------------------------

## Eslint

We're on the same page that:

- heuristics work until they don't

- we'd all rather have false positives than missed positives

- Having something is better than nothing

- ESLint fits it's roll well for now

I've been using node since the 0.x days and used iojs while it was ahead, I've gone from jslint -> jshint -> eslint -> tslint -> eslint (because it supported ts) + sonarlint -> now (which is rome tools in editor, and sonarlint to catch what rome tools doesn't support yet).

The one problem I've had transitioning projects through each linter is just the amount of crufty exception comments to disable rules that ends up through my code.

I've found that I can get rid of a lot of those by setting up my configs and turning on most of the strict modes.

As for promises specifically, I've ended up needing to fire off a lot of floating promises in the last 18 months. There's a lot of firing things off to set values in things that may not exist anymore. (I've noticed it happens a lot a lot around using Promise.race to make code that gracefully recovers in chaotic environments)

The false positives got too much so I disabled the rule (and at a later point moved away from eslint altogether).

There's also some tricky things with catching floating promises when working with frameworks that can deal with super hard to debug side-effects.

So now I have:

- floating promises where for specific situations I don't want to catch their errors and have them throw up to the next layer

- floating promises that are conditionally caught

- floating promises that are actually a wrapped promise that fails as an uncaught promise should, but also conditionally triggers the debugger or logs out a trace.

I use different approaches depending on the situation.

Maybe for you, the only situation you need to deal with is catching all promises (in which case you should continue using ESLint then turn off that rule when TS gets the correct promise handling detection), but for me it causes more trouble than it fixes.

----------------------------------------------------------------

## Images

If I had to do what you suggested, I would have actually just used sharp, but after reading your comment about dependencies, I wasn't sure if you would accept that answer.

I suggested two alternatives:

1. Compiling an existing solution into web assembly to box up that functionality and call into it. It could be ImageMagick, libpng, libspng, libvips, etc... I suggested ImageMagick because that tends to be the go-to for when someone has a specific setting in mind (usually due to a legacy system).

2. Setting up streams and using TypedArrays (which is what sharp uses anyway)


There's a lot of 'just' in your argument.

As programmers we fall into this trap where we think that 'just' doing something else will solve all our problems. But I can guarantee that it's never that simple, and for the people who consume your library, it won't be either.


There's a lot of 'just' in your argument.

I used the word "just" once in my comment in the point about using Temporal.

The Temporal spec was created in part specifically because of the issues with moment.js.

----------------------------------------------------------------------------------------

> But I can guarantee that it's never that simple, and for the people who consume your library, it won't be either.

Unfortunately, Node has historically not used the same standards as browsers over a whole swath of functionality, which lead to differences in the language based on whether it was running client-side or server-side.

Simple libraries intended to run anywhere would sometimes need to release a client version and a server version.

Even when node started adding support for the standard APIs instead of creating new proprietary APIs, they ended up with a fractured ecosystem where some things would only work with the proprietary APIs, and some would only work with the standard APIs.

There were so many missteps with node that the creator of node essentially said screw this, I'm starting again from scratch, hence: Deno.

Coming back to your point:

> But I can guarantee that it's never that simple, and for the people who consume your library, it won't be either.

But it *IS* that simple.

How?

Because Deno uses the standard APIs for things. If it already works in the browser, it will continue to work in the server. No more fractured language.


> Because Deno uses the standard APIs for things. If it already works in the browser, it will continue to work in the server. No more fractured language.

For greenfield projects? Maybe. For established projects? Not for a very long time.

There's a reason Deno added support for npm modules and CommonJS. Because no amount of wide-eyed naïve fanboyism can replace reality.


This feel pretty biased pro-Deno:

- "main, browser, and fs don't matter in Deno since Deno's APIs are based on browser APIs."

  - fs implies we are reading files, how do you use a browser API to read files in the local filesystem? You cannot, you'd use Deno.readTextFile, which is not browser-compatible, so in Deno you have to either make it for Deno or for the browser, not both. The fields main and browser allow you to make a single package compatible with both NodeJS and front-end JS, something not possible with Deno.
- "type, module, requires, and imports doesn't matter in Deno since it shares the same import API as browsers."

  - Seems like Deno just doesn't support CommonJS, e.g. the vast majority of npm modules, which is a big con and not an advantage: "Current Node.js supports both CommonJS and ES Modules, while Deno only supports ES Modules"
etc.

If you interpret the article as intended, yes Deno will make the pain worse because virtually no one is writing libraries that only supports Deno, so now you'd have all the above issues + Deno-specific ones.


I can see where you've gone wrong, let me briefly go though your points.

> fs implies we are reading files, how do you use a browser API to read files in the local filesystem? You cannot, you'd use Deno.readTextFile, which is not browser-compatible, so in Deno you have to either make it for Deno or for the browser, not both. The fields main and browser allow you to make a single package compatible with both NodeJS and front-end JS, something not possible with Deno.

Both Deno and browsers have a bunch of APIs facilitating File/FileSystem/Stream, etc...

- In Deno, you can use things like Deno.readTextFile which is written on top of those APIs to read/write files on the server's file system which the server will do if it asks for permission and is granted by the developer.

- In browser, you can still use those APIs to read/write files on a private sandboxed file system, and the client can request permission to read/write between the private sandboxed file system and the client's real file system through things like the file picker API's, drag and drop APIs, etc...

- The only real difference between the two is that the developer can explicitly grant the server access to files/folders up-front before the server asks for permission in the first place.

> Seems like Deno just doesn't support CommonJS, e.g. the vast majority of npm modules, which is a big con and not an advantage: "Current Node.js supports both CommonJS and ES Modules, while Deno only supports ES Modules"

Deno *Does* support CommonJS (see the --compat flag). But you probably want to use ESM over CommonJS anyway.

> [...] Deno will make the pain worse because virtually no one is writing libraries that only supports Deno, so now you'd have all the above issues + Deno-specific ones.

If you write your library to the JS standards, then you have code that supports both browsers and Deno (and possibly Node depending on if Node supports those particular standards and you're web standard code isn't being used by your non-web standard code).


- That's not the point, the point is that by having a browser and a main script you can selectively pick whether you are loading one or the other. The browser loads the browser-only code, the main loads the fs-compat code. Browser support for FS is a joke compared to NodeJS support.

- That was a quote from Deno's official page, if it supports commonjs better ofc. "But you probably want to use ESM over CommonJS anyway" -> no way, if you want to use most of the npm packages you need support for commonjs. Ofc you'd be writing ESM for your modern app though.

- There's no "JS standards" for backend stuff like FS, running commands, launching a server, etc. so very often you need backend-specific code. You already showed two extra pain points of using Deno vs Node in this convo, adding the `--compat` flag and granting permissions.


> Nearly every complaint in the article could have been solved by using Deno

Alternatively, don't go out of your way to install Node or Deno—instead, just use the runtime you already have on your computer; browser makers are much better at following the standards (and consequently not encouraging/inducing you to write against standards-incompatible APIs to begin) than the people peddling Node and Node-influenced stuff.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: