You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ensure the lowest size, we know what properties are safe to mangle
consistent performance, no minifier/transpiler would insert a snippet that performs poorly
I do see what you are saying about traces becoming unreadable while investigating bugs/performance. It's been one of my main motivators to fight for "readable" dist bundles as well.
However doing so would most likely warrant a major as we do ship properties that we need mangled for our plugin ecosystem, the reconciler is pluggable so devtools/signals/fast-refresh rely on that being consistent.
If you are facing a bug and don't know how to reproduce due to the bundle being unreadable I am open to figure this out together on a GitHub discussion/...
For my personal use case I am likely to copy paste the source code of preact into my application and use it directly so that I can have the unminified version.
I ran into the same issue with react, and was fighting with nextjs in that it does not allow me to set NODE_ENV
It would help me if you committed a version of preact.single-file.js into the git repo so I could copy a single file instead of the entire source code.
The way i used to copy jquery.js into my vendor/jquery.js codebase and also copy vendor/jquery.min.js and control what I load when and where for development / staging / production.
I guess having dist/preact.raw.js next to dist/preact.min.js would also help me, in that I can quickly and easily copy the raw single file source code or import it with require('preact/dist/preact.raw.js')
This would be a non breaking change, just an extra file into the npm publish tarball.
For my personal use case I am likely to copy paste the source code of preact into my application and use it directly so that I can have the unminified version.
As Jovi mentioned, this could be an issue as the plugin system relies upon mangled properties for hooking into the reconciler. If you're only using Preact core, you shouldn't run into any issues, but you are locking yourself off from devtools/prefresh/etc.
Unfortunately I'm not sure a mangled, but unminified, distribution file would end up being much more readable... _children still needs to become __k, etc.
I appreciate the technical explanation of why this wouldn't work with the ecosystem and the devtools.
I am however completely blown away that this technical limitation exists. it boggles my mind.
A mangled & unminified build would not really be helpful. I guess all the plugin ecosystem tools would have to support both mangled & unmangled copy of preact with some kind of config setting.
Well, I'm not quite sure what other alternatives exist. The problem is that properties need to remain consistent across versions and across every distribution method.
Mangling ahead of time certainly isn't ideal, but I don't know of any better options that doesn't offload the problem onto end users.
I'm also frustrated by this right now as I have some code that is getting called too frequently and what is happening inside preact is quite opaque. The included TypeScript definition files help a lot with reading the code, but unfortunately Firefox (at least) doesn't unmangle variables in the debugger so this is what I see:
My position on this is that minification/mangling isn't worth the costs, especially given that basically every file served over the internet is gzipped. A given word/token (e.g., _children) is essentially one lookup table entry in a gzipped file plus maybe a byte or two of data per reference, thus mangling gives very minimal benefits. Meanwhile, the cost is that it takes significantly longer to debug applications than if the code was un-mangled.
I would encourage comparing just gzipping vs gzipping+mangling to make sure you are actually benefiting in a significant way at least. My guess is that mangling isn't actually saving much. Even if it is, there should still be a way to run without mangling for people who don't want/need mangling.
I'm currently using: import * as preactSignals from '@preact/signals-core';
I tried this: import * as preactSignals from '@preact/signals-core/src/index.ts';
... but rollup complained about it not being JavaScript even though I have the typescript plugin loaded, and other typescript imports in my bundle are working fine.
rollup complained about it not being JavaScript even though I have the typescript plugin loaded, and other typescript imports in my bundle are working fine.
You'd need to configure your TS plugin to compile node_modules, that's not standard behavior.
Currently jsx-dev-runtime points to the same thing as jsx-runtime, so unless that's for historical reasons, might make sense to tweak for dev. Otherwise an ./jsx-runtime/src export could be added.
Then you adjust the alias settings in esbuild for development:
I'd be open to submitting a PR if this is something the Preact team would consider!
I would +1 this as somewhere in between 10.20.1 and 10.22.1 an exported function started being compiled as $2 that's conflicts with jQuery/Ruby on Rails javascript.
I'm currently exploring something like this in esbuild to force it to resolve to the src instead of the dist directories.
Seeing how unminified code is published on npm as well, I ended up with the following patch, and another one in prefresh to unmangle the fields. It added 253 bytes to the brotli'd javascript size.
Just ran into a pesky hydration bug. Preact kept remounting dom elements, rerunning the @starting-style transitions, and causing a flash. The html elements preact was hydrating were identical to what it rendered; logically I had done everything right. I had no idea what it wanted from me!
It turned out there was some whitespace around the elements and preact was diffing against blank TextNodes. There's no way I would have found that out if I wasn't stepping through the unminified preact code in the debugger.
Hmm, then we probably diff the divs correctly but maybe the unmount of the empty text node causes the state of the HTMLElement to be reset as it moves from position 1 to 0. Maybe it's worth to not unmount empty text nodes for this reason, they should not lead to erroneous child diffing.
The message did not make sense to me originally, but I dismissed it thinking engineers are not communicators. Only when I was looking preact/debug's source code did I realise it was supposed to log the diffed element tag names.
Again, because I have the unminified code running, I was able to add this line to node_modules to immediately determine why it wasn't logging the available elements. That's twice in one day!
but I dismissed it thinking engineers are not communicators.
Snide comments like this aren't helpful, please try to keep things a bit more positive for people volunteering time.
Again, because I have the unminified code running, I was able to add this line to node_modules to immediately determine why it wasn't logging the available elements. That's twice in one day!
Alternatively, we do offer source maps... you can simply open your debugger and add a breakpoint. I get the value of console.log debugging, it's absolutely my go-to, but our source maps, along with any proper JS debugger, handles this situation (and more) very, very well.
This would still be highly desirable for me - I promisingly saw that this thread was referenced from the v11 tracking branch but couldn't track down exactly from which comment. It would be marvellous if v11 could include a build without name mangling.
@amb26 As mentioned, some name mangling would be required, but the problem with separate builds (which I ran into yesterday whilst testing out an idea) is that it's really, really easy to load the unminified build and standard build which breaks certain things as Preact must be a singleton. You have to be very careful with your build tooling and your aliases to get something usable.
A separate build output seems more likely to harm than help, I'm not sure that's a viable option for us. Source maps will probably continue to be the recommended path.
Just my two cents: npm is a package registry, targetting the end-users. Code needs to be minified, and source maps should not be included. If one needs the non minified code or the source map, it means that they want to debug preact itself. Not their code; they want to debug something else.
We never need to debug anything else than our own code. If something else needs to be debugged, it must be done from the source code of the said thing, not from the published artefact. npm is already a massive waste of bandwidth with source maps, not required dependencies, CDN files, all those things that are never even used by the applications that import the packages. Let's not add non-minified files just because some people want to debug something that they are not working on.
If you need to debug preact, clone the preact repository and debug from there. If you have a runtime error on your application, this is because there is a bug in your application. There is no need to debug preact.
We never need to debug anything else than our own code. If something else needs to be debugged, it must be done from the source code of the said thing, not from the published artefact.
Sorry, but this is far from true, quite often (5+ times a week) I need to debug external code, usually starting from the context of my existing app. Expecting users to jump from "found bug in app" straight to "extracted minimal repro in the source lib's tests" is just not very realistic.
Source maps are meant to be shipped alongside built assets, that's pretty much the whole point. All in, Preact is 1.5mb w/ no deps. We don't need to worry ourselves with NPM's bandwidth.
If you have a runtime error on your application, this is because there is a bug in your application.
Us maintainers aren't perfect, we absolutely do make mistakes. Runtime errors aren't necessarily bugs in the application.
Sorry, but this is far from true, quite often (5+ times a week) I need to debug external code, usually starting from the context of my existing app
You understand that if the rest of the world was doing the same thing, our industry would have ceased to exist decades ago? Imagine the Linux ecosystem if, whenever you install a package from a repository, you would get the compiled artefact plus the source maps and the embedded source code? This would represent gazillions of peta-octets of bandwidth and disk usage wasted every single year. The source code of the Linux kernel itself is 50 millions of line or so. Add the weight of the source map mappings and, well, you get the deal. And then add the size of every single package source code and source maps.
Imagine the same with, I don't know, Unreal libraries and assets, Windows DLLs, MacOS binaries, PS5, Switch, Xbox, Android, iOS...basically every single programmable system ever, and you get an idea about why nobody would ever want to do that: HDD space would have been depleted decades ago, and internet bandwidth would be non existent, wasted by gazillions of useless data.
Have you met a single developer outside of the JavaScript ecosystem that once said to its community "please provide the source code and the source-maps alongside the compiled package because I need them to understand why my application, that I'm currently developing, doesn't work as expected" and was granted satisfaction?
Us maintainers aren't perfect, we absolutely do make mistakes. Runtime errors aren't necessarily bugs in the application.
What you are describing are bugs. If I use your product and it does not work as described in the documentation and the specification, then this is a bug. I then open an issue. And maybe propose a fix.
What this issue is about is not what you describe. In this issue, some people request to be able to debug your code during the development of their product. Which means one thing: they are not sure if they are doing something wrong, and thus need to dig into your code to understand why something is not working as expected.
My opinion: they are doing so because they don't want to actually read the documentation and specification. Would they do so, they would be able to tell if they are doing something wrong, or if they found a bug in preact, without a doubt.
Have you met a single developer outside of the JavaScript ecosystem that once said to its community "please provide the source code and the source-maps alongside the compiled package because I need them to understand why my application, that I'm currently developing, doesn't work as expected" and was granted satisfaction?
Er, yes, this is what debug symbols are for. Some bigger platforms have dedicated symbol servers to supply this information.
My opinion: they are doing so because they don't want to actually read the documentation and specification. Would they do so, they would be able to tell if they are doing something wrong, or if they found a bug in preact, without a doubt.
We don't have a comprehensive specification of what Preact does in certain situations, and certain errors absolutely have little documentation. That's our bad, we'd love to do better, but this is something we do in our free time, by and large. Users can and will come across some undocumented dragons and source maps help in those situations.
Anyways, I think this issue has little to offer at this point in time. The maintainers are very aware of difficulties here and will try to take action where/when we think is appropriate, though today that has difficulties and tradeoffs which blocks any action for the foreseeable future.
For future readers, mind summarizing why this has difficulties?
As stated above, our ecosystem (first party especially) relies upon variable mangling to function correctly. Unless you're copy/pasting our mangle.json into your build system (which we don't publish, so you'd have to copy from GitHub), you're not building the library correctly and there will be runtime errors.
preact-iso's <Router>, for example, makes use of this.__v.__k here. This corresponds with this._vnode._children pre-mangle, an example of which can be seen here.
Activity
JoviDeCroock commentedon Jul 9, 2023
The main goal of us doing so has been to
I do see what you are saying about traces becoming unreadable while investigating bugs/performance. It's been one of my main motivators to fight for "readable" dist bundles as well.
However doing so would most likely warrant a major as we do ship properties that we need mangled for our plugin ecosystem, the reconciler is pluggable so devtools/signals/fast-refresh rely on that being consistent.
If you are facing a bug and don't know how to reproduce due to the bundle being unreadable I am open to figure this out together on a GitHub discussion/...
Raynos commentedon Jul 9, 2023
For my personal use case I am likely to copy paste the source code of
preactinto my application and use it directly so that I can have the unminified version.I ran into the same issue with
react, and was fighting withnextjsin that it does not allow me to setNODE_ENVIt would help me if you committed a version of
preact.single-file.jsinto the git repo so I could copy a single file instead of the entire source code.The way i used to copy jquery.js into my
vendor/jquery.jscodebase and also copyvendor/jquery.min.jsand control what I load when and where for development / staging / production.Raynos commentedon Jul 9, 2023
I guess having
dist/preact.raw.jsnext todist/preact.min.jswould also help me, in that I can quickly and easily copy the raw single file source code or import it withrequire('preact/dist/preact.raw.js')This would be a non breaking change, just an extra file into the npm publish tarball.
rschristian commentedon Jul 9, 2023
As Jovi mentioned, this could be an issue as the plugin system relies upon mangled properties for hooking into the reconciler. If you're only using Preact core, you shouldn't run into any issues, but you are locking yourself off from devtools/prefresh/etc.
Unfortunately I'm not sure a mangled, but unminified, distribution file would end up being much more readable...
_childrenstill needs to become__k, etc.Raynos commentedon Jul 10, 2023
I appreciate the technical explanation of why this wouldn't work with the ecosystem and the devtools.
I am however completely blown away that this technical limitation exists. it boggles my mind.
A mangled & unminified build would not really be helpful. I guess all the plugin ecosystem tools would have to support both mangled & unmangled copy of preact with some kind of config setting.
rschristian commentedon Jul 11, 2023
Well, I'm not quite sure what other alternatives exist. The problem is that properties need to remain consistent across versions and across every distribution method.
Mangling ahead of time certainly isn't ideal, but I don't know of any better options that doesn't offload the problem onto end users.
Raynos commentedon Jul 11, 2023
The consistent mangling for ecosystem I can understand.
Would be nice if the ecosystem respects both the unmangled and mangled property names, so I could use either the min or raw version.
MicahZoltu commentedon Dec 13, 2023
I'm also frustrated by this right now as I have some code that is getting called too frequently and what is happening inside preact is quite opaque. The included TypeScript definition files help a lot with reading the code, but unfortunately Firefox (at least) doesn't unmangle variables in the debugger so this is what I see:

My position on this is that minification/mangling isn't worth the costs, especially given that basically every file served over the internet is gzipped. A given word/token (e.g.,
_children) is essentially one lookup table entry in a gzipped file plus maybe a byte or two of data per reference, thus mangling gives very minimal benefits. Meanwhile, the cost is that it takes significantly longer to debug applications than if the code was un-mangled.I would encourage comparing just gzipping vs gzipping+mangling to make sure you are actually benefiting in a significant way at least. My guess is that mangling isn't actually saving much. Even if it is, there should still be a way to run without mangling for people who don't want/need mangling.
dliebner commentedon Dec 29, 2023
Is there a way to import the source version?
I'm currently using:
import * as preactSignals from '@preact/signals-core';I tried this:
import * as preactSignals from '@preact/signals-core/src/index.ts';... but rollup complained about it not being JavaScript even though I have the typescript plugin loaded, and other typescript imports in my bundle are working fine.
rschristian commentedon Dec 30, 2023
As mentioned, no.
You'd need to configure your TS plugin to compile
node_modules, that's not standard behavior.matthewmueller commentedon Feb 4, 2024
I was able to get a PoC working with esbuild by:
Tweaking
preact/package.json:preact/srcas a valid exportpreact/jsx-dev-runtimeto point to src:Currently
jsx-dev-runtimepoints to the same thing asjsx-runtime, so unless that's for historical reasons, might make sense to tweak for dev. Otherwise an./jsx-runtime/srcexport could be added.Then you adjust the alias settings in esbuild for development:
I'd be open to submitting a PR if this is something the Preact team would consider!
johrstrom commentedon Jul 9, 2024
I would +1 this as somewhere in between
10.20.1and10.22.1an exported function started being compiled as$2that's conflicts with jQuery/Ruby on Rails javascript.I'm currently exploring something like this in
esbuildto force it to resolve to the src instead of the dist directories.lilnasy commentedon Nov 26, 2024
Seeing how unminified code is published on npm as well, I ended up with the following patch, and another one in prefresh to unmangle the fields. It added 253 bytes to the brotli'd javascript size.
preact.patch
@prefresh/core.patch
lilnasy commentedon Dec 14, 2024
Just ran into a pesky hydration bug. Preact kept remounting dom elements, rerunning the @starting-style transitions, and causing a flash. The html elements preact was hydrating were identical to what it rendered; logically I had done everything right. I had no idea what it wanted from me!
It turned out there was some whitespace around the elements and preact was diffing against blank
TextNodes. There's no way I would have found that out if I wasn't stepping through the unminified preact code in the debugger.8 remaining items
JoviDeCroock commentedon Dec 14, 2024
Hmm, then we probably diff the divs correctly but maybe the unmount of the empty text node causes the state of the HTMLElement to be reset as it moves from position 1 to 0. Maybe it's worth to not unmount empty text nodes for this reason, they should not lead to erroneous child diffing.
lilnasy commentedon Dec 14, 2024
In the meantime maybe this helps:
The message did not make sense to me originally, but I dismissed it thinking engineers are not communicators. Only when I was looking preact/debug's source code did I realise it was supposed to log the diffed element tag names.
Again, because I have the unminified code running, I was able to add this line to node_modules to immediately determine why it wasn't logging the available elements. That's twice in one day!
Here's the repro for the flashing issue: https://stackblitz.com/edit/github-vmfzstte?file=src%2Fpages%2Findex.astro,h1.ts&on=stackblitz
rschristian commentedon Dec 15, 2024
Snide comments like this aren't helpful, please try to keep things a bit more positive for people volunteering time.
Alternatively, we do offer source maps... you can simply open your debugger and add a breakpoint. I get the value of
console.logdebugging, it's absolutely my go-to, but our source maps, along with any proper JS debugger, handles this situation (and more) very, very well.lilnasy commentedon Dec 15, 2024
Sorry. It's hard to communicate tone over text, but I didn't mean to be snide.
amb26 commentedon Feb 17, 2025
This would still be highly desirable for me - I promisingly saw that this thread was referenced from the v11 tracking branch but couldn't track down exactly from which comment. It would be marvellous if v11 could include a build without name mangling.
rschristian commentedon Feb 17, 2025
@amb26 As mentioned, some name mangling would be required, but the problem with separate builds (which I ran into yesterday whilst testing out an idea) is that it's really, really easy to load the unminified build and standard build which breaks certain things as Preact must be a singleton. You have to be very careful with your build tooling and your aliases to get something usable.
A separate build output seems more likely to harm than help, I'm not sure that's a viable option for us. Source maps will probably continue to be the recommended path.
ericmorand commentedon Oct 20, 2025
Just my two cents: npm is a package registry, targetting the end-users. Code needs to be minified, and source maps should not be included. If one needs the non minified code or the source map, it means that they want to debug preact itself. Not their code; they want to debug something else.
We never need to debug anything else than our own code. If something else needs to be debugged, it must be done from the source code of the said thing, not from the published artefact. npm is already a massive waste of bandwidth with source maps, not required dependencies, CDN files, all those things that are never even used by the applications that import the packages. Let's not add non-minified files just because some people want to debug something that they are not working on.
If you need to debug preact, clone the preact repository and debug from there. If you have a runtime error on your application, this is because there is a bug in your application. There is no need to debug preact.
rschristian commentedon Oct 20, 2025
Sorry, but this is far from true, quite often (5+ times a week) I need to debug external code, usually starting from the context of my existing app. Expecting users to jump from "found bug in app" straight to "extracted minimal repro in the source lib's tests" is just not very realistic.
Source maps are meant to be shipped alongside built assets, that's pretty much the whole point. All in, Preact is 1.5mb w/ no deps. We don't need to worry ourselves with NPM's bandwidth.
Us maintainers aren't perfect, we absolutely do make mistakes. Runtime errors aren't necessarily bugs in the application.
ericmorand commentedon Oct 20, 2025
You understand that if the rest of the world was doing the same thing, our industry would have ceased to exist decades ago? Imagine the Linux ecosystem if, whenever you install a package from a repository, you would get the compiled artefact plus the source maps and the embedded source code? This would represent gazillions of peta-octets of bandwidth and disk usage wasted every single year. The source code of the Linux kernel itself is 50 millions of line or so. Add the weight of the source map mappings and, well, you get the deal. And then add the size of every single package source code and source maps.
Imagine the same with, I don't know, Unreal libraries and assets, Windows DLLs, MacOS binaries, PS5, Switch, Xbox, Android, iOS...basically every single programmable system ever, and you get an idea about why nobody would ever want to do that: HDD space would have been depleted decades ago, and internet bandwidth would be non existent, wasted by gazillions of useless data.
Have you met a single developer outside of the JavaScript ecosystem that once said to its community "please provide the source code and the source-maps alongside the compiled package because I need them to understand why my application, that I'm currently developing, doesn't work as expected" and was granted satisfaction?
What you are describing are bugs. If I use your product and it does not work as described in the documentation and the specification, then this is a bug. I then open an issue. And maybe propose a fix.
What this issue is about is not what you describe. In this issue, some people request to be able to debug your code during the development of their product. Which means one thing: they are not sure if they are doing something wrong, and thus need to dig into your code to understand why something is not working as expected.
My opinion: they are doing so because they don't want to actually read the documentation and specification. Would they do so, they would be able to tell if they are doing something wrong, or if they found a bug in preact, without a doubt.
rschristian commentedon Oct 20, 2025
Er, yes, this is what debug symbols are for. Some bigger platforms have dedicated symbol servers to supply this information.
We don't have a comprehensive specification of what Preact does in certain situations, and certain errors absolutely have little documentation. That's our bad, we'd love to do better, but this is something we do in our free time, by and large. Users can and will come across some undocumented dragons and source maps help in those situations.
Anyways, I think this issue has little to offer at this point in time. The maintainers are very aware of difficulties here and will try to take action where/when we think is appropriate, though today that has difficulties and tradeoffs which blocks any action for the foreseeable future.
We appreciate the feedback from everyone!
ericmorand commentedon Oct 20, 2025
matthewmueller commentedon Oct 20, 2025
For future readers, mind summarizing why this has difficulties?
From my quick look at the problem last year (comment), it seems it could be solved with a few extra
exports, but probably missing something.rschristian commentedon Oct 20, 2025
As stated above, our ecosystem (first party especially) relies upon variable mangling to function correctly. Unless you're copy/pasting our
mangle.jsoninto your build system (which we don't publish, so you'd have to copy from GitHub), you're not building the library correctly and there will be runtime errors.preact-iso's<Router>, for example, makes use ofthis.__v.__khere. This corresponds withthis._vnode._childrenpre-mangle, an example of which can be seen here.