Open naturalethic opened 10 months ago
To use vite with babel plugins, add this to vite.config.ts:
import babel from "vite-plugin-babel";
export default defineConfig({
plugins: [
babel({
filter: /\.tsx?$/,
loader: "tsx",
babelConfig: {
babelrc: false,
configFile: false,
presets: ["@babel/preset-typescript"],
plugins: [
"@babel/plugin-syntax-jsx",
"mutraction-dom/compile-jsx",
],
},
}),
],
...
})
Running Bun native would be neat too.
Do you have any experience setting this up? Are you hoping for HMR?
Using the plugins as above works fine, though I suspect in a larger application the performance might start to drag.
I'm somewhat familiar with Vite plugins, but not babel. I'll take a look at compile-jsx
and see if I can grok it.
Looking at this a bit today. The correct approach, which would go most of the way to satisfying a typical Vite or Bun setup, would be to write a custom JSX factory lib, similar to how React, Preact, Solid, etc do it. This would require a bit of a re-architecture of your framework for element construction.
For example, if a child element has dynamic content under your framework, you'll wrap that with child(() => ... )
, however using a jsx factory, something like {state.val}
is evaluated at construction, so there is no chance to wrap it in child
. To keep that pattern, this is where a plugin might be needed to wrap that child content before it gets passed off to the jsx factory.
At any rate, this will require a lot more thinking and a determination from you to put it on the roadmap if you think its worthwhile or important. For now I'll just stick with the babel plugin while I evaluate the framework more fully.
Thus far my component code in my candidate has about half the number of lines as the Solid project I'm porting it from.
Thanks for doing this investigation legwork. It seems I need to acquaint myself with JSX factories.
You have gotten to the heart of why I wasn't able to use any existing JSX compilers/transformers that I could find. The values need to be evaluated during element construction, not before.
Maybe I can figure it out if I look at some existing implementations, like you've mentioned.
To decide whether to commit to implementing this, I'd like to know what you see as the main benefits. The obvious thing you get with vite is fast startup and HMR. That may be compelling enough on it's own, but is there more?
Ultimately, I suppose the reasoning would be the same as why you created this framework in the first place.
I wouldn't want you to commit unless it scratched an itch for you. Certainly don't do it for me! I just like this area of of the stack and trying out different frameworks. Impossible for me to say whether I'd be in a position to use it in a production setting for anything significant.
For general rationale, I think just to keep up with modern tooling, as babel seems to be on the way out. And here I believe bun will incrementally implement everything vite currently does and supercede it.
Other things I'd look at is structuring your modules to allow for tree shaking out parts that a consumer isn't using, to keep their built size smaller. Also for components it would be nice to be able to use jsx syntax for them instead of {component(...)} type syntax.
Do you use this framework in any production capacity? Does anyone else that you know of?
As for existing solutions for inspiration, I'd probably use Solid as an exemplar, and this project has pretty readable code.
I'm pretty sure no one is using this in production, and I couldn't really recommend doing so at this point. It's kind of a tech demo, but I do intend to support it, and I have (and will continue to) put effort into the developer ergonomics. But it doesn't (yet) have a proven track record of stability.
The real reason I made this is that I was under threat of being forced to use react at work. I didn't build this to use instead, but rather to be able to speak from an informed position about front end data-driven UI frameworks. I also spent a fair amount of time reading react source code. I do not like react.
I built mutraction just to see what would happen if I built something the way I would have chosen. I half expected the concept to fall apart when applied to a full framework. When I found how well everything seemed to be working out, I just kept going.
Most of the use I get out of it now is building mock-up type stuff using the sandbox. But I'm planning to keep developing it just because it's fun.
I don't know any technical reason why mutraction would be inappropriate for production. It just has a short existence, and few users or maintainers.
Anyway, I'm going to put some vite stuff on my reading list, including your link. I'm intending to learn enough to be able to decide what to do. I think keeping it modern is a big enough reason to give it a serious attempt. My main concern at this point is figuring out how to get it to work with the sandbox, which currently uses a portable browser-targeted build of babel.
As for <Component />
syntax, it seemed to me that { Component() }
was just generally as good or better in every metric. Some benefits I can imagine for the latter:
{ comps[idx]() }
or { (a ?? b)(...c) }
.Maybe I could make it work both ways for the happy paths, and esoteric fancy calls could still use the { comp }
notation.
Ok, I'll stop now. Sorry for the extended ramble.
I like the extended ramble.
Regarding <Component />
you make very good points. For what its worth I was able to get typescript types working with jsx components without a problem (in my own experimental framework .. uh work), but regardless, I like your reasons for keeping the function call.
I've put a 'watch' on this repo and look forward to seeing it develop further. Also happy to be available to bounce ideas off if you like.
J
I've done some investigation. I'm not done, but I found some stuff.
rollup provides a parse()
method but the transform
plugin hook doesn't seem to have a way to accept an AST as a transform output, as far as I can tell. A number of other "fancy" rollup transform plugins internally use babel or an alternative.
There are a number of alternatives to babel.
SWC and esbuild seem to require plugins to built in WASM. esprima seems to be abondoned. espree is built on top of acorn. I'm not interested in getting into WASM for now. So it would seem that acorn and its ilk are all that are remaining. It seems to work with recast for AST transforms, but there doesn't seem to be a practical benefit over babel.
So, as it stands, here's my plan.
I've done some work with Rust and WASM in the past. Rust is fantastic for code generation and targeting WASM is trivial. For AST transformation the experience isn't going to be much different between Rust or TS, but you can target WASM easily, as mentioned.
Very interesting. The "babel compatible" transformer seems to be not ready. Depending how stuff goes this weekend, I might be able to get into swc and rust.
One problem I'm having vite is that its build output is unusable from a file://
url.
It's an (unstated) goal of mine to be able to distribute browser-based applications as bundles of static files, invoked locally from a file system. <script type="module">
seems incompatible with this, since it requires same origin. But all file:
urls represent different origins.
In the trivial case, I had to make some changes to the vite build output to get it to run this way.
type
and crossorigin
attributes from the script tag.crossorigin
from the style <link>
.<head>
to <body>
so that document.body
would be defined. This could be accomplished with a defer
attribute instead.I'm guessing more problems would surface in a scenario where chunking or splitting came into play.
At this point, I'm targeting the goals in this order.
file://
-compatible build outputbabel
to swc
or similar.If your target is Electron or other native wrapper, this shouldn't be a problem. Browsers are so locked down I've never bothered with the use case you're attempting.
I've been hacking getting this to work with vite, using vite-plugin-babel, but ideally this would have native vite plugin, for performance reasons.