> John gives up. Concludes never to touch Node, npm, or ES6 modules with a barge pole.
> The End.
> Note that John is a computer scientist that knows a fair bit about the Web: He had Node & npm installed, he knew what MIME types are, he could start a localhost when needed. What hope do actual novices have?
The ones who don't give up on the first night will likely have more luck (try, try again).
As someone with little experience in Rust, I can say that I have had no trouble downloading, compiling, and running binaries from a crate. The only hard part for me is organizing my own crate correctly.
Rust is definitely known for having a sharp learning curve, but I'm not sure what you mean about the package system. I've onboarded several people onto Rust at my job over the past year, and the package system has never been an issue for any of them.
Or, you know, Python, Ruby, Java, Go, C#, Swift, Kotlin, etc., etc., or any number of other languages that are less of a foot-gun full of bizarre issues, poorly maintained packages, and droves of Jr. devs eager to do clever things that make the language and ecosystem psychotic.
Python is good at many things, but packaging is not one of them. The best python package manager at the moment is Poetry, and it drew most of its inspiration from npm and yarn...
Python packaging has historically been so bad that dotcloud invented docker in an attempt to make it usable.
But at least I can just download a .py file (or a bunch of files) and just import them. Perhaps the biggest frustration/pain point in this article isn't npm as such, but that you can't "just" use some JS module.
You definitely can. On the server side, you can literally do that. On the client side, you can "import" one with a script tag, and increasingly you can use modules in browsers too.
Nothing would stop you from doing that (import thing from ‘./downloaded.js’) but it’s Just Not Done That Way and packages aren’t really built with that in mind, so it probably wouldn’t work very well in practice.
I've played around with a bunch of languages, and Rusts' is unequivocally the best experience I've had so far. Cargo works as intended, literally straight out of the box, crates.io and the Cargo.toml was straightforward to figure out. Certainly way less frustrating than figuring out how to use Python virtualenv when I was first starting.
that's fair, but newer languages like Rust have the benefit of hindsight, and can mandate one way to do things. to be clear, i'm all for that.
i don't think it's possible to do that any more with Python, the genie is out of the bottle. but you can get close with things like Black (auto-formatting) and Poetry (nicer deps mgmt and so much more). of course, how would a beginner know this? hopefully some day tools like that will become the default answers
What experience DOES john have? I've had far worse experiences with ruby, python, scheme, clojure, java and C.
If you want a language that requires zero learning to use, I am sad to say that they are very far and few between. Sure, we have a clusterf*ck of a module ecosystem and interoperability issues between preprocessors but it isn't like that is a particularly novel problem either.
The node environment and the browser environment is a pretty unique aspect to JavaScript. It adds some complexity for novices. An hour spent trying is a bit on the light side though.
Now I want to see John try to build a client on another stack, like deciding between Carthage vs CocoaPods vs etc. for his iOS hello-world and running into the problems with that.
Or, hell, how about the packaging systems in Go or Python? "Yeahhh, we don't really use X anymore, go ahead and use Y."
John certainly failed the perseverance test though.
It's true that basically every language (except Rust?) has nightmarish package/environment management/tooling ecosystem problems. Why is this, anyway? It's a little nuts that it's easier to learn how to code than it is to figure out how to install a module.
Right now you can click File > Swift Packages > Add Package Dependency and let SPM handle it for you without thinking. I know not every package supports SPM yet but it's clearly the path forward and something everyones working towards. I think the other point I've found doing both web and iOS is you don't need any dependencies to get started on iOS, a hello world app is as straightforward as opening XCode, creating a new project and plugging in your phone.
Eh, yes and no- that only gets you started if someone else already picked modules for you. Snowpack and such make modern ES modules with npm bearable, but the sheer volume of modules that rely on webpack's preprocessing bastardization of the module system is really depressing. I really wish they had used comment directives or something other than the import statement for things like attaching CSS files to builds.
shrug it basically just copies files out of node_modules to another folder for sane browser use of module imports (no concatenation or build process). Basically, for people who liked bower but are stuck with npm.
I've used it for some personal projects, but doubt that I'll use it for anything paid anytime soon.
I think JS gets shit on the most because its both the largest, most popular, visible and relatable. Imagine trying this same exercise with a C++ library you found
>The cmake build is doesn't work without -GNinja (you do have ninja installed, right?)
>No actually use Bazel/Buck/Pants/Meson
>Oh you installed $DEP, but not the right $DEP with $DEP-X support
>pkg-config can't find $DEP-X
>Pre-build $DEP-X was built with GCC N, and you have GCC N-1, try building from source
>GOTO 1 for DEP-X
I'm embellishing here, but I feel like I always do some version of this song and dance when trying to build a C++ project. And then after all that is done you somehow still end up with linker errors in your final project.
I think one difference is that this is usually abstracted to quite some degree. Most devs rarely (if ever) have to deal with C/C++ build systems, as package managers and whatnot deal with that.
For most people installing some C/C++ library it's just "apt-get install libfoo" (and maybe libfoo-dev), and they never have to deal with ninja/autotools/cmake/etc, whereas for JavaScript you directly have to deal with the tooling by using "npm install libfoo".
The same task mentioned in the article would probably be a lot easier: install package, write some code, "c++ -lfoo main.cpp".
This is fair, but, the original article mentioned installing a random module on github. A C/C++ library large enough to have distro maintainers, is more akin to a large JS library that has UMD scripts hosted by Cloudflare. In that case, a developer could just do '<script src="https://cdnjs.com/lib.js">' in a html page.
I'm not saying JS is perfect, or that other languages don't have these issues. I haven't used Rails in years but I remember spending a day trying to get a gem installed and figuring out why nokogiri wouldn't compile. Almost every language has these problems.
Most of the C++ is curated by the package maintainers. That's the key: do not let upstream programmers do it (they adore their unique build systems and other stuff like that).
That's how you get quality user experience. It creates balance between developer of the library/tool and the user of the library/tool.
In my last C++ project (it's been a while) we ended up including many of our dependencies in source as we required different versions, different build options or small modifications compared to the packaged version.
Most of the time we would create a minimal CMake file to build the library to our specs or adapt the existing CMake file.
Well, since you mentioned ruby, I've never had - not even once! - to wipe out my gems folder in 10 years I'm coding with it. I think most ruby developers never had too.
With javascript? Well, for instance, take Expo's official release notes for each new SDK and it's right there, as the recommended practice: wipe out your `node_modules` folder and run `yarn` again every time. And good luck not having your `yarn.lock` file randomly changing versions after a while.
It's just a single silly example, but it tells how much more stable the ruby development experience is.
The module syntax inconsistency situation is atrocious but we're gradually making the transition. Now that we have a clear destination, I suspect it will be a non-issue in a few years. Projects like Deno and Pika are accelerating/papering-over the transition.
I've been working in JS for years and I've never encountered a module containing a typescript file with a .js extension... That was extraordinarily unfortunate. I don't think I've encountered a module containing Typescript at all. Correct practice is to build to JS and include the optional type declaration files. In my experience people are pretty good about that.
Ah, yeah. Flow files do, unfortunately, stick with the .js extension by convention. However, it's still terrible practice to publish a node module that doesn't include a plain JS version of everything.
It was definitely flow. It was the first thing that came to my mind, because I've never seen anyone writing TS in .js files, but I've seen flow in just plain .js files - a lot.
This resonates so much. I support some JS packages but I often wonder how anyone gets anything done in general on the JS side, and why people seem to accept the state of affairs. I'm spending most of my time with Ruby and it is night and day.
People get stuff done in JS by sidestepping all the bullshit. If you keep your tooling simple and use a minimal amount of dependencies, then JS is one of the languages/environments with the least bloat, not the most.
The big problem JS has is the same one PHP used to have when it was top dog. Everyone is a fucking noob, including all the people writing all the advice online. I find almost every JS resource to be unbearably bad, with the sole exception of MDN. The vast majority of my learning these days comes from work colleagues who also have a decent level of mastery.
So the real answer is probably that the people getting stuff done are happy with the current state of affairs, because it works for them. And the people that are unhappy are for the most part trying to change the current state of affairs without fully understanding it, and making it worse. I think every language suffers from this to some extent, JS just has a much worse ratio of masters to beginners so the effect is exacerbated.
The package.json should have something like this if they are going to use import/export statements so anyone on older versions don’t have to worry about it (it’s not native to Node yet without .mjs extension).
We can blame whoever didn’t set that up, or the instructions should have been to just use require().
As a computer scientist who learned JavaScript this year, I strongly agree with the sentiment here. I feel like I often spend more time debugging module errors than my actual project.
Granted, once I understood the ecosystem more, I gradually began to grasp the reason these issues are around. But still, it does make it incredibly frustrating as a reasonably decent coder getting started in JavaScript.
As a programmer who has been using JS heavily since the late 90s and now doing mostly React and Node.js, I would say that finding the right modules and patterns to use has always been a big part of the job. It takes a lot of searching, experimenting, learning, judging code quality and reading the tea leaves on package stability and popularity.
Things have largely gotten much, much better for JavaScript though ever since Node and NPM came along. It's easier to find the right modules to use or at least the right ideas to borrow. Package overload paralysis still happens at times, but I'd personally always rather have more, rather than less choice.
The constant rate of change does make me feel like I'm always re-learning a new way to do the same old job, but luckily for me - learning potentially better ways of doing the same old thing continues to be enjoyable.
Like many others, I'm chiming in with a me-too... IMO the biggest problem is that if you come back to JS after a hiatus, it's very likely that most of what you thought you knew would probably have changed in the interim.
I mostly work on the backend.. However, I've done a decent amount of JS too. In fact, back in 2015, even built a lot of the core parts of an SPA using a mix of knockout & requirejs with minified bundles and dynamic loading and so on.
Given that it stuff put together from scratch, I though picking things up after a couple of years away from js would be easy. Oh how wrong I was...
In 2017/18 sought to write a starter boilerplate with vue 2, Typescript and .NET Core. I would have probably spent an order of magnitude effort more fixing build issues and warnings than on the project. Once you hit bugs/issues with 3rd party webpack modules (which is almost a given), it is not fun at all.
I recently had to put up a one page visualization and was not looking forward to it. Surprisingly, create-react-app just worked out of the box. Not much of a data point - but still a pleasant experience.
The worst node module import issue I’ve encountered is with bootstrap react Navbar component. It runs fine locally but wouldn’t build in ci, and after an hour of troubleshooting it turns out that the B is capitalized (NavBar)... so WTF it works locally?...
My friend and I decided to start a project. This friend and I have had discussions where he espoused how libraries like Webpack, React, Redux, etc. just overcomplicate the web. I decided to humor him and do a "simple" stack of lit-html, vanilla JS and ES6 modules (since they landed in browsers). It took us maybe...a day to pedal that back? The first thing to go was doing ES6 imports in the browser. I forget the exact sequence of events but the MIME issue definitely showed up, along with maybe an untrusted source issue. Say what you will about Webpack, but native ES6 modules are definitely not here yet.
Yeah I bet once you get the stack up and running, as well as smooth out the inevitable early adopter bugs of lit-html, you'll have a great experience. The subtext of this was my friend constantly telling me easy and simple it'd be versus React. When in fact each stack has its tradeoffs and incidental complexity.
lit-html has been used in production for over 2 years now, on sites with billions of page views a day. At this point no one new to it would be an early adopter :)
The issue with module loading is a pretty fundamental one, though pretty unrelated to web components.
Once you understand it, there are a large number of tools that make them work. The core problem is that most modules available on npm are written with import specifiers that assume the environment supports Node's module name result. Browsers don't, so it won't load something like `import * as redux from 'redux';`
The solution is a tool that transforms package names into URLs. Webpack, Rollup, Parcel, es-dev-server, Snowpack, Vite, unpkg.com, Polymer CLI, and many more do this for you.
More and more of the ecosystem is moving to native modules and we're all going to have to understand this issue.
ReasonReact has been used in production for 3 years now, with billions of page views a day. I'd still call it immature in many^[1] regards :D
The particular point of this project was to prove that each successive simplification that my friend proposed, i.e. avoiding Webpack for native ES6 modules, using lit-html instead of React, etc. introduced its own complexity. I'm not saying that these were all bad ideas, but just that they're fundamentally tradeoffs. I'm quite sure lit-html is a great stack. But it's not "better" than React any more than React is "better" than Angular.
[1]: Lack of async/await, or its equivalent, let+ in OCaml 4.08, is a big one. Mediocre typings for browser APIs is another.
I feel like the tremendous popularity of node caused the development team to self-reinforce bad habits, but it’s just a theory.
I often wonder what the js ecosystem would look like with Google-working-on-Go levels of runtime and package management design discipline.
One would really think Google would do this, especially considering that Microsoft now has veto power over the npm repository and package format. Yarn was a huge improvement but is still dependent upon the same broken backend model.
AFAICT the success of the JS ecosystem is entangled with Google’s success.
The shortcomings of JS are rooted in its legacy baggage. Go had none of that. JS today is a good language emerging from the ashes of a bad one, but there are a lot of ashes, and some of them are impossible to completely shake off.
As much as I am not a fan of js-the-language, the problems TFA described and that I addressed in GP are 100% independent of the language and are 100% in the domain of tooling.
Literally nothing about javascript-the-language is why package.json is in a file format that does not support comments, or why node_modules can’t be renamed or hidden or cached properly across projects, or why any of the cryptic import issues encountered by the author of TFA happened, or why yarn had to be made because npm is (or at least was) nondeterministic.
The js packaging tooling sucks, and, more importantly, has continued to suck contiguously for at least ten years. Much like Python and Ruby (cryptographic checksums, anyone?) and Debian/Ubuntu to some extent, I think nobody gives enough of a shit (or has the skills and experience and inclination) to unfuck it, or has just become blind to it over ten+ years of it sucking in the same way (much like autoconf).
It is entirely unfuckable. No part of it is baked into javascript. Go’s was fucked, and they did an epic job of unfucking it with the module and caching system. The same could be done for JS.
It would require forking node to handle imports sanely, and replacing npm/yarn packages (as well as the backend npm package repository they talk to)—surmountable tasks.
Side note: Go has a little bit of baggage. That community is in the process of going from multiple 3rd party package/dependency managers to one official one.
It's become easier to build with hard-compiled languages than with interpretive ones. Interpretive ones shouldn't need "building", but they seem to acquire build systems anyway. Compile and link systems at least diagnose what's missing during the build process, not during execution.
Are there other languages that suffer from this? I think Python, Erlang, Ruby at least seem to have escaped the fate so far.
The upside of the JS transformation into just another compiler target is that there is little reason to use JS as the source language, IMO. These JSVM languages do suffer from the same problems to varying degrees.
A major difference is that JS developers have little control over the runtime of their users, while all these other languages and especially compiled languages do. JS is a special case because it's the sole supported language of browsers, which all implement it differently—that comes with a unique layer of complexity.
I don't know why people do this. In more complex areas of programming the code and tooling are simpler. It seems like any ecosystem just fills up to the certain level of complexity regardless of the complexity of the original task at hand.
Since you mentioned complexity, past a certain level of application complexity, you realistically can't do a linear list of Javascript files that you import on the page in order. When you have hundreds of views, you don't want to manually go and figure out what each of them needs as prerequisites. Circular dependencies are annoying when you do it by hand but practically trivial with a packer as long as they're logically sound. Inversion of Control. On-demand loading. These are all problems that have been previously solved by hand, but when you don't want to solve these prerequisite problems before your actual business (or hacking) problems, you build tools to do it for you.
"Can't do a linear list of Javascript files that you import on the page in order" - sounds like a problem that a BCPL developer has stumbled upon 50 years ago while writing his include directives.
If web programmers had the choice to install an arbitrary language's runtime in users' browsers, they would. But users have disparate browsers with disparate JS implementations, so if you want to code in a sane language with consistent behavior, you'll need to transpile and polyfill it.
You can't just distribute arbitrary binaries to users on the web, so web developers have to deal with a layer of complexity that other programs don't have to. That said, maybe WebAssembly will change this story.
Those are all runtime concerns. They don't affect the literal syntax that you write, as is the case with JavaScript. You can't feature-detect syntax. Instead your entire program will just fail to parse.
I have hit a few of these myself and I have also hit similar needlessly complicated issues in a bunch of languages. This particular instance also suffers from the seam between Modern ES modules and legacy JS, which could be better.
Learning a language involves learning a bunch of non-language arcana about the environment, for no particular reason. Ideally you should be able to write the helloWorld equivalent for any platform and have a single command to turn that one file into a working program, but alas we have tool chains, configurations and requirements standing in our way. I don't think it has to be like that, but it all too frequently is. Deno seems to be making an admirable effort towards making a thing that just works.
Developing for Android or iOS makes the JavaScript experience positively direct.
Anybody who's an outsider is going to hit stumbling blocks. It's your choice to feign ignorance or pick yourself up. A lot of languages have their peculiarities and JavaScript is no exception. Would "Today's <Language X>, from an Outsider's Perspective" look any different? Where X is a language that's at least 20 years old.
> But why do I… ok fine, I’m going to start a localhost.
Is "start a localhost" a generic term? If someone told me to do that, I would probably freeze in embarrassment -- no one has ever told me to do that in such context-independent terms. Since this was about node/JS, did John install express, or some other static file serving module? Or did he have an unrelated tool that makes this trivial?
Yup, I've never heard of that particular idiom used to describe the action of spinning up a local server, and it's not really something trivial as to not require some external tooling. So I don't know what's up with that.
> Turns out VS Code collapses folders with only 1 subfolder, which is why we hadn’t noticed.
OMG. Decades of life in emacs (emacs!) would never have prepared me for a world where my editor would helpfully lie about the filesystem to me.
Yeah, this was horrifying to read. Obviously some of it is just normal churn, and all environments have their own oral histories and weird quirks. But... yikes.
"Quickly" using the JavaScript tooling is somewhat akin to watching one or two episodes of the 6th Game of Thrones season without watching anything else. You really need to watch season 1-5 to understand what's going on.
The other day I wanted to publish a little script I've been maintaining for years as a module easily usable by WebPack and whatnot, and that's much easier said than done. I published it on npm and put some UMD magic thing in there, and I think it should work now ... but I'm not really sure to be honest (still need to look at this and confirm).
Just searching "publish JavaScript module" and trying to make sense of the WebPack isn't really all that helpful, not for me anyway, as I'm joining half-way through season 6.
I have no opinion on the tooling as such – I lack experience to have an informed opinion – but it sure is confusing to "quickly" do something for people who are not heavily involved in it (i.e. me)
I don't use it at all, but others do and I think my little library is neat enough for others to benefit. Unfortunately, I can't get any of thus UMD stuff to work, so for the time being I just "window.imgzoom = function(..) { .. }" it shrug.
> "Quickly" using the JavaScript tooling is somewhat akin to watching one or two episodes of the 6th Game of Thrones season without watching anything else. You really need to watch season 1-5 to understand what's going on.
I disagree. In both cases, you really only need one or two episodes to know that the story is not going anywhere. It will only get more complicated and convoluted without ever rewarding you, you will realize that no thought was ever put into it, and you will only stay for the ride because of sunk costs.
That's nice and all. Unfortunately, (to stay in the metaphor) the PM has arranged to quiz you on the main plot points of season 6 three days from now, so your best option is to find a good plot summary for seasons 1-5 on Youtube somewhere.
As time goes on the breath of questions increases so necessarily the depth must decrease, due to all the history of the language (JS, C# or whatever). You are not a code now you are an archaeologist. It was so much easier in the year 2000!
I was under the impression this was still the best way to do it for maximum compatibility ... but perhaps that character got killed in season 3 and I missed it
to echo others here, python ecosystem is worse imo. And compared to cross compiling C++ and C for ARM, js ecosystem seems like easy mode. You can always just write a little script to attach your module to the window, if you feel averse to webpack
I've been programming professionally a long time and had toyed with python before for small scripts, but have only recently had to write larger amounts of production code, and I was not prepared for how bad the python import system is.
I'm sorry but this rant is full of bs. Liquid, stinky bs. It's like someone found a lib on Maven Central and tries to use it without having project built my maven or gradle. If they do, they're in for a looooong journey
I am a backend developer and recently I had to start a personal project with _a lot_ of frontend. Googling how to setup minimal webpack config for React (using that react starter app seemed an overkill) took 15 minutes and in another 15 minutes I had a proper minimal hello world. One more hour and I had everything - eslint with standardjs, automatic formatting, everything. Everything just works, react jsx, babel, source maps, everything. For whatever question I has there is an answer one Google search away.
Last time I did something serious on frontend was in 2009 and so far I've written around 2000 lines in JSX with React for my personal project and it's been an absolute _pleasure_ compared to horrors I had to deal with in 2009.
Stop wining and educate yourself, it literally takes 15 minutes.
I had a similarly frustrating experience when I first set up Python to use Django. The complete mess that is the Python 2/3 split (thankfully somewhat better now after many years), trying to figure out what the hell pip and pipenv were (this was before I was familiar with package management).
However, I initially learned some Python in university and I liked it then. We just installed Idle and ran some simple scripts, and everything worked. That's the right way to learn a language. If you dive straight into JS package management, you are attempting to learn multiple things at the same time:
* Node.js environment
* Browser environment
* JavaScript syntax
* 'running a localhost'
* JavaScript modules
* NPM package management
You need to tackle these one by one. If you do them all at once, even with prior experience in other languages, of course you're gonna have a bad time.
Really what I take away from this post is that the author is a bad teacher, although the experience of her student is probably similar to what many people experience when trying to learn by themselves.
There are many improvements that could be made to the JS ecosystem, but this post does not do the current state justice. What it highlights, if anything, is a problem with the available of a standardized learning path. But I'm not sure what the solution to that would be.
I've been learning Vue this year (I'm new to anything JavaScript so that means I also had to learn JavaScript, Node, NPM, We pack, etc.). I'm getting a lot better, but it has been a pretty frustrating experience. There are so many different layers and they are constantly changing what they do and don't use in another layer.
I've been working in Python for the last several years. There's definitely a learning curve there, and I get frustrated with things all the time, but the whole JavaScript ecosystem seems like such a mess compared to Python.
One of the things I miss the most about Python when working in JavaScript is the documentation. And I mean the core documentation from Python.org. The Tutorial is amazing [0]. And you can download the entire documentation already in PDF. Maybe I'm one of the few, but when I'm learning something new it is such a better process if I can leave my computer and read through a tutorial and mark it up.
if you are learning vue and new to javascript ecosystem, would it not be better to start with index.html using Vue from a CDN, and switch to advanced workflow (node, npm, webapack, etc) later?
of course, if you are new, then this approach may not be obvious
When I learned Vue, I just inclued the library with a script tag, and started writing plain JavaScript around it.
That was about 3 years ago, and I just started using modules. Even then, I use the native browser modules, no Webpack. With HTTP2, there is little cost to requesting many small files.
Likewise, I don't use a CSS preprocessor in any of my projects. They aren't that complicated.
Those projects have no build process. What you write is what you run (WYWIWYR?). If the project is small enough I'll serve its root directory with Python's SimpleHttpServer. Later, I might have nginx do it.
This allows me to get a project running in a minute. I add tools when they are needed, because then I have the motivation to learn them and set them up properly.
Such tools are required if you must coordinate the work of multiple developers. Their cost is divided by the number of devs, and their benefits multiplied.
If you're just a home gamer toying around, you can do without them.
I started using Vue from a script tag a year ago (not that hard). But when I started building an SPA, things got complicated very quickly.
I found myself longing for a really good tutorial similar to Django's [0], rather than the thousand variations of "Today We'll Build a To-Do App in Vue!" that are so common.
For the projects that I work on, I use the same pip/virtualenv setup that I've used for years. Can't imagine that happening with Webpack (Side note: it might be that I could use the same Webpack setup for years, but the unstable reputation around the JS ecosystem makes me think I couldn't).
IMO this is a symptom of a larger problem with the entire web 'ecosystem' (HTML, CSS, JS primarily). It all tries (or tried, anyway) to be simple and easy and forgiving - which means that simple things are easy, and moderately complex things are insanely difficult.
I honestly think the only real solution is re-doing all of it 'from scratch', to make everything (a) stricter and (b) more normal/consistent.
(I think the extant transpilers/preprocessors tend to try to be too 'thin' of a wrapper around CSS/JS: they do give some nice quality of life features but still don't really clean up the mess that is JS and the DOM.)
It actually it is (mostly) as easy as it can be if you think about how the web lets one run third part code safely, not only as a sandboxed in the host environment but also from different domains. I've seen this space evolve since the days of DHTML and the best way to create dynamic content is with document.createElement. Actually I use the crelt[1] util, and the code is shorter and faster then any React/Vue virtual-dom templating system. It like finally riding a bicycle a without training wheels after 15 years of practice.
And so I use create-react-app anytime I need to start a front-end JS/TS project, even if I am not using React at all. Basically avoiding dealing with troubleshooting the soup of build time dependencies and mismatching package versions, which unfortunately comes with the modern JS (or node) ecosystem.
"Really what I take away from this post is that the author is a bad teacher"
No she isn't.
This entire thread is full of the generic excuses one has come to expect from this profession when people struggle with programming setup and running programs. Always a defence of the (broken) status quo.
Something has gone wrong? You didn't read the documentation (the incomplete or non-existing documentation). Or it's actually simple, all you need to do is x, y, z followed by a, b, c - how could you not know that? (Often implied in these responses: you're clearly a clueless noob).
This is quite simply a profession that wouldn't recognise 'simple' if it came and bit it on the arse (or ass).
She wasn’t helping one of her students, she was helping a friend who is a computer scientist. The closing thought was if this person, with so much existing knowledge and some assistance, can’t make one “simple” thing work in a reasonable timeframe, what hope do actual novices have?
Novices don't need any of this - Babel and webpack are for pros who need to support IE9. I have in my team 19 year old who knows all this stuff to implementation detail, so it's not that hard to learn - speaks more about this friend.
I’m pretty sure the author isn’t teaching anything but is instead pointing out the unfortunately common pitfalls when having someone new start with the JS ecosystem.
Javascript is the ONLY language where people think they can just pick it up and use it with ZERO education first. Sure, they spent years learning to program in language X or Y, but even a couple days to learn Javascript is just too much effort.
If you think learning NPM is hard, try telling a new dev how to setup a Java or C# build by hand. If you think webpack is hard, try teaching someone the intricacies of make.
What about babel? Other languages make breaking changes and dictate that the new version of code just won't be compatible with older stuff. Python 2/3 wouldn't be a blip on the radar if the same option to transpile between versions existed. Those famous "update your .Net version to whatever" warnings simply wouldn't be needed. Instead, people complain that learning a few lines of config is too difficult.
If people put half the time into learning JS that they put into learning the other languages and build tools they know, there would be almost no complaints because the tooling these days just isn't that bad.
> Javascript is the ONLY language where people think they can just pick it up and use it with ZERO education first. Sure, they spent years learning to program in language X or Y, but even a couple days to learn Javascript is just too much effort.
The problem is not one of putting the effort in, it's even knowing where to go.
If I want to learn about how to use some new JS library/utility/webpacker, I can probably find about 30 good-quality-looking blogs/articles/documentation pages on how to do it. Most of them won't work, because they'll be out of date. This is hugely frustrating, because you don't know if it's not working because the documentation is wrong, or because you're holding it wrong.
> If you think learning NPM is hard, try telling a new dev how to setup a Java or C# build by hand. If you think webpack is hard, try teaching someone the intricacies of make.
Make is actually a brilliant example of something that's complex and daunting, but ultimately rewarding. It's easy to put the effort in to learn it because the maintainers don't change their minds every 2 minutes about what the Makefile syntax is, so learning how to use it is pretty straightforward. And once you know it, you can understand makefiles written both yesterday and decades ago.
Give me make over webpack any day of the week. I'll put money on which dies first.
I totally agree with the author here, but also would love to give some context since we have lived something like this before on Javascript IMHO:
Callback hell around 2015. It used to be that if you wanted to do something async you'd have to create a new callback. This led into callback hell[1], which was specially bad back then on the backend.
Luckily after a migration that has taken many years, now most of the libraries use async/await instead of callbacks. There was some time where this was extra difficult because some code was using callbacks and some other code was using async/await, but it's almost totally solved in 2020.
Which brings us to the article on hand. This is probably one of the biggest issues, and a fake promise in Javascript right now: reuse code on the back-end and front-end. The front-end side has been using `import` for almost a decade with Webpack and friends but this was not easy on the back-end, so there was not a practical way of reusing the code in a project.
Luckily since last year Node.js supports import/export, and React supports it in libraries. It took a while because it was not an easy issue. I expect that more and more libraries will start to work only with import/export, and hopefully in 1-5 years this will also be a non-issue.
> Luckily after a migration that has taken many years, now most of the libraries use async/await instead of callbacks.
Is that true? I was looking to port one of my C# projects to TypeScript/Node and it uses gRPC and it's not async/await compatible. That's a pretty major library in my opinion.
In the end I didn't end up porting my project because the lack of elegance compared to the C# version was too depressing -- the C# code made heavy use of async and porting without that was just too messy. I'll take another shot at the project once this problem is totally solved.
Well, it's true for libraries that were using Node-style callbacks ('nodebacks') which had an upgrade path to promises[1] and from there to async/await. If some library was doing a completely different style of async, then unfortunately it won't get that easy migration path but it can probably still use the Promise constructor[2] to wrap the async operation in a promise.
I don't know which library you were looking at, but if it wasn't https://github.com/protobufjs/protobuf.js, it probably should be. That one uses promises, so is async/await compatible (JS async/await is just sugar over promises) and I've seen it work well enough in production use to have no reservations in recommending it.
Yes, I said most and not all, there are still some older libraries that haven't been updated. These are fairly rare, and you can still util.promisify, but sure it's definitely not ideal.
Please note that not all callbacks can (or should!) be converted to promises, e.g. events like `on('click', ...)` don't have a clear way to be promisified since a promise can only be resolved once and stays resolved.
If you don't want async/callbacks you are using the wrong framework. Serial code is much easier to deal with. And async/await just hides the complexity under the rug, hoping you'll never get backpressure and other issues.
Callbacks take a while to grok, it took me about a year to learn how to juggle all the async calls in my head, which a multi threaded language will do for you. Both have their pro et contra though, with multi-threading you'll be dealing with locks.
Yikes. I really do not think that was the solution to this problem and only added a ton of complexity.
JS is in a unique position because it can run both code in a browser as well as a server-side/scripting language. In order to do that with any level of success, tooling is required. This tooling (dev server, webpack) builds on other tooling (node, babel, typescript) which is where all this complexity lives.
Furthermore, some packages are not worth installing and if you run into issues with that package, then try something else. We have no information about the package they tried to install and since the JS ecosystem encourages people to publish to npm for virtually anything, this is one area where you really have to be careful.
The lesson here is the same lesson with installing something like left-pad: be careful what you install and read the source code to understand what it is doing. Most of the time, these packages can be inlined easily. Just because a library exists, doesn't mean you should use it. Most of the time for JS I'm reading the library's source code to see if I can a) inline it or b) use it as inspiration to build specifically what I need.
> JS is in a unique position because it can run both code in a browser as well as a server-side/scripting language. In order to do that with any level of success, tooling is required.
Mind that this was not that much of a problem back in 1997 with Netscape Navigator and Netscape Enterprise Server. I think, the real issue here is that the JS ecosystem is targeting an abstract implementation, rather than a real world one. Much of the tooling is just about turning the abstract implementation into a real world standard and, in a second step, about packaging (i.e. linking).
> Much of the tooling is just about turning the abstract implementation into a real world standard and, in a second step, about packaging (i.e. linking).
So long as you have browsers in various states of compliance and paying customers using those browsers, this will always be a problem.
> be careful what you install and read the source code to understand what it is doing.
That’s the reason why I started to love pika.dev ‘s package search. Webpack still sucks and will ruin your day with hours of unnecessary configurations and fixes.
On the other hand, when setting yourself a rule to use plain ESM only without any build system, coding has been a joy.
The only thing that still sucks is UI frameworks, because all major frameworks still require a shitty babel workflow in one form or the other. Vue.js has an ESM module which is useless without babel (due to the .vue file format), and Angular/React are still in the lets-invent-our-own-language fatigue.
React without jsx components is just as useless as Vue without .vue files. If you cannot use the ecosystem of a framework in practice, your framework isn’t a framework anymore.
Lately I've been developing with a JS workflow that's finally made me think "hey this is fun!" again:
Chrome target, native ESM modules, VS Code with JSDoc annotations for types. All libraries (chosen preferentially from microjs.com) are copied into vendor/, and the front end is written in preact.js using htm [0] for native JS tagged html strings, leading to code like:
import ImageView from "./image-view.js";
render({ trail_item, selector }, state) {
/** @type {LinkItem} */
let link_item = trail_item;
let title = this.render_title(trail_item);
let favicon = this.render_favicon(trail_item);
let img = html`<ImageView src=${favicon} />`;
return html`${img}${title}`;
}
There's a VS Code extension which formats html`` strings as actual HTML, and the Typescript checker built in to VS Code gives me advanced types and autocomplete, all with a workflow that's as simple as "refresh page".
Granted, not every project can afford to target just evergreen browsers, but for my use case it works perfectly and I finally feel like I have the perfect blend of old-style web dev (in terms of refresh cycle) with modern language features and typing. The overhead, both in page-weight and cognitive load, is as small as I can make it.
EDIT: Modified my code sample to show how you can use Preact components in a JSX-like way.
Yeah, the microjs approach is much nicer than the Node approach.
I think the mistake of modern JS (and many other languages) is conflating source files with libraries. A better model is combining many source files into one library file, which provides one toplevel name when imported. A good example is how Three.js, which has a complex internal structure, gets distributed as one file and provides one toplevel name THREE. And of course there are many examples in C-land, where a large library can live behind a single header file. A project should only depend on a handful of those, and there should be few dependencies between them, so package management becomes easy enough to do by hand - just drop a file in your project's vendor/ directory.
As a bonus, this fixes the problem of having many fine-grained imports. If done right, your project's source files might not need any import statements at all. Anything inside the project could be available without ceremony, as if it was all one big file, and external libraries live in a handful of big namespaces which are also available without ceremony.
I don't know enough about Three.js to say if that works well for them or not, it probably does, but I don't think a future where all libraries would do this would be very bright. If the library is big, you'd end up shipping a whole lot of unused code to the client, making the end user bored and angry while waiting the page to load (especially if they are the sort of person who hangs around in Hacker News). In fact, the direction has been the exact opposite in recent years! Look at how lodash has moved to exporting one function per one file so you can include just as much of the library as you need.
Sure, it's just that the person you were answering to--and this whole thread really--seem to be advocating for just importing module files without any sort of build step. Without a build step I also assumed tree shaking wouldn't be an option. Tools that handle tree shaking, like Webpack and Rollup, aren't really the simplest of JS tools anyway so if we are talking about simplicity of dev experience, I'd argue that multiple direct file imports--how inconvenient it may be--is still _simpler_ to get right than "single namespace import" + tree shaking.
> The only thing that still sucks is UI frameworks, because all major frameworks still require a shitty babel workflow in one form or the other. Vue.js has an ESM module which is useless without babel (due to the .vue file format), and Angular/React are still in the lets-invent-our-own-language fatigue.
The pain is real. Create-react-app will dump 250 MB+ of files in node_modules
however, newer approaches are emerging and (hopefully) will be stable soon. few noteworthy ones are:
1. SnowPack[0] (in early access)
2. Vite[1] (from author of Vue.js) . It is in experimental phase. but is quie good.
3. Unnamed project by Author of Preact.
The challenge of JS is and has always been finding a productive corner of all the possibilities of what you can do with it, and optimizing within that corner.
Usually that means picking up a subset of well supported frameworks that you like and find works well in the domain you’re in. It also means learning what language features not to use, or at least abstract away their use. People coming from highly opinionated languages with a large standard library tend to shoot themselves in the foot because they don’t understand this, and nobody really tells them. And inevitably a discussion turns into an argument with different sides becoming Balkanized because they use different parts of the possible language/library set.
Looks to me like a regular workflow and typical gotchas... ability to resolve this and similar is what pays the salary. Is Android, QT, Django, or Java development any more straightforward?
Anegdotally my perception is that people oftentimes think "It's just stupid JavaScript, let me paste it into HTML and run in a web browser, oh wait... why it doesn't work?!".
If you think it's confusing then add Angular to this tiny app (it's from Google so it must be good, right?).
I'm a dedicated Javascript hater, but I don't think this is a Javascript problem. This seems to be how people (not me) have decided all software should be organized now.
My thoughts are its to make something boring and uninteresting into something complex and special - the process of complification I like to call it. Maybe its to charge more to, like the old lawyers charge by the word scam.
So basically the entire series of issues can be rooted to the fact they're trying to run TypeScript code in Node/a browser. This doesn't seem like an issue with "today's JavaScript" but rather a symptom of either not reading the docs or the module not having good docs. I wouldn't be able to compile Java code with a C++ compiler.
Also that the package is published to Node Package Manager with only a TypeScript distribution seems very odd.
I do agree that the Node ecosystem could be easier to use, especially with the myriad of transpilers and build tools. But this doesn't seem like a very compelling anecdote to demonstrate it. Unless the point is that NPM package authors should not be able to publish their package in languages other than Node-flavored JS?
One of the problems with the js community is the idea that it is a good idea to name just about anything that is js-ish in a file with a .js extension. I love Dan Abramov, but I think a large part of the blame for this can be placed on his feet for encouraging the use of js extensions for jsx. This sent a lot of people down a dark path. File extensions serve a purpose. Even more so if you don’t have a standardized header line disambiguating the contents of the file. When you rely on tribal knowledge and sophisticated build tools that rely on strange assumptions or the requirement to parse whole files with different syntaxes just to know what you are looking at you have a problem.
If the c++ community had a tendency to name their java files with cpp, would you be so forgiving?
To be honest, I don't run into much JS code that doesn't have proper extensions, but that's just been my experience for the past 6 or whatever years I've been using Node.js. If I use JSX, I use .jsx as an extension. Likewise for TS and TSX. And CoffeeScript in years past. I can't recall coming across any NPM packages that couldn't run in Node. So I can't really relate. Maybe it's confusing that there's different flavors of JS though with the same file extension: browser-flavored JS and Node-flavored JS.
I wish I could say the same, but nearly half of the teams I've worked with on web development go exclusively with .js because it's been pushed by prominent members of the React community for "ergonomics"[0] (which here is just a fancy way of saying devs can't be bothered to invest the two seconds it takes to make file extensions accurate when switching to a superset language)
The trend of unreliable file extensions has lots of other nasty side effects on IDEs, build tools, and browsers (e.g. [1])
I worked in Facebook briefly, and the reason why Dan (who also is/was at Facebook) might be suggesting this is because this is the practice at Facebook: all "JS" files use the same build system and file extension. Which is to say, there's no JS, or TS, or even CommonJS APIs. It's all and always Facebook-flavored Flow (with the occasional caveat).
And perhaps this is why it didn't seem obvious for Dan (I'm speculating) that anyone would want to use multiple file extensions for things, but when you're outside of Facebook's ecosystem and you have to set up your own build tools and deal with all the pain it comes with, you realize stuff like this makes no sense. Because ya know, maybe targeting by file extension in your build system would make it easier to use the right transpiler (e.g. that's what Parcel does). But that's just been my perspective being in both worlds.
The problem is, these are the Node team's stated goals for ES Modules:
> It is worth mentioning that many of our design decisions were made with two primary goals. Spec compliance and Web Compatibility. It is our belief that the current implementation offers a future proof model to authoring ESM modules that paves the path to Universal JavaScript. Please read more in our documentation.
Sorry guys, those are the wrong goals! Just make CommonJS and ESM be mix and match interoperatable. ESM wasn't designed to be a local disk build system. Just have CommonJS behavior with ESM syntax for god's sakes.
npm i pythag
npm i complex-sqrt
// then
var pythag = require('pythag');
var sqrtrt = (z) => require('complex-sqrt')(z,0);
let x = 3
const y = 4
var result = sqrtrt(pythag(x, y))
236 comments
[ 2.2 ms ] story [ 279 ms ] threadThe ones who don't give up on the first night will likely have more luck (try, try again).
I ran into one with Go imports just the other day, and since I’m new to it, it wasn’t a 10 minute google fix.
Python packaging has historically been so bad that dotcloud invented docker in an attempt to make it usable.
Unless you have a Python version locally that doesn't support some features used in said .py file...
Just importing doesn't seem to work for millions of people:
- https://stackoverflow.com/questions/4383571/importing-files-... (1.5m views)
- https://stackoverflow.com/questions/14132789/relative-import... (215k views)
- https://stackoverflow.com/questions/72852/how-to-do-relative... (325k views)
- https://stackoverflow.com/questions/1918539/can-anyone-expla... (100k views)
- https://stackoverflow.com/questions/1260792/import-a-file-fr... (480k views)
- https://stackoverflow.com/questions/7505988/importing-from-a... (136k views)
- https://stackoverflow.com/questions/9252543/importerror-cann... (700k views)
- https://stackoverflow.com/questions/2325923/how-to-fix-impor... (430k views)
- https://stackoverflow.com/questions/15514593/importerror-no-... (250k views)
Nested `mod`s with sometimes `pub` and then `use` for other stuff certainly seems more complex to me than `import X from P`.
Package/crate management is fairly trivial in both cases, yes. `npm i [package]` isn't exactly a difficult process either.
i don't think it's possible to do that any more with Python, the genie is out of the bottle. but you can get close with things like Black (auto-formatting) and Poetry (nicer deps mgmt and so much more). of course, how would a beginner know this? hopefully some day tools like that will become the default answers
If you want a language that requires zero learning to use, I am sad to say that they are very far and few between. Sure, we have a clusterf*ck of a module ecosystem and interoperability issues between preprocessors but it isn't like that is a particularly novel problem either.
Or, hell, how about the packaging systems in Go or Python? "Yeahhh, we don't really use X anymore, go ahead and use Y."
John certainly failed the perseverance test though.
In John's case, even after he got some help he still couldn't set up and run the project which is really frustating.
oh look, another one
I've used it for some personal projects, but doubt that I'll use it for anything paid anytime soon.
>The cmake build is doesn't work without -GNinja (you do have ninja installed, right?)
>No actually use Bazel/Buck/Pants/Meson
>Oh you installed $DEP, but not the right $DEP with $DEP-X support
>pkg-config can't find $DEP-X
>Pre-build $DEP-X was built with GCC N, and you have GCC N-1, try building from source
>GOTO 1 for DEP-X
I'm embellishing here, but I feel like I always do some version of this song and dance when trying to build a C++ project. And then after all that is done you somehow still end up with linker errors in your final project.
For most people installing some C/C++ library it's just "apt-get install libfoo" (and maybe libfoo-dev), and they never have to deal with ninja/autotools/cmake/etc, whereas for JavaScript you directly have to deal with the tooling by using "npm install libfoo".
The same task mentioned in the article would probably be a lot easier: install package, write some code, "c++ -lfoo main.cpp".
I'm not saying JS is perfect, or that other languages don't have these issues. I haven't used Rails in years but I remember spending a day trying to get a gem installed and figuring out why nokogiri wouldn't compile. Almost every language has these problems.
That's how you get quality user experience. It creates balance between developer of the library/tool and the user of the library/tool.
Most of the time we would create a minimal CMake file to build the library to our specs or adapt the existing CMake file.
With javascript? Well, for instance, take Expo's official release notes for each new SDK and it's right there, as the recommended practice: wipe out your `node_modules` folder and run `yarn` again every time. And good luck not having your `yarn.lock` file randomly changing versions after a while.
It's just a single silly example, but it tells how much more stable the ruby development experience is.
I've been working in JS for years and I've never encountered a module containing a typescript file with a .js extension... That was extraordinarily unfortunate. I don't think I've encountered a module containing Typescript at all. Correct practice is to build to JS and include the optional type declaration files. In my experience people are pretty good about that.
[1] flow.org
The big problem JS has is the same one PHP used to have when it was top dog. Everyone is a fucking noob, including all the people writing all the advice online. I find almost every JS resource to be unbearably bad, with the sole exception of MDN. The vast majority of my learning these days comes from work colleagues who also have a decent level of mastery.
So the real answer is probably that the people getting stuff done are happy with the current state of affairs, because it works for them. And the people that are unhappy are for the most part trying to change the current state of affairs without fully understanding it, and making it worse. I think every language suffers from this to some extent, JS just has a much worse ratio of masters to beginners so the effect is exacerbated.
https://www.npmjs.com/package/esm
The package.json should have something like this if they are going to use import/export statements so anyone on older versions don’t have to worry about it (it’s not native to Node yet without .mjs extension).
We can blame whoever didn’t set that up, or the instructions should have been to just use require().
Since v13, you can use ES modules without the .mjs extension if the nearest package.json includes `"type": "module"`.
Granted, once I understood the ecosystem more, I gradually began to grasp the reason these issues are around. But still, it does make it incredibly frustrating as a reasonably decent coder getting started in JavaScript.
Things have largely gotten much, much better for JavaScript though ever since Node and NPM came along. It's easier to find the right modules to use or at least the right ideas to borrow. Package overload paralysis still happens at times, but I'd personally always rather have more, rather than less choice.
The constant rate of change does make me feel like I'm always re-learning a new way to do the same old job, but luckily for me - learning potentially better ways of doing the same old thing continues to be enjoyable.
I mostly work on the backend.. However, I've done a decent amount of JS too. In fact, back in 2015, even built a lot of the core parts of an SPA using a mix of knockout & requirejs with minified bundles and dynamic loading and so on. Given that it stuff put together from scratch, I though picking things up after a couple of years away from js would be easy. Oh how wrong I was...
In 2017/18 sought to write a starter boilerplate with vue 2, Typescript and .NET Core. I would have probably spent an order of magnitude effort more fixing build issues and warnings than on the project. Once you hit bugs/issues with 3rd party webpack modules (which is almost a given), it is not fun at all.
I recently had to put up a one page visualization and was not looking forward to it. Surprisingly, create-react-app just worked out of the box. Not much of a data point - but still a pleasant experience.
create-react-app is the only thing I've used in the ecosystem that hasn't catastrophically broken for me due to some years-old issue.
Except for monorepos/yarn workspaces, that still doesn't have first class support[0]
[0] https://github.com/facebook/create-react-app/issues/1333
This is precisely how I’ve been building tableofsending.com and it’s been a lovely experience.
You do need some babel/tsc/etc build step to reach a reasonable audience.
The issue with module loading is a pretty fundamental one, though pretty unrelated to web components.
Once you understand it, there are a large number of tools that make them work. The core problem is that most modules available on npm are written with import specifiers that assume the environment supports Node's module name result. Browsers don't, so it won't load something like `import * as redux from 'redux';`
The solution is a tool that transforms package names into URLs. Webpack, Rollup, Parcel, es-dev-server, Snowpack, Vite, unpkg.com, Polymer CLI, and many more do this for you.
More and more of the ecosystem is moving to native modules and we're all going to have to understand this issue.
The particular point of this project was to prove that each successive simplification that my friend proposed, i.e. avoiding Webpack for native ES6 modules, using lit-html instead of React, etc. introduced its own complexity. I'm not saying that these were all bad ideas, but just that they're fundamentally tradeoffs. I'm quite sure lit-html is a great stack. But it's not "better" than React any more than React is "better" than Angular.
[1]: Lack of async/await, or its equivalent, let+ in OCaml 4.08, is a big one. Mediocre typings for browser APIs is another.
I often wonder what the js ecosystem would look like with Google-working-on-Go levels of runtime and package management design discipline.
One would really think Google would do this, especially considering that Microsoft now has veto power over the npm repository and package format. Yarn was a huge improvement but is still dependent upon the same broken backend model.
AFAICT the success of the JS ecosystem is entangled with Google’s success.
Literally nothing about javascript-the-language is why package.json is in a file format that does not support comments, or why node_modules can’t be renamed or hidden or cached properly across projects, or why any of the cryptic import issues encountered by the author of TFA happened, or why yarn had to be made because npm is (or at least was) nondeterministic.
The js packaging tooling sucks, and, more importantly, has continued to suck contiguously for at least ten years. Much like Python and Ruby (cryptographic checksums, anyone?) and Debian/Ubuntu to some extent, I think nobody gives enough of a shit (or has the skills and experience and inclination) to unfuck it, or has just become blind to it over ten+ years of it sucking in the same way (much like autoconf).
It is entirely unfuckable. No part of it is baked into javascript. Go’s was fucked, and they did an epic job of unfucking it with the module and caching system. The same could be done for JS.
It would require forking node to handle imports sanely, and replacing npm/yarn packages (as well as the backend npm package repository they talk to)—surmountable tasks.
Side note: Go has a little bit of baggage. That community is in the process of going from multiple 3rd party package/dependency managers to one official one.
The upside of the JS transformation into just another compiler target is that there is little reason to use JS as the source language, IMO. These JSVM languages do suffer from the same problems to varying degrees.
There is no package.json, typescript, flow, javascript mix, with tens of things configured which change frequently.
Also continuing to work on a python project after a year often is not much of a hassle.
That being said: virtualenvs still seem to be complex matter, especially when you are a beginner.
You can't just distribute arbitrary binaries to users on the web, so web developers have to deal with a layer of complexity that other programs don't have to. That said, maybe WebAssembly will change this story.
yep, other programs totally don't need to deal with different OS, graphics APIs, GPU driverstacks and hardware architectures.
Learning a language involves learning a bunch of non-language arcana about the environment, for no particular reason. Ideally you should be able to write the helloWorld equivalent for any platform and have a single command to turn that one file into a working program, but alas we have tool chains, configurations and requirements standing in our way. I don't think it has to be like that, but it all too frequently is. Deno seems to be making an admirable effort towards making a thing that just works.
Developing for Android or iOS makes the JavaScript experience positively direct.
Is "start a localhost" a generic term? If someone told me to do that, I would probably freeze in embarrassment -- no one has ever told me to do that in such context-independent terms. Since this was about node/JS, did John install express, or some other static file serving module? Or did he have an unrelated tool that makes this trivial?
python3 -m http.server
https://gist.github.com/willurd/5720255 ("Big list of http static server one-liners")
OMG. Decades of life in emacs (emacs!) would never have prepared me for a world where my editor would helpfully lie about the filesystem to me.
Yeah, this was horrifying to read. Obviously some of it is just normal churn, and all environments have their own oral histories and weird quirks. But... yikes.
It's nice for Java style packages that are all "src/com/company/project" before you get into the meat of any code.
I agree though about how surprising it is.
The other day I wanted to publish a little script I've been maintaining for years as a module easily usable by WebPack and whatnot, and that's much easier said than done. I published it on npm and put some UMD magic thing in there, and I think it should work now ... but I'm not really sure to be honest (still need to look at this and confirm).
Just searching "publish JavaScript module" and trying to make sense of the WebPack isn't really all that helpful, not for me anyway, as I'm joining half-way through season 6.
I have no opinion on the tooling as such – I lack experience to have an informed opinion – but it sure is confusing to "quickly" do something for people who are not heavily involved in it (i.e. me)
I use rollup for libraries and webpack only for fullblown frontend projects for precisely this reason.
I disagree. In both cases, you really only need one or two episodes to know that the story is not going anywhere. It will only get more complicated and convoluted without ever rewarding you, you will realize that no thought was ever put into it, and you will only stay for the ride because of sunk costs.
Whoa. That's a name I haven't heard in a long time.
These days you'd just add the right bit to commonJS to say this is an ES6 module.
I am a backend developer and recently I had to start a personal project with _a lot_ of frontend. Googling how to setup minimal webpack config for React (using that react starter app seemed an overkill) took 15 minutes and in another 15 minutes I had a proper minimal hello world. One more hour and I had everything - eslint with standardjs, automatic formatting, everything. Everything just works, react jsx, babel, source maps, everything. For whatever question I has there is an answer one Google search away.
Last time I did something serious on frontend was in 2009 and so far I've written around 2000 lines in JSX with React for my personal project and it's been an absolute _pleasure_ compared to horrors I had to deal with in 2009.
Stop wining and educate yourself, it literally takes 15 minutes.
However, I initially learned some Python in university and I liked it then. We just installed Idle and ran some simple scripts, and everything worked. That's the right way to learn a language. If you dive straight into JS package management, you are attempting to learn multiple things at the same time:
* Node.js environment
* Browser environment
* JavaScript syntax
* 'running a localhost'
* JavaScript modules
* NPM package management
You need to tackle these one by one. If you do them all at once, even with prior experience in other languages, of course you're gonna have a bad time.
Really what I take away from this post is that the author is a bad teacher, although the experience of her student is probably similar to what many people experience when trying to learn by themselves.
There are many improvements that could be made to the JS ecosystem, but this post does not do the current state justice. What it highlights, if anything, is a problem with the available of a standardized learning path. But I'm not sure what the solution to that would be.
I've been working in Python for the last several years. There's definitely a learning curve there, and I get frustrated with things all the time, but the whole JavaScript ecosystem seems like such a mess compared to Python.
One of the things I miss the most about Python when working in JavaScript is the documentation. And I mean the core documentation from Python.org. The Tutorial is amazing [0]. And you can download the entire documentation already in PDF. Maybe I'm one of the few, but when I'm learning something new it is such a better process if I can leave my computer and read through a tutorial and mark it up.
[0] https://docs.python.org/3/tutorial/index.html
Javascript runs directly on the browser. That automatically makes it much more complex because:
1. There are some packages written for browser and some for Node.
2. There are transpilers, abstractions layers, bundlers, etc to make packages run on both environments.
3. Browser based packages need to have all sort of backward incompatibilities in mind (from IE6 to now)
Multiply these 2 and 3 together and you'll see why it's a mess of an ecosystem...
Yet, it only takes a little bit of knowledge and experience to get something working. It's hugely productive.
I mean honestly considering the hand dealt with it (decades of backward incompatibility required), I think the js ecosystem is holding up real well.
of course, if you are new, then this approach may not be obvious
That was about 3 years ago, and I just started using modules. Even then, I use the native browser modules, no Webpack. With HTTP2, there is little cost to requesting many small files.
Likewise, I don't use a CSS preprocessor in any of my projects. They aren't that complicated.
Those projects have no build process. What you write is what you run (WYWIWYR?). If the project is small enough I'll serve its root directory with Python's SimpleHttpServer. Later, I might have nginx do it.
This allows me to get a project running in a minute. I add tools when they are needed, because then I have the motivation to learn them and set them up properly.
Such tools are required if you must coordinate the work of multiple developers. Their cost is divided by the number of devs, and their benefits multiplied.
If you're just a home gamer toying around, you can do without them.
I started using Vue from a script tag a year ago (not that hard). But when I started building an SPA, things got complicated very quickly.
I found myself longing for a really good tutorial similar to Django's [0], rather than the thousand variations of "Today We'll Build a To-Do App in Vue!" that are so common.
For the projects that I work on, I use the same pip/virtualenv setup that I've used for years. Can't imagine that happening with Webpack (Side note: it might be that I could use the same Webpack setup for years, but the unstable reputation around the JS ecosystem makes me think I couldn't).
[0] https://docs.djangoproject.com/en/3.0/intro/tutorial01/
I honestly think the only real solution is re-doing all of it 'from scratch', to make everything (a) stricter and (b) more normal/consistent.
(I think the extant transpilers/preprocessors tend to try to be too 'thin' of a wrapper around CSS/JS: they do give some nice quality of life features but still don't really clean up the mess that is JS and the DOM.)
A person can be a successful programmer for decades and do millions of HTTP operations without knowing the distinction between TCP and IP.
[1] https://github.com/marijnh/crelt
Python3 -m venv env. That’s all it takes.
Sometimes I am in the same boat. Thinking, this should be easy, ending up yak shaving.
For all Python's ease of use language wise it‘s ecosystem can be utterly inscrutable.
No she isn't.
This entire thread is full of the generic excuses one has come to expect from this profession when people struggle with programming setup and running programs. Always a defence of the (broken) status quo.
Something has gone wrong? You didn't read the documentation (the incomplete or non-existing documentation). Or it's actually simple, all you need to do is x, y, z followed by a, b, c - how could you not know that? (Often implied in these responses: you're clearly a clueless noob).
This is quite simply a profession that wouldn't recognise 'simple' if it came and bit it on the arse (or ass).
She wasn’t helping one of her students, she was helping a friend who is a computer scientist. The closing thought was if this person, with so much existing knowledge and some assistance, can’t make one “simple” thing work in a reasonable timeframe, what hope do actual novices have?
Novices should be referred to preset codesandbox.
There's blame to go around but I mostly blame npm for being full of hot garbage while obscuring what is garbage and hot.
If you think learning NPM is hard, try telling a new dev how to setup a Java or C# build by hand. If you think webpack is hard, try teaching someone the intricacies of make.
What about babel? Other languages make breaking changes and dictate that the new version of code just won't be compatible with older stuff. Python 2/3 wouldn't be a blip on the radar if the same option to transpile between versions existed. Those famous "update your .Net version to whatever" warnings simply wouldn't be needed. Instead, people complain that learning a few lines of config is too difficult.
If people put half the time into learning JS that they put into learning the other languages and build tools they know, there would be almost no complaints because the tooling these days just isn't that bad.
The problem is not one of putting the effort in, it's even knowing where to go.
If I want to learn about how to use some new JS library/utility/webpacker, I can probably find about 30 good-quality-looking blogs/articles/documentation pages on how to do it. Most of them won't work, because they'll be out of date. This is hugely frustrating, because you don't know if it's not working because the documentation is wrong, or because you're holding it wrong.
> If you think learning NPM is hard, try telling a new dev how to setup a Java or C# build by hand. If you think webpack is hard, try teaching someone the intricacies of make.
Make is actually a brilliant example of something that's complex and daunting, but ultimately rewarding. It's easy to put the effort in to learn it because the maintainers don't change their minds every 2 minutes about what the Makefile syntax is, so learning how to use it is pretty straightforward. And once you know it, you can understand makefiles written both yesterday and decades ago.
Give me make over webpack any day of the week. I'll put money on which dies first.
Callback hell around 2015. It used to be that if you wanted to do something async you'd have to create a new callback. This led into callback hell[1], which was specially bad back then on the backend.
Luckily after a migration that has taken many years, now most of the libraries use async/await instead of callbacks. There was some time where this was extra difficult because some code was using callbacks and some other code was using async/await, but it's almost totally solved in 2020.
Which brings us to the article on hand. This is probably one of the biggest issues, and a fake promise in Javascript right now: reuse code on the back-end and front-end. The front-end side has been using `import` for almost a decade with Webpack and friends but this was not easy on the back-end, so there was not a practical way of reusing the code in a project.
Luckily since last year Node.js supports import/export, and React supports it in libraries. It took a while because it was not an easy issue. I expect that more and more libraries will start to work only with import/export, and hopefully in 1-5 years this will also be a non-issue.
[3] http://callbackhell.com/
Is that true? I was looking to port one of my C# projects to TypeScript/Node and it uses gRPC and it's not async/await compatible. That's a pretty major library in my opinion.
In the end I didn't end up porting my project because the lack of elegance compared to the C# version was too depressing -- the C# code made heavy use of async and porting without that was just too messy. I'll take another shot at the project once this problem is totally solved.
[1] https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_...
[2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Please note that not all callbacks can (or should!) be converted to promises, e.g. events like `on('click', ...)` don't have a clear way to be promisified since a promise can only be resolved once and stays resolved.
Yikes. I really do not think that was the solution to this problem and only added a ton of complexity.
JS is in a unique position because it can run both code in a browser as well as a server-side/scripting language. In order to do that with any level of success, tooling is required. This tooling (dev server, webpack) builds on other tooling (node, babel, typescript) which is where all this complexity lives.
Furthermore, some packages are not worth installing and if you run into issues with that package, then try something else. We have no information about the package they tried to install and since the JS ecosystem encourages people to publish to npm for virtually anything, this is one area where you really have to be careful.
The lesson here is the same lesson with installing something like left-pad: be careful what you install and read the source code to understand what it is doing. Most of the time, these packages can be inlined easily. Just because a library exists, doesn't mean you should use it. Most of the time for JS I'm reading the library's source code to see if I can a) inline it or b) use it as inspiration to build specifically what I need.
Mind that this was not that much of a problem back in 1997 with Netscape Navigator and Netscape Enterprise Server. I think, the real issue here is that the JS ecosystem is targeting an abstract implementation, rather than a real world one. Much of the tooling is just about turning the abstract implementation into a real world standard and, in a second step, about packaging (i.e. linking).
So long as you have browsers in various states of compliance and paying customers using those browsers, this will always be a problem.
Node works fine out of the box from the command line, modules just need to have the correct instructions for the README.
That’s the reason why I started to love pika.dev ‘s package search. Webpack still sucks and will ruin your day with hours of unnecessary configurations and fixes.
On the other hand, when setting yourself a rule to use plain ESM only without any build system, coding has been a joy.
The only thing that still sucks is UI frameworks, because all major frameworks still require a shitty babel workflow in one form or the other. Vue.js has an ESM module which is useless without babel (due to the .vue file format), and Angular/React are still in the lets-invent-our-own-language fatigue.
Fixed that for you.
React without jsx components is just as useless as Vue without .vue files. If you cannot use the ecosystem of a framework in practice, your framework isn’t a framework anymore.
It's not useless at all. JSX in React is just an alternate syntax for React.createElement calls.
https://dev.to/arswaw/create-a-lightweight-componentized-spa...
Chrome target, native ESM modules, VS Code with JSDoc annotations for types. All libraries (chosen preferentially from microjs.com) are copied into vendor/, and the front end is written in preact.js using htm [0] for native JS tagged html strings, leading to code like:
There's a VS Code extension which formats html`` strings as actual HTML, and the Typescript checker built in to VS Code gives me advanced types and autocomplete, all with a workflow that's as simple as "refresh page".Granted, not every project can afford to target just evergreen browsers, but for my use case it works perfectly and I finally feel like I have the perfect blend of old-style web dev (in terms of refresh cycle) with modern language features and typing. The overhead, both in page-weight and cognitive load, is as small as I can make it.
EDIT: Modified my code sample to show how you can use Preact components in a JSX-like way.
[0] https://preactjs.com/guide/v10/getting-started/#alternatives...
I think the mistake of modern JS (and many other languages) is conflating source files with libraries. A better model is combining many source files into one library file, which provides one toplevel name when imported. A good example is how Three.js, which has a complex internal structure, gets distributed as one file and provides one toplevel name THREE. And of course there are many examples in C-land, where a large library can live behind a single header file. A project should only depend on a handful of those, and there should be few dependencies between them, so package management becomes easy enough to do by hand - just drop a file in your project's vendor/ directory.
As a bonus, this fixes the problem of having many fine-grained imports. If done right, your project's source files might not need any import statements at all. Anything inside the project could be available without ceremony, as if it was all one big file, and external libraries live in a handful of big namespaces which are also available without ceremony.
The pain is real. Create-react-app will dump 250 MB+ of files in node_modules
however, newer approaches are emerging and (hopefully) will be stable soon. few noteworthy ones are:
1. SnowPack[0] (in early access) 2. Vite[1] (from author of Vue.js) . It is in experimental phase. but is quie good. 3. Unnamed project by Author of Preact.
[0] https://www.snowpack.dev/ [1] https://github.com/vitejs/vite [2] https://twitter.com/_developit/status/1264062182326710273
You can build Vue applications without bundler... file is JS extension, you use
const template =` <you html stuff here> `
Usually that means picking up a subset of well supported frameworks that you like and find works well in the domain you’re in. It also means learning what language features not to use, or at least abstract away their use. People coming from highly opinionated languages with a large standard library tend to shoot themselves in the foot because they don’t understand this, and nobody really tells them. And inevitably a discussion turns into an argument with different sides becoming Balkanized because they use different parts of the possible language/library set.
Anegdotally my perception is that people oftentimes think "It's just stupid JavaScript, let me paste it into HTML and run in a web browser, oh wait... why it doesn't work?!".
If you think it's confusing then add Angular to this tiny app (it's from Google so it must be good, right?).
Ironically had they run ng new followed by npm install the import instructions would have worked out of the box.
In today’s javascript landscape you have to pick the template to start your project from, because starting from scratch is way more difficult.
I don't get it. I really don't.
Also that the package is published to Node Package Manager with only a TypeScript distribution seems very odd.
I do agree that the Node ecosystem could be easier to use, especially with the myriad of transpilers and build tools. But this doesn't seem like a very compelling anecdote to demonstrate it. Unless the point is that NPM package authors should not be able to publish their package in languages other than Node-flavored JS?
If the c++ community had a tendency to name their java files with cpp, would you be so forgiving?
[0] https://github.com/airbnb/javascript/pull/985#issuecomment-2...
[1] https://bugs.chromium.org/p/chromium/issues/detail?id=659515
And perhaps this is why it didn't seem obvious for Dan (I'm speculating) that anyone would want to use multiple file extensions for things, but when you're outside of Facebook's ecosystem and you have to set up your own build tools and deal with all the pain it comes with, you realize stuff like this makes no sense. Because ya know, maybe targeting by file extension in your build system would make it easier to use the right transpiler (e.g. that's what Parcel does). But that's just been my perspective being in both worlds.
> It is worth mentioning that many of our design decisions were made with two primary goals. Spec compliance and Web Compatibility. It is our belief that the current implementation offers a future proof model to authoring ESM modules that paves the path to Universal JavaScript. Please read more in our documentation.
Sorry guys, those are the wrong goals! Just make CommonJS and ESM be mix and match interoperatable. ESM wasn't designed to be a local disk build system. Just have CommonJS behavior with ESM syntax for god's sakes.