> Vite works by treating your source code and your dependencies differently. Unlike your source code, dependencies don't change nearly as often during development. Vite takes advantage of this fact by pre-bundling your dependencies using esbuild. Esbuild is a JS bundler written in Go that bundles dependencies 10-100x faster than JavaScript based alternatives like Webpack and Parcel.
I find it useful to have my vendor dependencies compiled and watched for debugging. There are always bugs in deps or poor error messages, and sometimes the dev tools debugger doesn’t work properly, so being able to modify a dev is nice.
Of course it would prob be better if this was a toggle.
I think webpack module federation may improve this situation too. I used webpack all plugin previously to speed up vendor dep compilation.
Thing about webpack though is it’s so complex how all this works that I always have to revisit it every few months to jog my memory.
We need simpler abstractions on top. Next is nice but still, if you need to dive deeper it’s painful.
I think in like 20 years time we will probably be able to get rid of all of this tool chain and the new kids will never know the pains we went through.
It's always impressive to me that, the co-founder of Figma (https://twitter.com/evanwallace) who essentially built a browser in a browser (figma.com) built esbuild. Could honestly be the Woz of our generation.
He has some insanely high quality projects. shout out to his His Kiwi Schema https://github.com/evanw/kiwi project that saved me from protobuff swamp monster hell
Yes but there are some difficulties you may run into when replacing the default loader nextjs uses, because it includes some custom babel plugins that get blown away when you replace the loader with esbuild-loader.
This reads as a very acrimonious, biased take. Authors choose the tools they use based on a number of criteria and personal preferences. It's one thing to disagree with them, it's another to project judgement without knowing the why.
I would posit that perhaps they know better than you.
When pure performance is the concern it makes sense to go to a more performant language, like Go. But every time your JavaScript build tool moves away from JavaScript you close yourself off to a huge pool of potential code contributors and make it a lot more difficult to customise. So I think Vite has it just right: optimise the really intensive stuff, leave the rest more available and more editable.
The speedup from tools like esbuild, swc, etc. are not because of the language they were written in but because they're competing against Babel. Babel is this single-threaded highly-extensible behemoth. On top of this, you're encouraged to install dozens of plugins, and each plugin has access to global state.
The new transpilers have worked around this problem by introducing various limitations. esbuild plugins literally can't modify the AST. It's basically a way for you to run a command on a string/file. So sure, if you redefine the problem as string transforms rather than AST transforms, you can get an O(N) speedup...
Hmmm. I knew I was being a bit of a smartass with, “and thus should know better”, but I figured I mediated that in the second sentence, where I presumed they know what they're doing. ¯\_(ツ)_/¯
Some stats not mentioned in the post. Create React App (webpack) vs Vite (esbuild) on Replit containers:
- 1 second start up time on Vite vs 15 seconds for CRA
- React.js hello world project is 234mb on CRA and only 34mb on Vite
- 1GB RAM for Vite dev server vs 3GB+ for CRA
This is a perfect example of how fast and efficient tools can be, and I think we can do even better! Super excited about the future of JavaScript tooling ecosystem with more focus on efficiency and speed.
In addition to the UX win, and I wish we measured this, but I bet this saved us thousands of dollars in monthly cloud spend.
I don't think Vite has a testing story yet. As for the rest, yes, it totally is straightforward. We only had to change one line of configuration in the base template for it to work on Replit. See https://replit.com/@templates/Reactjs
As the "webpack" guy on my team, these numbers look extremely compelling, but I also know Webpack does a lot for us (e.g., through Webpack v4, it includes browserfied node libs as needed). Beyond node libs, there's a long tail of niche things that need to be taken of... am I trading coverage of that long tail for speed?
Previously I've been a heavy user of Webpack + plugins, but I've now moved over to ESBuild for all new projects. This means letting go of many fancy features, but the overall complexity is so much reduced and I'm a lot happier.
Before: Chain together style-loader, css-loader, postcss-loader and the MiniCssExtractPlugin in some weird way. So complicated to understand which PostCSS plugins interacts with resolving imports. I often need to look into the webpack.config.js to understand how everything work. After: Use PostCSS and its tooling for CSS. Yes, there's now a separate process I also need to run in order to watch and build CSS. Yes, I can no longer `import "./style.css"` from the JavaScript files. But it's so much easier to reason about! The CSS tooling creates a CSS file; the JavaScript tooling creates a JavaScript file. Do I want to build SVG sprites? Well, that can very easily be a separate script which I can debug independently and _not_ couple into my builder's plugin system.
In addition, now my JavaScript files are actually just JavaScript and I can be pretty sure that it will work with any new tooling without any problems. Once the successor to ESBuild comes out I will most likely be able to point it at index.js and everything will work.
> In addition, now my JavaScript files are actually just JavaScript and I can be pretty sure that it will work with any new tooling without any problems.
That's been my feeling for years, too: if your team is less than, say, several dozen people there's a significant amount of merit to having something which doesn't require continous care and feeding for anyone to work, especially when it's combining a number of complex libraries with independent development teams.
This is excellent advice. There's something I really dislike about import "./style.css" into JS files - it just seems meaningless especially if you've worked with other languages/ecosystems. A great many tutorials default to this style, so it'll likely live on for a while.
As yet another tiny UI framework creator (forgojs.org), the switch to esbuild-loader was our best developer experience decision. create-forgo-app (our CRA equivalent) takes 3-4 seconds, and running it is instantaneous. Faster builds actually change the way developers write code.
One great problem it solves is namespacing all of your styles. I don't have to worry about classname collisions because the bundle handles it all for me. Instead of having one massive global stylesheet, I have a bunch of small, modular stylesheets that fit entirely on my display without scrolling, and I can reason about the output much easier than before.
It’s funny to me that we’ve sort of ended up back where I started with Browserify and a seperate Less compile step, or even further back with require.js in some ways.
It’s smart though. Despite having built webpack plugins myself, my main gripe with it was how overloaded it became.
Tree shaking isn't sorted, so can't currently get an bundle optimised to same extent as you do with Webpack/Rollup et al. It'll come, but not quite there yet.
Yes you can, my bad/ But some people have webpack configs, so the easiest for them is to keep those and can use Vite for development. Like if you are not doing new project.
In my experience, the vast majority of use cases are covered by these "no config" tools. If your app isn't a typical CRUD app you might fall into that long tail, but FWIW almost every app I've built has not :)
I'm sure it's less disk space because it has less deps but the most of the RAM and CPU usage in CRA is Webpack so I'd be surprised if that changed much.
webpack AND all the extra plugins and preprocessing and postprocessing CRA adds -- its not a small webpack setup by any means and you can get 1s build times with webpack pretty easily without CRA
Agreed, I use webpack for small and medium projects and it's basically instant. I use TS but not the compiler - I tell babel to strip types and use just a few plugins, transforms and loaders.
I'm not in love but it's a core tool in almost all of my projects, personal and professional.
Exactly: 99% of the time, "webpack is slow" is just code for "I have Babel in my toolchain" and forgetting to set ts-loader as "transpile only".
Personally I removed it years ago, and Webpack 5 even allowed me to get rid of more loaders now that there are Assets Modules that automatically detect assets and webworkers using the "new URL()" syntax, and Typescript does everything else I need.
Even if your target platform didn't have ES6 modules, Babel is probably not the tool you'd want to transpile those with. Let the bundler (which is the topic of the discussion here so I assume a bundler is used) handle them. Tree shaking works better that way anyway.
Also if JSX or similar JS extensions are the only thing you need tramspiling for, you might want to look at Sucrase [1] as a fast alternative to Babel.
Yep, I needed to put together a Webpack build tool chain for React last month & thought it was going to be a bit of a nightmare and it just...wasn't. Tiny bit of fiddling, but generally easy -- that was with a fairly complex setup in terms of the project structure and rules around deployment, so quite impressed after a few years of avoiding it due to how much I hated the song and dance over setting it up.
Most of the build tooling gets installed along the way.
The compiled JS is hundreds of bytes at most, usually because React creates a bunch of boilerplate for you (a basic CSS file, an application, a web worker, etc) which you may remove.
But why would you? This is the silliest way to judge something ever: what practical web application is anyone routinely building with no CSS, web workers etc.
Well, that's part of the jab: that you ostensibly don't need build tooling for an interpreted language, and further, that you don't even need an interpreted language in the first place considering we're talking about a platform that can do UI out of the box via a declarative language.
(Obviously, that's neither here or there when we're talking about baselines for SPAs)
The answer to this question is complicated. JavaScript char encoding is roughly UTF-16, which is 2-bytes, but the byte you read may have been part of a surrogate so, depending on your first one, you must read the next 2 bytes to complete your character.
And of course, this basic explanation doesn’t really do justice to answering your question, because depending on your definition of what a “character” is, you may need to take into account ligatures etc.
The 2-bit part applies, if not the rest, and it’s not really “on disk” but rather “memory for data type,” right?
Given the nature of the questions, I presumed they were interested in knowing “how does JavaScript load strings into memory, anyway?”
And to answer that question, your rough heuristic should be “2 bytes per character” not 1, even for ascii range. That just leads to additional questions, though, because of the oddity of it.
In order to achieve the ability to do Unicode, there’s a reserved set of values within that 2-bytes, to allow you to extend the encoding to reach Unicode.
Back to the original measurement, for the string “hello world”, I believe a JavaScript `sizeof`, if it existed, would report 24 bytes (22 for the characters, and 2 (give or take) for either the NULL character or for a length header.
The thread was originally about CRA vs Vite size on disk (or implicitly, if we're applying it to real world applications, network cost in CI job startup times). And like I said, surrogate pairs don't apply to ASCII.
See this[0] for reference. Note how the first byte must fall within a certain range in order to signal being a surrogate pair. This range quite deliberately falls outside the ASCII range. This fact is taken advantage of by JS parsers to make parsing of ASCII substrings faster by special casing that range, since checking for a valid character in the entire unicode range is quite a bit more expensive[1].
IMHO nitpicking about memory consumption of the underlying data structure is a bit meaningless, since the spec doesn't actually enforce any guarantees about memory layout. An implementation can take more memory for pointer to prototype, to cache hash code/length, etc, and there are also considerations such as whether the underlying data structure is polymorphic or monomorphic due to JIT, whether the string is boxed/unboxed, whether it's implemented in terms of C strings vs slices, etc.
Regardless, it doesn't change the fact that the octet sequence "hello world" takes 11 bytes in ASCII/UTF8 encoding (disregarding implementation metadata).
Considering that projects nowadays have all dependencies installed into their folders, what else is both viable and much smaller? If we had to install everything required for a hello.c into c_modules, including a compiler, libc, etc, it wouldn’t take less than 34mb.
Of course a counter argument is that you don’t usually swap C compilers between projects and libc is stable af, but if a toolchain and/or stdlib was constantly changing and subject to non-compat, you’d have to.
It's worth noting that the tooling and build systems are that big. They include type definitions, binaries, scss preprocessors, typescript compiler, linter, and a lot of other tools to enhance DX. Some of them might include other non-code resources.
You could, since it’s a runtime dep. But a better comparison would be to the client dev tool chains in other ecosystems, like Xcode (11GB), though still not very interesting. Turns out client dev is hard and it doesn’t make much sense hand wringing over dev tool size metrics.
Better to look at how well they solve their problem space.
It’s funny because in order to compile/minify JS it passes said JS to golang which spits out JS to be run under JS. I’m not allowed to be amused by the circularity? Get a grip.
Python is a C core that takes Python code and spits out bytecode to interpret and run said Python. What esbuild is doing is not much different than any other interpreted language.
It's not much different but yet it needs a solution built in another language to "build" it. I understand the process is not much different from other scripted languages but I find it funny that JS cannot reasonably do this itself.
Well, it's wrong to say that it "can't reasonably do this itself" since JS building itself is actually the status quo and has been for years, this particular solution is just a new take with an aim for improved performance.
I wonder how this compares to a proper manual Webpack configuration. Comparing it to CRA isn't really helpful to me, as CRA is already known to be very slow.
I would consider trying it if it has significant performance benefits over a manual Webpack config, especially one making use of esbuild-loader (https://github.com/privatenumber/esbuild-loader)
> It's such a complex and arcane beast, that I doubt anyone could really figure out a "proper" way to do anything with it.
I'm sorry but you sound ignorant here. There are a lot of projects that can get away with around ~200 lines of simple Webpack configs.
And yes, Webpack is complex but an important part of that complexity is coming from the intrinsic complexity of the problem we call module bundling. You can see this complexity in older bundling solutions as well.
Regardless of whatever you'd like to believe, a lot of people figured out proper ways to do a lot of things with it. You may not be willing to deal with this yourself, that is understandable, but saying what you are saying about the most popular bundling tool in the ecosystem is a bit much.
I myself regularly write manual Webpack configs and usually ~200 lines of simple configs are enough for me, as well as very performant. And I know a lot of people like me.
Webpack is not perfect, and I'm not really a big fan, but come on. I guess what you have a problem with is people who write terrible Webpack configurations rather than Webpack itself. Maybe think about it.
The switchover of build tools in JS land is insane. I get that this has concrete performance improvements over alternatives, but I wonder if the same effort put towards improving an existing toolchain wouldn't get you a lot of similar efforts without breaking everything yet again.
That's the beauty of it, if the concrete performance improvements don't seem like a worthwhile tradeoff you don't have to use it. The idea that everyone should just contribute to one package instead of creating their own solutions is just silly, we are not able to dictate what people code up in their own time. Besides, there are dozens and sometimes hundreds of active contributors to every popular open source package, just adding more developers doesn't necessarily make things better, not to mention that the necessary quality control and code review demands for mature projects means many contributions are often misguided or not useful.
A counter point would be to look at the Python ecosystem. They have many fewer libraries but the ones they have are very well maintained and widely adopted.
JS/Node is full of unmaintained projects that people inevitably need to migrate away from.
Of all the new choices in bundlers today, it’s also inevitable that some won’t work out, yet they will drive hype and adoption, which could have been spent on already established tools such as webpack.
Yes, innovation is good and no one should tell someone what to do in their free time.
But it’s always going to be harder to build on top of old rather than to write something new, but what is new eventually becomes old...and the cycle repeats.
> A counter point would be to look at the Python ecosystem. They have many fewer libraries but the ones they have are very well maintained and widely adopted.
So what? It is what it is - the python ecosystem faces completely different challenges than the JS ecosystem, if the browsers exclusively ran Python instead of JS it would be the exact same situation for Python.
> JS/Node is full of unmaintained projects that people inevitably need to migrate away from
This isn't true. jQuery, Angular.js, Angular, React, Vue etc are all still maintained (check their githubs if you are in doubt) and all still work just fine, so if you want to use the same tooling you did a decade ago that's totally possible.
> it’s always going to be harder to build on top of old rather than to write something new
So what? If you want to contribute to old projects instead of writing something new you're free to do that, and if you don't like new stuff you don't have to use it, complaining about this stuff is just pointless contrarianism, but of course, you're free to do that too.
It isn't contrariarism. The end result is that most JS libraries are immature, have complex edge cases that can only be fulfilled by one package but not from another similar package, and that old packages don't evolve to adapt to new paradigms.
Knowing that pretty much every Python dev knows how to use requests, Django, and NumPy means saving a huge amount of effort in retraining and fighting to pick and choose on choices of ultimately little value.
AFAIK Axios isn't even universally used for requests, and in the SPA framework space it seems to be a split between Angular and React in popularity. None of these things seem to be occurring in the Python space.
Nothing is universal, you're seeing what you want to see. I could say the same thing about django, flask, and web2py or numpy and panda, or trio and asyncio.
Django doesn't occupy the same space as flask; not in the same way React and Vue seem to. Web2py is nonexistent. Numpy is a basic linear algebra library and Pandas is a high-level tabular data analysis library.
None of these things compete with each other in any meaningful way.
This is just wrong. Django absolutely occupies the space as Flask, this is pretty obvious, but you're splitting hairs to defend your argument - the bottom line is that a Python developer building a web application has to decide if Django or Flask is a better choice for their engineering needs, you wouldn't use both (though you could, same as you could use react and vue together).
> Web2py is nonexistent
This is totally wrong. You can selectively discard every example that doesn't meet your arbitrary standard of popularity, but I could just as easily discard a criticism of Vite which is far more "non-existent" relative to webpack than web2py is to Django
> Numpy is a basic linear algebra library and Pandas is a high-level tabular data analysis library.
Once again you're splitting hairs. Yes, Pandas and Numpy have different specialties, but there is clear overlap between them and a developer who is unfamiliar with the ecosystem wouldn't necessarily understand why e.g. they might choose pandas dataframes vs numpy arrays, and this dynamic is also true in the JS world where different packages have overlap but particular specialties that make one more attractive than the other depending on the needs.
You can switch to esbuild now or you can switch later, but you will switch. It is superior in design, configuration and performance by orders of magnitude.
Webdev truly is one of a kind. Not only do you have your source code, you also have your build code, oddly dictating the organization of your source code. For extra fun, some libraries don't build with build system a, others require build system b, when you're lucky enough to have a working mix, changing build systems is better to be avoided. Of course periodically the officially blessed build system for your used libraries changes.
The webdev ecosystem is so broken, it's no wonder so many websites deliver assets that are extremely suboptimally optimised, big unused blobs of assets /scripts slowing page load, optimising it all is actually made harder than coding it all.
Hate to break it to you but Clojurescript, Elm and the whole paradigm of "compile to JS" languages are part of what is broken about the javascript ecosystem. So much unnecessary complexity and energy wasted making javascript pretend to be something it isn't and to make it do things it was never meant to do, pressing a small, simple and powerful scripting language into the service of the profane eldritch abomination that is Enterprise Development.
I dunno, I feel that’s like saying that Lisp and Haskell are part of what’s broken about the machine code ecosystem.
ClojureScript and Elm aren’t compile-to-JS languages for the sake of doing something weird, there’s just literally nothing else that will run in a browser (except wasm but probably best not to get into that).
Different programming languages exist for a multitude of valid reasons, the compiled output isn’t particularly important as long as it can express everything you need it to.
> I dunno, I feel that’s like saying that Lisp and Haskell are part of what’s broken about the machine code ecosystem.
It would be if machine code were another high-level text-based language completely unrelated to either Lisp or Haskell with its own semantics, execution model and type system rather than a more directly machine-readable format of those languages themselves.
Javascript is fundamentally different enough from a bytecode for any arbitrary language that, at least to me the distinction matters. I can accept that it works well enough that most people don't care, even though I suspect most of the use cases for doing so (error checking, type checking) could be better served with linters or editor tools for JS itself.
But the decision to avoid actually writing javascript at all costs has contributed a great deal of complexity in the JS ecosystem, which translates into the bloat in the web that everyone complains about, because all of that javascript is wasting time and cycles simulating other languages.
> But the decision to avoid actually writing javascript at all costs
Who's JavaScript is it anyway? ES7? ES6? Internet Explorer 11's? How do you isolate things for the sake of unit tests and then bring them together into a performant build?
Hate to break it to you, but what you call "Enterprise Development" is really just "large software projects", for which many find the "simple and powerful scripting language" inadequate.
Are you using JavaScript when you are using TypeScript? I guess so, to some degree. The additional tooling complexity is just not that significant compared to the gains of a language that compiles to JavaScript vs using vanilla JavaScript.
Also Trunk [0] for Rust-wasm web dev. It’s made me not hate doing the front end for my projects. I look forward to the Rust web ecosystem evolving to the point where I can recommend it in a work context.
I added the dependency by writing about three CMake lines.
And after that, it just works, for years.
I may have to add from 2, to 5 dependencies for a project, instead of the myriad of dependencies in JS. And they don't become obsolete and need an update each week.
It's a difference of some orders of magnitude, both in number and in upgrade frequency. This is a huge part of dependency management for me.
And there are C++ package managers like Conan, which solve your requirement of adding a dependency by just using the command line.
I will probably use Conan if I have to write C++ again.
CMake only finds the dependencies, how do they get to your computer? Do you link statically or dynamically? What compiler toolchains are these libraries built with, do they use the same standard library as your code or different ones? When you want to cross compile, how do you find libraries for your target architecture?
Conan makes much of this easier, but is not really suited for large software projects with the problems mentioned above - in my experience.
Well, I don't cross compile. If I need to test a new OS, then I get the VM and compile it there.
About dependencies, if they can be found in the package manager then it goes that way. Else, they are a git submodule.
The most problematic has indeed been the C++ MySQL connector, because it has changed a bit over the last five years, so I had to edit the #include lines in the source code files.
> you also have your build code, oddly dictating the organization of your source code
It... really doesn't? You generally have an entry point file - which can be any file, you just have to specify it to your build system - and import statements are followed from there on. If anything you could argue the JS build ecosystem is too flexible (which is one of the things esbuild is pushing back against). I've never heard someone criticize it for being too opinionated.
> For extra fun, some libraries don't build with build system a, others require build system b
I've literally never encountered this problem. Library authors virtually always ship least-common-denominator JS that will work without using a build system at all, and then build systems know how to handle lots of different variations of JS and converge them into a single representation. Compatibility is not an issue that exists in my experience.
> The webdev ecosystem is so broken, it's no wonder so many websites deliver assets that are extremely suboptimally optimised, big unused blobs of assets /scripts slowing page load, optimising it all is actually made harder than coding it all.
Now you're just airing your own personal beef which doesn't actually have anything to do with the original topic.
You enable sourcemaps on Webpack with `devtool = "eval-source-map"` in your config, and I'm not sure how you expect transpiling to be a problem with testing considering your tests are also transpiled.
Have you seen the android build system? I mean what the hell is a gradle wrapper. At least js tools are configured in .json or .js files not in a special purpose programming language.
I don‘t mean to discuss which system is too complicated and which is not just to point out a lot of real world build systems are on that level.
Android apps are written in Kotlin, and Gradle config is also written in Kotlin. How come it is different from the JS situation? Even though Gradle can be configured in Groovy, and Android apps can be written in Java, it is still the same ecosystem - basically, the situation of TypeScript/PureScript/WhateverScript and JavaScript.
Gradle wrapper is just a name for a script (automatically created by Gradle btw) which allows one not to have any kind of Gradle-related tooling installed on the machine (basically, to run build tasks you execute `./gradlew someTask`, and it takes care about downloading and running the appropriate Gradle version) - which I think is a clear benefit over the fact that you need to have `npm` installed system-wide or via a tool like NVM in order to build JS projects.
Gradle has its own warts, and a lot of them, but at least there is only one major build system in this area, and it is simply impossible for a library published to a Maven repo to be dependent on the build system it is built with.
Webdev can be broken, but doesn't have to be. I am currently having fun & feeling productive on both a large team project and some small personal projects.
For personal projects I just use plain javaScript, ES5 even, without any compile steps, everything loads instantly and runs on every browser that supports JavaScript, and the development can be set up in any environment/OS without headaches.
I do use minification for production but that is not really necessary if the browser supports loading JS-script tags async (all major browsers). The bundle gets very small without any frameworks attached. Debugging is easy with the browser built in dev-tools - with small error messages that always have the correct line (eg. no source maps). I'm currently working on a 100,000+ line JS project that uses the plugin pattern with script tags and it's very manageable, adding new features is fast and fun.
There are of course trade-offs, I can't just "npm install react-x-y-z", but the browser API's are extensive, you can do just about anything on the front-end with just the native browser components and API's.
I really love TypeScript. But I have always considered the end game of TypeScript to be that it’s inference engine (and third party libraries) become so good that you can just can write ECMAScript and get all the benefits of typescript.
I wouldn’t give up all my structural type inference for the 1:1 you’re describing, but it is tempting.
FE web developer is one of a kind and there are good reasons for that. I keep seeing the same responses pop up all the time so I decided to write my thoughts down on why FE web dev is a black swan in software development: https://erock.io/2021/03/27/my-love-letter-to-front-end-web-...
I haven't tried Vite, but I tried ESBuild last weekend on a personal project and was absolutely blown away. Even as someone who's become pretty comfortable working in the Webpack trenches, I don't see myself starting a new project with Webpack ever again. There's just no reason to when you can get the exact same output, much faster, without any of the headaches.
Honestly it's so good I wonder if it will undercut Deno a little bit by lowering the barrier for bootstrapping a TypeScript project
I tried out both snowpack and esbuild recently, and while the approach of using es modules was neat, these tools are still wildly immature compared to webpack.
Need to handle non-js assets in your bundle?
Need to integrate into both node and browser environments?
You should stick with webpack. Any time you lose waiting for webpack to run you will get back 10x over by not fighting with your tooling because it doesn't handle a set of use cases you have.
I'm sure the next generation of build tools and bundlers will mature over time and we'll all get to enjoy the benefits of es modules, but right now webpack's mature plugin ecosystem, documentation, and stability makes it my default choice.
> Any time you lose waiting for webpack to run you will get back 10x over by not fighting with your tooling because it doesn't handle a set of use cases you have.
Generally I think this is good advice for tools--stick with the mature thing. But my former company's webpack builds were 30+ minutes for a relatively simple site. No doubt something was misconfigured, but you really have to be a webpack expert to get any sort of insight into where the time is going, and even then it may not be especially actionable (or at least not obviously so). In our case, we were using a monorepo and we didn't have something like Bazel, so this was painful for backend engineers, data scientists, etc--not just frontend engineers.
Maybe our case was pathological, but we would have saved a ton of time moving to esbuild and building whatever additional features we needed from scratch.
I feel like there just needs to be a good plugin that gives you proper stats as to how long things are taking and tips to improve things.
It’s usually slow css loaders, or too-inclusive patterns for loaders ending up processing node_modules, and not good enough disk caching.
There is a plugin called smc to monitor loader execution time.
Dll plugin was the best speed up to avoid recompiling things that don’t change, but now module federation is suppose to be a better solution. Disk caching in v5 will also do great things.
Thing is, it’s so complicated to setup, and debugging it involves so much config tweaking ans waiting.
I think we are a few years out from when we have nice speedy builds in webpack with good abstractions.
But then it’s a question of whether people move away from webpack because we don’t need all the plugins and transpiration and want native compile speeds.
One thing for certain though is the hype cycle will continue on...
Your experience mirrors mine to a letter - I appreciate the wide variety of use cases that are covered by Webpack (a number of which are crucial to our build process), but its performance is abysmal (20m+ on CI) and totally inscrutable; making the potential switch from it rather enticing.
Especially as seeing that there is no good solution (but a lot of attempts at them), I feel it somewhat points to this overcomplexity being a problem central to Webpack.
I wasn’t a frontend developer, so I’m not familiar with the details, but it seemed to be pretty slow from the start, but compounded as our app grew in size. I.e., there was some large coefficient associated with our web pack configuration.
How large was the bundle at the end? I'm not going to claim that webpack is fast for large applications, but I've never seen a build take longer than 3 minutes and this is for applications where our own source code was at the MB scale.
I paired snowpack and webpack together and got something that I can use to mostly get a build pipeline going.
Snowpack's latest releases have been... troublesome, but we've stuck with 3.0 and it's been good enough. It completely doesn't support some libraries, but other than that it's been tolerable. Knowing what I know now I probably wouldn't have invested in Snowpack quite yet.
Really hoping Snowpack stabilizes a bit more, or we'll probably just fall back to webpack (or maybe Vite?) again.
I have tried to use esbuild, and over the past 3 months I had at least a dozen times when it has compiled incorrect code that doesn't work or doesn't do what it's supposed to do. So despite the performance benefits, I was forced to go back to webpack, babel, and terser.
Did u try using typescript with esbuild? React + esbuild + typescript is a perfect combination for me. I had the chance to kick off a new project a few months ago and started with this stack. It needed roughly 50 lines of code to get a decent server side rendering development experience set up. Compile time is still below 200ms.
The only issues I had in the beginning was esbuild's compilation of typescript enums: the import order was off from time to time. Besides that, no issues. I am also super glad I do not need to configure webpack any longer.
I recently ported a microfrontend based frontend to webpack 5 and replaced babel/terser with esbuild and the builds are 50%-60% faster now. I couldnt replace webpack because I am using Module Federation which is not available in other bundlers. Would recommend this approach if not possible to fully replace webpack.
I literally just spent days trying out Vite and comparing it to Webpack 5, and I can comfortably say that they are in two very distinct leagues. It isn't fair to compare Vite to a CRA build with Webpack. You can greatly improve Webpack's performance by:
* Making sure `mode` is set to "development" (don't specify it all if in doubt)
* Ditching babel-loader and using esbuild-loader instead
* Adjusting build targets and making sure polyfills are not added in development
* Making sure you don't import the entirety of libraries like Lodash and MomentJS (prefer date-fns)
* [FUTURE] We'll soon be able to tell Webpack to output ES modules just like Vite [1]
Vite still has many problems:
* It just isn't suitable for proper server-side rendering, we'd need access to chunk names at build time
* It has a weird mix of own and Rollup config settings that seems somewhat unpredictable
* Many open issues regarding module imports, for ex, when a CJS module imports an ES one [2]
Our current bottleneck with Webpack is actually sass-loader, taking at least 70% of the time during a fresh build, and we'd have the same problem with Vite.
Something else that is worth pointing out is the ecosystem: Webpack's community has built tons of plugins for basically any use case you can imagine, and version 5 supports module federation, persistent caching, externals (very handy when doing SSR), customizable filename generators, performance hints, etc etc. Totally different game.
Try to keep your build config simple, avoid too many loaders, plugins, and you should be fine 99% of the time. If you hit a wall, install speed-measure-webpack-plugin to get some help.
If you figure out how to get Webpack to solve all these issues, that makes one working Webpack installation. When Vite solves their issues, all Vite installations will have the issues solved.
Vite is not a completely opinionated tool. You can still customise its behaviour and use plugins, so both installations would have very similar vulnerabilities at the end. For SSR, you need a self-written server entry point.
Webpack 5 has introduced asset modules, so now you can safely ditch raw-loader, url-loader and file-loader. [1]
>* It has a weird mix of own and Rollup config settings that seems somewhat unpredictable
Oh god, this is a giant red flag. This is precisely one of my biggest gripes with Quasar (a Vue framework), which, on top of webpack/vue adds its own config that are intermingled with vue's and webpack's, and its honestly a mess, and oftentimes just straight up makes problems harder to solve.
I am obviously not railing against config dedicated to a single tool in a toolchain, but the way you described it rings a bell, especially the "unpredictability".
>* Many open issues regarding module imports, for ex, when a CJS module imports an ES one
This also seems to confirm my and other's suspicion, that the tool isn't really "deliver-grade".
>If you hit a wall, install speed-measure-webpack-plugin to get some help.
But on the other hand, this is at least the fifth plugin I have heard someone recommend, dedicated just to profiling Webpack.
What do you think about the time difference shown in the article? I sort of feel it's a bit disingenuous since the test included a lot of other variables, but it seems hard to argue against it if it's this plain. Is this a config issue, or a "most commonly used loader" issue...?
I'd be dishonest if I told you I was able to compare them 1-to-1. I couldn't finish my Vite setup because of bugs and lack of proper SSR support.
I believe that, at this point, people are just nitpicking. When working on a client-side-only app, Vite is faster, but not by that much. In one of our apps, I saw it starting up in 1s compared to 2s with Webpack, and reloads in 100ms compared to 250ms. This is a Preact/TS/Emotion app that outputs almost 7MB of assets, 61 files to be precise, and works on IE11. And I hadn't even tried persistent caching with it yet. Webpack 5 with esbuild is a fast-enough solution.
NextJS is a well-established tool now and version 10.2 uses Webpack 5 under the hood. V11 is looking insanely fast (I suspect they replaced Babel with esbuild, and did some witchery): https://twitter.com/shuding_/status/1378086219708473344.
So yeah, slow performance with Webpack is definitely caused by a bad set of loaders/plugins. Eject a CRA app and you'll see a monster coming out.
> It just isn't suitable for proper server-side rendering, we'd need access to chunk names at build time
You can at later rollup hooks (it doesn't make sense to access chunks that don't exist yet).
Actually, there are SSR frameworks being built on top of Vite such as SvelteKit [1] or vite-plugin-ssr [2] (vite-plugin-ssr is not a framework but gives you a similar DX than Nuxt/Next.js; I'm its author), and many people are implementing custom SSR solutions.
Have you seen SvelteKit's source code? It looks like a toy project. [1]
vite-plugin-ssr can't even be integrated with Vue Router (I saw you're working on deep integration though). They're both very rigid, early stage endeavours. [2] What happens, for ex, if you used nested lazy components in those pages, are they going to be included in the server render as well?
I mean, fair enough that there are people trying to do better, but it's extremely hard to find the right abstractions for such complex builds and Webpack is definitely on top here.
I mean, if you think vite-plugin-ssr to be rigid, then Next.js should feel like a 2sqm prison cell to you ;-).
If you want more flexibility than vite-plugin-ssr then use Vite's native SSR API.
Whereas with webpack: good luck with 1. using two webpack configs (one for Node.js and one for the browser), 2. synchronising between these 2 webpack configs, 3. implementing server-side HMR; it's incredibly painful and can cost you many weeks of dev time... whereas Vite's SSR API does all of this for you for free.
Sure, things are early stage, but saying that webpack is "definitely" on top for SSR is wrong in virtually any possible way.
We just switched from TypeScript/ts-node to esbuild for server-side code at Notion; it's been great. Would love to see the same kind of speed wins for our clients :')
We’re using a node -r esbuild-loader.js kinda thing with very simple mtime-based cache. It’s like 50 lines; we opted to write our own because we wanted the absolute latest version of esbuild so we could use the recent speed ups to the sync interface.
Thanks for reminding me I'm getting old and corporate.
My first two thoughts were:
* Imagine all the smart people in webdev world would improve the existing tool rather than create a new one. [0]
* "if you do less, it will go faster". I.e. Vite is young and new, supports a subset of Webpack and of course boasts how fast it is. Yet my repos can't use it because it doesn't has the support it needs for my repo sizes with legacy stuff. Of course it is "on the roadmap" and by the time it will be supported Vite is as slow (if lucky) as Webpack. Doesn't matter though as a new tool will be there long before Vite reaches Webpack..
Yup. Getting old and also cynical in the evenings. Dammit!
If you want to learn more about Vite, I recommend that you join Vite Land (https://chat.vitejs.dev). There is a very active and helpful community, and there are tons of opportunities to collaborate in the creation of plugins, integrations, and to improve Vite itself.
How do people using Vite deal with Common JS dependencies? As far as I tried, there were issues with those when using "vite dev". Sadly, at this point, I can't get rid of those (e.g. protobufs+grpc-web generated code).
I've been using vite for a while now and it has been super painless. However I use it in a pretty straight forward manner, about the most "advanced" thing I use is a proxy to redirect web requests to the backend during development. I haven't played around with things like SSR yet which is currently marked as experimental.
What about using native es6 imports cached by a service worker? If you don't have to support old browsers, this is a much better option than a compile step. Just pull from git and load it in your browser, no complications eating a weekend reading through docs and shotgun debugging.
I can't share code yet but we are working on potentially open sourcing it. We have a no-build policy, so just raw JS. Using an in-house web component framework similar to LitElement. There is a minimal deploy step that creates a manifest that hashes all files in the repo, and the service worker uses this manifest to determine if a file is cached or not, and serves it up if so. Service workers can intercept network requests so they work great for this. The win here is if you change a couple files, only those files need to be downloaded and cached.
My position on web development for even consulting projects is just to not use build processes as much as possible. I still end up using them for things like JSX, but I don’t bundle anymore, nor do any web projects I build require installation out of the box.
I’ve found that by doing so, I can just basically ignore, for years on end, all of the peddlers pushing how their projects make development easier or faster or some nonsense.
You know what’s easiest and fastest? Flat files in a good directory structure with some getting started template.
That’s it. The fastest build times are the ones that don’t exist. Period.
Web development is as complicated as you choose to make it. Very few fields work like this.
...which is essentially cargo cult programming, since browsers work in an entirely different way (perhaps with the exception of WASM because of how it's designed).
When I learned about Prolog in university I had a "eureka" moment where I wondered why I was spending all this time learning to implement algorithms in imperative code, when I could just express the output I want and then let some über constraint solver figure out how to produce it. How liberating declarative programming would be if only we started coding with it more.
When I try to use Webpack, as I click through obsolete StackOverflow posts, trying to figure out the right key-value pairs to get the output I want, I realize how mistaken I was. I hope build tools for the web become less "magical" and more predictable and debuggable, even if it means discarding their declarative form.
228 comments
[ 3.0 ms ] story [ 209 ms ] thread> Vite works by treating your source code and your dependencies differently. Unlike your source code, dependencies don't change nearly as often during development. Vite takes advantage of this fact by pre-bundling your dependencies using esbuild. Esbuild is a JS bundler written in Go that bundles dependencies 10-100x faster than JavaScript based alternatives like Webpack and Parcel.
Of course it would prob be better if this was a toggle.
I think webpack module federation may improve this situation too. I used webpack all plugin previously to speed up vendor dep compilation.
Thing about webpack though is it’s so complex how all this works that I always have to revisit it every few months to jog my memory.
We need simpler abstractions on top. Next is nice but still, if you need to dive deeper it’s painful.
I think in like 20 years time we will probably be able to get rid of all of this tool chain and the new kids will never know the pains we went through.
I presume this is a considered choice, and that what Vite does is unlikely to be on the critical path for edit/build/view cycle time…
This reads as a very acrimonious, biased take. Authors choose the tools they use based on a number of criteria and personal preferences. It's one thing to disagree with them, it's another to project judgement without knowing the why.
I would posit that perhaps they know better than you.
When pure performance is the concern it makes sense to go to a more performant language, like Go. But every time your JavaScript build tool moves away from JavaScript you close yourself off to a huge pool of potential code contributors and make it a lot more difficult to customise. So I think Vite has it just right: optimise the really intensive stuff, leave the rest more available and more editable.
The new transpilers have worked around this problem by introducing various limitations. esbuild plugins literally can't modify the AST. It's basically a way for you to run a command on a string/file. So sure, if you redefine the problem as string transforms rather than AST transforms, you can get an O(N) speedup...
* Transform the file using esbuild first
* Then use Babel with that one specific plugin (Loadable Components, Styled Components, Apollo, React Refresh...)
This is much faster than letting Babel do all the work.
- 1 second start up time on Vite vs 15 seconds for CRA
- React.js hello world project is 234mb on CRA and only 34mb on Vite
- 1GB RAM for Vite dev server vs 3GB+ for CRA
This is a perfect example of how fast and efficient tools can be, and I think we can do even better! Super excited about the future of JavaScript tooling ecosystem with more focus on efficiency and speed.
In addition to the UX win, and I wish we measured this, but I bet this saved us thousands of dollars in monthly cloud spend.
How is the configuration overhead? Is it relatively easy to get Vite + a custom react app template + tsx + testing up and running?
CRA is bloated, but still one of the fastest ways to get a "full app" up and running with React.
Before: Chain together style-loader, css-loader, postcss-loader and the MiniCssExtractPlugin in some weird way. So complicated to understand which PostCSS plugins interacts with resolving imports. I often need to look into the webpack.config.js to understand how everything work. After: Use PostCSS and its tooling for CSS. Yes, there's now a separate process I also need to run in order to watch and build CSS. Yes, I can no longer `import "./style.css"` from the JavaScript files. But it's so much easier to reason about! The CSS tooling creates a CSS file; the JavaScript tooling creates a JavaScript file. Do I want to build SVG sprites? Well, that can very easily be a separate script which I can debug independently and _not_ couple into my builder's plugin system.
In addition, now my JavaScript files are actually just JavaScript and I can be pretty sure that it will work with any new tooling without any problems. Once the successor to ESBuild comes out I will most likely be able to point it at index.js and everything will work.
That's been my feeling for years, too: if your team is less than, say, several dozen people there's a significant amount of merit to having something which doesn't require continous care and feeding for anyone to work, especially when it's combining a number of complex libraries with independent development teams.
As yet another tiny UI framework creator (forgojs.org), the switch to esbuild-loader was our best developer experience decision. create-forgo-app (our CRA equivalent) takes 3-4 seconds, and running it is instantaneous. Faster builds actually change the way developers write code.
It’s smart though. Despite having built webpack plugins myself, my main gripe with it was how overloaded it became.
I'm not in love but it's a core tool in almost all of my projects, personal and professional.
Personally I removed it years ago, and Webpack 5 even allowed me to get rid of more loaders now that there are Assets Modules that automatically detect assets and webworkers using the "new URL()" syntax, and Typescript does everything else I need.
https://webpack.js.org/blog/2020-10-10-webpack-5-release/#as...
Also if JSX or similar JS extensions are the only thing you need tramspiling for, you might want to look at Sucrase [1] as a fast alternative to Babel.
https://github.com/alangpierce/sucrase
The compiled JS is hundreds of bytes at most, usually because React creates a bunch of boilerplate for you (a basic CSS file, an application, a web worker, etc) which you may remove.
(Obviously, that's neither here or there when we're talking about baselines for SPAs)
The actual languages are often Typescript and jsx, to say nothing of the Svelte compiler or Elm.
You can write vanilla JS without all that, of course.
And of course, this basic explanation doesn’t really do justice to answering your question, because depending on your definition of what a “character” is, you may need to take into account ligatures etc.
Given the nature of the questions, I presumed they were interested in knowing “how does JavaScript load strings into memory, anyway?”
And to answer that question, your rough heuristic should be “2 bytes per character” not 1, even for ascii range. That just leads to additional questions, though, because of the oddity of it.
In order to achieve the ability to do Unicode, there’s a reserved set of values within that 2-bytes, to allow you to extend the encoding to reach Unicode.
Back to the original measurement, for the string “hello world”, I believe a JavaScript `sizeof`, if it existed, would report 24 bytes (22 for the characters, and 2 (give or take) for either the NULL character or for a length header.
See this[0] for reference. Note how the first byte must fall within a certain range in order to signal being a surrogate pair. This range quite deliberately falls outside the ASCII range. This fact is taken advantage of by JS parsers to make parsing of ASCII substrings faster by special casing that range, since checking for a valid character in the entire unicode range is quite a bit more expensive[1].
IMHO nitpicking about memory consumption of the underlying data structure is a bit meaningless, since the spec doesn't actually enforce any guarantees about memory layout. An implementation can take more memory for pointer to prototype, to cache hash code/length, etc, and there are also considerations such as whether the underlying data structure is polymorphic or monomorphic due to JIT, whether the string is boxed/unboxed, whether it's implemented in terms of C strings vs slices, etc.
Regardless, it doesn't change the fact that the octet sequence "hello world" takes 11 bytes in ASCII/UTF8 encoding (disregarding implementation metadata).
[0] https://github.com/jquery/esprima/blob/0911ad869928fd218371b...
[1] https://github.com/jquery/esprima/blob/0911ad869928fd218371b...
Of course a counter argument is that you don’t usually swap C compilers between projects and libc is stable af, but if a toolchain and/or stdlib was constantly changing and subject to non-compat, you’d have to.
Well they can't get worse than now... 234mb for a friggin hello world app
The hello world app is not going to be this big.
Better to look at how well they solve their problem space.
A JS library calling a golang js-build tool to get the job done. Too funny.
(p.s. JS is not compiled)
(p.s. I'm aware)
https://github.com/preactjs/wmr
I would consider trying it if it has significant performance benefits over a manual Webpack config, especially one making use of esbuild-loader (https://github.com/privatenumber/esbuild-loader)
What is a "proper webpack config".
It's such a complex and arcane beast, that I doubt anyone could really figure out a "proper" way to do anything with it.
I'm sorry but you sound ignorant here. There are a lot of projects that can get away with around ~200 lines of simple Webpack configs.
And yes, Webpack is complex but an important part of that complexity is coming from the intrinsic complexity of the problem we call module bundling. You can see this complexity in older bundling solutions as well.
Regardless of whatever you'd like to believe, a lot of people figured out proper ways to do a lot of things with it. You may not be willing to deal with this yourself, that is understandable, but saying what you are saying about the most popular bundling tool in the ecosystem is a bit much.
I myself regularly write manual Webpack configs and usually ~200 lines of simple configs are enough for me, as well as very performant. And I know a lot of people like me.
Webpack is not perfect, and I'm not really a big fan, but come on. I guess what you have a problem with is people who write terrible Webpack configurations rather than Webpack itself. Maybe think about it.
The switchover of build tools in JS land is insane. I get that this has concrete performance improvements over alternatives, but I wonder if the same effort put towards improving an existing toolchain wouldn't get you a lot of similar efforts without breaking everything yet again.
JS/Node is full of unmaintained projects that people inevitably need to migrate away from.
Of all the new choices in bundlers today, it’s also inevitable that some won’t work out, yet they will drive hype and adoption, which could have been spent on already established tools such as webpack.
Yes, innovation is good and no one should tell someone what to do in their free time.
But it’s always going to be harder to build on top of old rather than to write something new, but what is new eventually becomes old...and the cycle repeats.
So what? It is what it is - the python ecosystem faces completely different challenges than the JS ecosystem, if the browsers exclusively ran Python instead of JS it would be the exact same situation for Python.
> JS/Node is full of unmaintained projects that people inevitably need to migrate away from
This isn't true. jQuery, Angular.js, Angular, React, Vue etc are all still maintained (check their githubs if you are in doubt) and all still work just fine, so if you want to use the same tooling you did a decade ago that's totally possible.
> it’s always going to be harder to build on top of old rather than to write something new
So what? If you want to contribute to old projects instead of writing something new you're free to do that, and if you don't like new stuff you don't have to use it, complaining about this stuff is just pointless contrarianism, but of course, you're free to do that too.
Knowing that pretty much every Python dev knows how to use requests, Django, and NumPy means saving a huge amount of effort in retraining and fighting to pick and choose on choices of ultimately little value.
> Knowing that pretty much every Python dev knows how to use requests, Django, and NumPy
This isn't true, but even if I grant this to be true, you could just as accurately say pretty much every js dev knows node, axios and react.
None of these things compete with each other in any meaningful way.
This is just wrong. Django absolutely occupies the space as Flask, this is pretty obvious, but you're splitting hairs to defend your argument - the bottom line is that a Python developer building a web application has to decide if Django or Flask is a better choice for their engineering needs, you wouldn't use both (though you could, same as you could use react and vue together).
> Web2py is nonexistent
This is totally wrong. You can selectively discard every example that doesn't meet your arbitrary standard of popularity, but I could just as easily discard a criticism of Vite which is far more "non-existent" relative to webpack than web2py is to Django
> Numpy is a basic linear algebra library and Pandas is a high-level tabular data analysis library.
Once again you're splitting hairs. Yes, Pandas and Numpy have different specialties, but there is clear overlap between them and a developer who is unfamiliar with the ecosystem wouldn't necessarily understand why e.g. they might choose pandas dataframes vs numpy arrays, and this dynamic is also true in the JS world where different packages have overlap but particular specialties that make one more attractive than the other depending on the needs.
The webdev ecosystem is so broken, it's no wonder so many websites deliver assets that are extremely suboptimally optimised, big unused blobs of assets /scripts slowing page load, optimising it all is actually made harder than coding it all.
Allow me to correct this statement: The Javascript ecosystem is so broken.
Working with Clojurescript and Elm is an experience that will make most developers fall in love with web development again.
ClojureScript and Elm aren’t compile-to-JS languages for the sake of doing something weird, there’s just literally nothing else that will run in a browser (except wasm but probably best not to get into that).
Different programming languages exist for a multitude of valid reasons, the compiled output isn’t particularly important as long as it can express everything you need it to.
It would be if machine code were another high-level text-based language completely unrelated to either Lisp or Haskell with its own semantics, execution model and type system rather than a more directly machine-readable format of those languages themselves.
Javascript is fundamentally different enough from a bytecode for any arbitrary language that, at least to me the distinction matters. I can accept that it works well enough that most people don't care, even though I suspect most of the use cases for doing so (error checking, type checking) could be better served with linters or editor tools for JS itself.
But the decision to avoid actually writing javascript at all costs has contributed a great deal of complexity in the JS ecosystem, which translates into the bloat in the web that everyone complains about, because all of that javascript is wasting time and cycles simulating other languages.
Who's JavaScript is it anyway? ES7? ES6? Internet Explorer 11's? How do you isolate things for the sake of unit tests and then bring them together into a performant build?
Cross-browser compatible Javascript was a solved problem when JQuery and shimming came along.
>How do you isolate things for the sake of unit tests and then bring them together into a performant build?
Use one of the many unit testing libraries and frameworks that already exist for Javascript.
[0] https://trunkrs.dev/
I added the dependency by writing about three CMake lines.
And after that, it just works, for years.
I may have to add from 2, to 5 dependencies for a project, instead of the myriad of dependencies in JS. And they don't become obsolete and need an update each week.
It's a difference of some orders of magnitude, both in number and in upgrade frequency. This is a huge part of dependency management for me.
And there are C++ package managers like Conan, which solve your requirement of adding a dependency by just using the command line.
I will probably use Conan if I have to write C++ again.
Conan makes much of this easier, but is not really suited for large software projects with the problems mentioned above - in my experience.
About dependencies, if they can be found in the package manager then it goes that way. Else, they are a git submodule.
The most problematic has indeed been the C++ MySQL connector, because it has changed a bit over the last five years, so I had to edit the #include lines in the source code files.
When you are using git submodules as package manager, what do you do if the dependency doesn’t come with CMake files, but with autotools for example?
I think bazel is becoming a great solution for these problems if you align with their philosophy.
It... really doesn't? You generally have an entry point file - which can be any file, you just have to specify it to your build system - and import statements are followed from there on. If anything you could argue the JS build ecosystem is too flexible (which is one of the things esbuild is pushing back against). I've never heard someone criticize it for being too opinionated.
> For extra fun, some libraries don't build with build system a, others require build system b
I've literally never encountered this problem. Library authors virtually always ship least-common-denominator JS that will work without using a build system at all, and then build systems know how to handle lots of different variations of JS and converge them into a single representation. Compatibility is not an issue that exists in my experience.
> The webdev ecosystem is so broken, it's no wonder so many websites deliver assets that are extremely suboptimally optimised, big unused blobs of assets /scripts slowing page load, optimising it all is actually made harder than coding it all.
Now you're just airing your own personal beef which doesn't actually have anything to do with the original topic.
I don‘t mean to discuss which system is too complicated and which is not just to point out a lot of real world build systems are on that level.
Gradle wrapper is just a name for a script (automatically created by Gradle btw) which allows one not to have any kind of Gradle-related tooling installed on the machine (basically, to run build tasks you execute `./gradlew someTask`, and it takes care about downloading and running the appropriate Gradle version) - which I think is a clear benefit over the fact that you need to have `npm` installed system-wide or via a tool like NVM in order to build JS projects.
Gradle has its own warts, and a lot of them, but at least there is only one major build system in this area, and it is simply impossible for a library published to a Maven repo to be dependent on the build system it is built with.
Webdev can be broken, but doesn't have to be. I am currently having fun & feeling productive on both a large team project and some small personal projects.
I wouldn’t give up all my structural type inference for the 1:1 you’re describing, but it is tempting.
Honestly it's so good I wonder if it will undercut Deno a little bit by lowering the barrier for bootstrapping a TypeScript project
Need to handle non-js assets in your bundle? Need to integrate into both node and browser environments?
You should stick with webpack. Any time you lose waiting for webpack to run you will get back 10x over by not fighting with your tooling because it doesn't handle a set of use cases you have.
I'm sure the next generation of build tools and bundlers will mature over time and we'll all get to enjoy the benefits of es modules, but right now webpack's mature plugin ecosystem, documentation, and stability makes it my default choice.
Generally I think this is good advice for tools--stick with the mature thing. But my former company's webpack builds were 30+ minutes for a relatively simple site. No doubt something was misconfigured, but you really have to be a webpack expert to get any sort of insight into where the time is going, and even then it may not be especially actionable (or at least not obviously so). In our case, we were using a monorepo and we didn't have something like Bazel, so this was painful for backend engineers, data scientists, etc--not just frontend engineers.
Maybe our case was pathological, but we would have saved a ton of time moving to esbuild and building whatever additional features we needed from scratch.
It’s usually slow css loaders, or too-inclusive patterns for loaders ending up processing node_modules, and not good enough disk caching.
There is a plugin called smc to monitor loader execution time.
Dll plugin was the best speed up to avoid recompiling things that don’t change, but now module federation is suppose to be a better solution. Disk caching in v5 will also do great things.
Thing is, it’s so complicated to setup, and debugging it involves so much config tweaking ans waiting.
I think we are a few years out from when we have nice speedy builds in webpack with good abstractions.
But then it’s a question of whether people move away from webpack because we don’t need all the plugins and transpiration and want native compile speeds.
One thing for certain though is the hype cycle will continue on...
Especially as seeing that there is no good solution (but a lot of attempts at them), I feel it somewhat points to this overcomplexity being a problem central to Webpack.
I’m genuinely curious what simple site would cause a 30+ minute build? Is it just one of those things that grow over time?
Snowpack's latest releases have been... troublesome, but we've stuck with 3.0 and it's been good enough. It completely doesn't support some libraries, but other than that it's been tolerable. Knowing what I know now I probably wouldn't have invested in Snowpack quite yet.
Really hoping Snowpack stabilizes a bit more, or we'll probably just fall back to webpack (or maybe Vite?) again.
Of course the correct way would be to force the dependencies to support es.
But vite has now become default for me as well for new projects.
The only issues I had in the beginning was esbuild's compilation of typescript enums: the import order was off from time to time. Besides that, no issues. I am also super glad I do not need to configure webpack any longer.
* Making sure `mode` is set to "development" (don't specify it all if in doubt)
* Ditching babel-loader and using esbuild-loader instead
* Adjusting build targets and making sure polyfills are not added in development
* Making sure you don't import the entirety of libraries like Lodash and MomentJS (prefer date-fns)
* [FUTURE] We'll soon be able to tell Webpack to output ES modules just like Vite [1]
Vite still has many problems:
* It just isn't suitable for proper server-side rendering, we'd need access to chunk names at build time
* It has a weird mix of own and Rollup config settings that seems somewhat unpredictable
* Many open issues regarding module imports, for ex, when a CJS module imports an ES one [2]
Our current bottleneck with Webpack is actually sass-loader, taking at least 70% of the time during a fresh build, and we'd have the same problem with Vite.
Something else that is worth pointing out is the ecosystem: Webpack's community has built tons of plugins for basically any use case you can imagine, and version 5 supports module federation, persistent caching, externals (very handy when doing SSR), customizable filename generators, performance hints, etc etc. Totally different game.
Try to keep your build config simple, avoid too many loaders, plugins, and you should be fine 99% of the time. If you hit a wall, install speed-measure-webpack-plugin to get some help.
[1] https://github.com/webpack/webpack/issues/2933
[2] https://github.com/vitejs/vite/issues?q=is%3Aissue+is%3Aopen...
Webpack 5 has introduced asset modules, so now you can safely ditch raw-loader, url-loader and file-loader. [1]
You might have NextJS or CRA in mind.
[1] https://webpack.js.org/guides/asset-modules/
Oh god, this is a giant red flag. This is precisely one of my biggest gripes with Quasar (a Vue framework), which, on top of webpack/vue adds its own config that are intermingled with vue's and webpack's, and its honestly a mess, and oftentimes just straight up makes problems harder to solve.
I am obviously not railing against config dedicated to a single tool in a toolchain, but the way you described it rings a bell, especially the "unpredictability".
>* Many open issues regarding module imports, for ex, when a CJS module imports an ES one
This also seems to confirm my and other's suspicion, that the tool isn't really "deliver-grade".
>If you hit a wall, install speed-measure-webpack-plugin to get some help.
But on the other hand, this is at least the fifth plugin I have heard someone recommend, dedicated just to profiling Webpack.
What do you think about the time difference shown in the article? I sort of feel it's a bit disingenuous since the test included a lot of other variables, but it seems hard to argue against it if it's this plain. Is this a config issue, or a "most commonly used loader" issue...?
I believe that, at this point, people are just nitpicking. When working on a client-side-only app, Vite is faster, but not by that much. In one of our apps, I saw it starting up in 1s compared to 2s with Webpack, and reloads in 100ms compared to 250ms. This is a Preact/TS/Emotion app that outputs almost 7MB of assets, 61 files to be precise, and works on IE11. And I hadn't even tried persistent caching with it yet. Webpack 5 with esbuild is a fast-enough solution.
NextJS is a well-established tool now and version 10.2 uses Webpack 5 under the hood. V11 is looking insanely fast (I suspect they replaced Babel with esbuild, and did some witchery): https://twitter.com/shuding_/status/1378086219708473344.
So yeah, slow performance with Webpack is definitely caused by a bad set of loaders/plugins. Eject a CRA app and you'll see a monster coming out.
You can at later rollup hooks (it doesn't make sense to access chunks that don't exist yet).
Actually, there are SSR frameworks being built on top of Vite such as SvelteKit [1] or vite-plugin-ssr [2] (vite-plugin-ssr is not a framework but gives you a similar DX than Nuxt/Next.js; I'm its author), and many people are implementing custom SSR solutions.
Join our Discord #ssr channel and ask us questions https://discord.gg/PkbxgzPhJv ;-).
[1]: https://github.com/sveltejs/kit
[2]: https://github.com/brillout/vite-plugin-ssr
vite-plugin-ssr can't even be integrated with Vue Router (I saw you're working on deep integration though). They're both very rigid, early stage endeavours. [2] What happens, for ex, if you used nested lazy components in those pages, are they going to be included in the server render as well?
I mean, fair enough that there are people trying to do better, but it's extremely hard to find the right abstractions for such complex builds and Webpack is definitely on top here.
[1] https://github.com/sveltejs/kit/blob/5c2665ff2280947a2fc6001...
[2] https://github.com/brillout/vite-plugin-ssr/blob/master/src/...
I mean, if you think vite-plugin-ssr to be rigid, then Next.js should feel like a 2sqm prison cell to you ;-).
If you want more flexibility than vite-plugin-ssr then use Vite's native SSR API.
Whereas with webpack: good luck with 1. using two webpack configs (one for Node.js and one for the browser), 2. synchronising between these 2 webpack configs, 3. implementing server-side HMR; it's incredibly painful and can cost you many weeks of dev time... whereas Vite's SSR API does all of this for you for free.
Sure, things are early stage, but saying that webpack is "definitely" on top for SSR is wrong in virtually any possible way.
Btw I interviewed at Notion but didn’t make the soft skill bar. Big fan of the product.
My first two thoughts were:
* Imagine all the smart people in webdev world would improve the existing tool rather than create a new one. [0]
* "if you do less, it will go faster". I.e. Vite is young and new, supports a subset of Webpack and of course boasts how fast it is. Yet my repos can't use it because it doesn't has the support it needs for my repo sizes with legacy stuff. Of course it is "on the roadmap" and by the time it will be supported Vite is as slow (if lucky) as Webpack. Doesn't matter though as a new tool will be there long before Vite reaches Webpack..
Yup. Getting old and also cynical in the evenings. Dammit!
[0] https://xkcd.com/927/
I believe vite does support cj's dependencies, you would need to file an issue on vite repo on why you are getting the error
I’ve found that by doing so, I can just basically ignore, for years on end, all of the peddlers pushing how their projects make development easier or faster or some nonsense.
You know what’s easiest and fastest? Flat files in a good directory structure with some getting started template.
That’s it. The fastest build times are the ones that don’t exist. Period.
Web development is as complicated as you choose to make it. Very few fields work like this.
Quite the opposite; I would argue that webdev is basically rediscovering the whole shebang, but decades later.
Modern webdev with transpilation, linking, pruning, compilation to WASM etc. starts to dreadfully look like the classical native development paradigm.
When I try to use Webpack, as I click through obsolete StackOverflow posts, trying to figure out the right key-value pairs to get the output I want, I realize how mistaken I was. I hope build tools for the web become less "magical" and more predictable and debuggable, even if it means discarding their declarative form.