51 comments

[ 3.1 ms ] story [ 117 ms ] thread
What does Preact sacrifice to get down to 3kb? Browser support? Nothing comes for free I guess, so just curious about the too good to be true nature of it.

Why isn’t the React team putting in these enhancements?

They sacrifice all the crazy performance optimisations that React has.
TBH preact is faster than React. I don't know of a scenario where react was faster.
How do you measure? I’d love to see large renders and complex top level state updates that hit hundreds of components.
I worked on a project where we were using React 14 before 2 years. It was only a desktop B2B site and later on when mobile support was inevitable we tried to use preact for mobile site since it was lightweight. We actually found that our desktop site which renders large tables with hundreds of rows and multiple chart components performed better in Preact without any optimizations. I'd say maybe a 20 - 30% improvement since we were seeing a gain FPS of around 10 frames. I think it would have been a bit more faster if we had used MobX instead of redux but that was too late.
Haven’t worked with React for a little while and only ever used MobX on one project, I was mostly using Redux. What performance improvements does MobX offer?
Redux always returns a brand new state. This will cause all consumers to rerender and react will update the dom only if there is a change. But with Mobx its more granular and the updates are atomic. This isn't a problem in apps where there is a single team working on it. But when you work in enterprise apps where different parts are worked on by different teams state updates to redux can be costly. This is not a limitation of Redux but a human problem that occurs inevitably. I've seen this in 3 different large scale projects. It starts well but after a year or so when people move out/in this bites us.

This can be enforced with strict rules, eslint plugins and infra but they are expensive as hell.

EDIT: 'This will cause all consumers (with incorrect mapStateToProps configuration) to rerender'

Understood, this is the reason I suspected and have spent considerable time in the past optimising state updates to forms in React and Redux projects so can imagine how this would become an issue in much larger teams than the ones I was working in.
When using Redux, components are supposed to select small parts of the state tree, and then they only rerender when those change. It is absolutely not the case that all components render on each unrelated update of the global state, that would be crazy.

https://react-redux.js.org/next/api/hooks#useselector

It is true that all of the selector functions need to run on each change, but those are supposed to be really small pure functions and their performance should be negligible, compared with everything else that normally happens in an app.

Edit: It is absolutely possible to affect performance with Redux, especially on a large app — for example if hundreds of selectors need to run for every keystroke in a textbox.

Yeah this is correct, I think what the OP was getting at was the fact that Redux requires a little more discipline as it's less opinionated than MobX.
Yes you are correct that we can use useSelector to optimize selectors for Redux and I even implemented this hook in an interview on the whiteboard :D.

And yeah components are supposed to select only what they need in mapStateToProps and mapDispatchToProps. But I have seen a couple of instances where this is not followed and the developer chooses to use the entire state object passed to the component. This was fixed quickly and all developers got a short doc on the do's and dont's of Redux. This is what I mean by the extra work around redux library and not the concept itself.

Also its a fairly common to see developers pushing multiple micro updates like keystrokes to redux making it slow down. This gets filtered in the reviews but it misses out sometimes. I'm guessing this to happen in many other projects too unless I'm missing out on some major update on the tooling around redux.

These problems are not because of the approach but in the implementations. I hope you get what I mean by cost in my opinion above.

Agreed then, Redux does give you enough rope to get into trouble, especially when used indiscriminately.
You still have to run the selectors for all components on each change and check if their result has changed and if so, update the component props. So the more components, the more memory/cpu you waste on each redux update. So now you have to use something like reselect to start caching results...
Also it'so easy to start making new components dependent on the store, and ending with reusability.
There are a few stuff that are missing from core preact that can be added via preact/compat package namely: memo, forwardRef, PureComponent, Event listener modifications similar to react, etc.,
They don't do the event normalization/redirection. This is something you probably won't notice or need in your project anyways. I myself encountered the difference just once, when using Portals: In React, all events inside the portal would bubble/propagate to the parent components of the React component tree just as if the portal was mounted as a child of the surrounding component. In preact, all events in the portal propagate to the actual, real browser DOM hierarchy. I.e. if you have a click event inside the portal, the wrapping Preact parent component would never see the event or be able to handle this. This incompatibility would only be an issue when migrating to Preact from React; if you start with Preact from the beginning you would refrain from using this event bubbling to notify the enclosing component and use some other mechanism (i.e. forward the event data through a custom event handler or PubSub instance).
Synthetic event system + render decoupling. Preact uses the event system of the platform (browser) and only renders to it (there's no react native support).

Anyway we are using it at prod and allowed us to reduce our bundle sizes ;)

Worth noting that while Preact specifically doesn’t support React Native, JSX does. So to the extent the dev APIs stay in line you can always swap out the underlying library for that target (or other renderers).
The team behind Preact also recently released WMR [0] which attempts to simplify the process of actually building a web app. We're thinking of trying it out to replace the current mess we have with create-react-app, webpack, etc.

0: http://github.com/preactjs/wmr

I found frontend tranquility in Snowpack and snowpack-rollup for production builds.
Any gotchas? When I read about Snowpack, I always get a too-good-to-be-true feeling. Maybe I'm just jaded by years of grunt, webpack, parcel, etc.
For starting from scratch it mist likely does wonders.

Don't try converting a large legacy-ish codebase :)

We love parceljs, too. Check it out.
I like parceljs too. I haven't used it on big projects (plus I'm not a web dev currently) but I found it to be more "config when you need to change the defaults" than "no config". But that's great. It works out of the box for a lot of stuff and you add some dotfiles when you want to customise.

I do want to try snowpack too though.

Snowpack got really really slow after I added a few dependencies. Also, it can't reuse its cache between a docker container and my laptop... I was hoping the cache would be portable but it's not. It needed more restarts than webpack. And you give away your freedom to tinker.
May I ask what is the problem with parcel? I can't remember I have ever run into problems with parcel. Maybe it's because, unlike when using webpack, I never try to perform "dark arts" when using parcel.
I had previously run into the issue of Parcel watching `node_modules` for file changes and inevitably having issues related to that. There are a few issues on GH related to that, to which the devs basically said "that's a feature, not a bug". It's been a while since I used Parcel though, Idk if that's still and issue.
Webpack has some serious positive side effects:

1-2 times a year when I go to update our app's Webpack, in a matter of 3-4 days I:

1. Get up to date on all recent developments in the world of javascript, babel, esbuild, typescript, eslint, webpack, jest and all their plugins

2. Get the chance to browse through hundreds of fresh github issues while they are still open!

3. Open a few new pull requests

4. Find out about tens of of plugins that are not being developed anymore and their new replacements which are almost the same only with a new name and slightly different API!

5. Give my laptop and build server's CPU's a good go

6. Call my therapist

It's a wonderful opportunity to keep life on edge.

This is too real. I don’t use webpack directly, only the way vue-cli bundles it, but still it’s a sort of blessing and curse. It is also dog slow for what it’s doing: even something like make can cache compilation objects and make sure that for example Bootstrap’s SCSS doesn’t need to be recompiled every time I update the background color of my app in my own stylesheet. And while speed measuring plugins exist, I am still at a loss at how to optimize a build of a simple SPA where my code all in is less than 10KB and yet it takes like 30 seconds to produce a build. And as you say, when a bug hits, good luck figuring that out.
Try esbuild instead of babel. Really helps. There is an esbuild-loader that can replace babel neatly.
On the bright side it’s still possible to make a living shipping professional code with simple script dev tags, for now.
:( I just get notifications when my dependences have vulns on github and I update them with pip install -U <package_name>
I've been using webpack since v1 and I can't recall having to open pull requests when periodically upgrading it, or its plugins. Webpack 5 + html-webpack-plugin are kind of a mess right now, though. Webpack, in many use cases, needs html-webpack-plugin but there is only an alpha release supporting v5.

The release was rushed by community pressure, and now we have a half-baked upgrade strategy. I would've happily waited another 6-12 months before v5 was released to get major plugins ready first.

I recently tried deno. Can we all switch yet? Please no more webpack, babel, etc etc.
It's a joke isn't it?! We spend hours maintaining that stuff and it gives the customer 0 value. :explodinghead: But on the flip-side, we get paid! :D
Customer? How about the users? The tools keep getting "better and better" and yet time and again I'm on sites - big major sites - that trigger a "No way! WTF is _that_?!??"

Mind you that's not necessarily a direct result of the tools or those using the tools. On the other hand, resources are finite. Any time used for X (e.g., wresting with Webpack) "comes out of the budget" for Y (e.g., bug fixes) or Z (e.g., a UX designer).

Clients/customers care about their users/end-customers. And users/end-customers don't give a toss about Webpack or anything else. They care about themselves. Full stop.

The tools get better, enabling even more complex applications which occasionally have bugs and unintended features.

This is just in the nature of progress. If any product owner was fine with a simple static website which only displays some text, I'm sure there wouldn't be any noticeable bugs in it.

I think it’s a general truth that all software projects tend to end up at the maximum possible complexity. Projects that aren’t inherently complex tend to achieve this by complicated tooling, deploys, and a slew of “special cases” that inevitably slow things down. It’s a special case of Parkinson’s law (work expands so as to fill the time available for its completion); all these developers need to spend their time on something after all, no-one’s going to code them self out of a job.
Is a goal of `wmr` to ever support translating `exports.foo = bar` / `module.exports.foo = bar` + `require()` to `import/export` so that modules that work with `node.js` can work in the browser too?
It already does this. Only for .cjs files and things in node_modules.
I love Preact, you'd have to look really hard to find actual, real-world differences that would make you use React over Preact. I find it funny that Preact also has a drop-in hook replacement `useErrorBoundary`, while React to this date still forces you to use class-based components if you want to establish error boundaries (using `componentDidCatch`).
I've been using preact with parcel for over half a year now and it has been a blast!

It seems to be 100% compatible with React. It's fast, it's small. And with preact/compat you can use any third party react component.

I'm a particular fan of https://github.com/developit/htm, which is an alternative to JSX that simply uses JS template strings and needs no preprocessor.

It is not 100% compatible, but it is very likely you will never hit those cases where it is not (see the other postings on this thread about it).
Gatsby has gatsby-plugin-preact which replaces React with Preact, and so far I've seen no difference in functionnality or speed, but the website's first load is slightly lighter.
Funny that this is on the front page today, I switched my project from preact to react in the afternoon. The main culprit : meteor supports react, not preact. I found a workaround at first but when getting a bit more serious it made sense to switch over to the mainstream and avoid unnecessary pains. Migrating from preact to react was easy, except for the render method arguments that I had to manually move over. Overall I like preact for small projects with little dependencies, and react for larger enterprise project where your just want as little pain as possible. Most react libs have to be forked to work with preact.
I reached for Preact on a project and was very satisfied with it. Until, that is, I hit a bug where DOM elements would be rendered out of order when I would call setState. I replaced Preact with React and everything worked fine. The logic was fairly straightforward as well - I was not doing anything fancy.

Preact is great but be prepared for anomalies like mine.

Most probably this would be something to do with the key prop. Or how conditional components are being rendered. I can't make any judgements without seeing the final code though.
We are working on a new renderer that started out life as a way of addressing the specific corner cases that can lead to this. It will be released in early 2021.