Closed ClassicOldSong closed 1 month ago
I have no clue why you post this as an issue.
I think I have made my points clear: classic JSX transformation is still valid in some frameworks, no dedicated JSX transformers have plan to get rid of classic transformation and nor should here.
Classic transformations are not obsolete and have meanings in some scenarios beyond the new jsx-runtime convention.
If you don't understand why I opened this issue, please check your website and there's
👉 Note: support for the classic runtime is deprecated and will likely be removed in the next major version.
written multiple times in https://mdxjs.com/packages/mdx
I think you can update your framework to support the automatic runtime
I provided the above example to show that classic
is a required feature for the framework to work. The renderer can be swapped on runtime instead of build time by providing it dynamically. It's a framework feature, upgrade
sounds like a downgrade in this case.
For a more complete example:
import { signal } from 'refui'
import { createDOMRenderer } from 'refui/dom'
import { createHTMLRenderer } from 'refui/html'
import { defaults } from 'refui/browser'
const DOMRenderer = createDOMRenderer(defaults)
const HTMLRenderer = createHTMLRenderer()
const App = () => {
const count = signal(0)
const increment = () => {
count.value += 1
}
return (R) => (
<>
<h1>Hello, rEFui</h1>
<button on:click={increment}>Click me! Count is {count}</button>
</>
)
}
// Render directly onto the DOM
DOMRenderer.render(document.body, App)
// Render to string
console.log(HTMLRenderer.serialize(HTMLRenderer.createElement(App))
Please listen to what I say: you can add the automatic runtime to your framework. The automatic runtime can do the same thing as the classic runtime. It can also do “update functions”
But by doing it via import { jsx } from 'some/jsx-runtime'
, the swap is global. Unless render to function body, the jsx
method that changes will affect all currently rendered components that were rendered by a different renderer.
How many different R
s are there? Why do you want many different R
s?
There might be a lot in the future, the R
can even render to physical hardwares/non-browser environments(out of scope but it really can, I have build specific runtime and hardware platform that is capable of doing this).
Currently there are two of them, the DOM one and the HTML one.
The original issue do not do something came across pretty confusing, but I see where you’re coming from. I don’t think a major version for MDX is happening very soon, but I do think it’s good to discuss if / how / why we want to support the classic runtime before we just remove it.
The JSX pragma R.c
and fragment R.f
don’t come from imports, but are injected by a function. I see how this conflicts with the automatic runtime, given the automatic runtime generates imports (even if we pass around the automatic runtime via options already in some places). The classic runtime does not typically rely on imports.
I am a bit confused though, how are you using rEfui
with MDX currently? MDX also generates an import when using the classic runtime, configured by the option pragmaImportSource
.
Currently there are two of them, the DOM one and the HTML one.
There might be a lot in the future
Why do they have to be different in the same file? How is there one component going to hardware and another going to I dunno a PDF? One to HTML another to DOM?
The renderer can be swapped on runtime instead of build time by providing it dynamically.
You can also do this with an automatic runtime.
Let someone import setThing
from your framework
, let people call setThing
. Inside _jsx
, take thing
.
This is a discussion. Issues are not for discussions. We have discussions for discussions.
Why do they have to be different in the same file? How is there one component going to hardware and another going to I dunno a PDF? One to HTML another to DOM?
Like displaying on screen and also provide a downloadable rendered result, in this case PDF is a valid render target.
You can also do this with an automatic runtime. Let someone import
setThing
from yourframework
, let people callsetThing
. Inside_jsx
, takething
.
I have said, in the case where multiple renderers all have something rendered, changing thing
globally will break their ability to render anything more.
I agree to move to discussions.
I am a bit confused though, how are you using
rEfui
with MDX currently? MDX also generates an import when using the classic runtime, configured by the optionpragmaImportSource
.
I'm exploring about making a document site for our upcoming JS runtime, and I'd like to use my own framework to handle the generation. As I have experimented, I did use a jsx-runtime
wrap to the existing classic render methods but that's way too hacky and is not very portable, as described above.
Working example: stackblitz
It doesn’t look that hacky IMO. As far as I can tell, you don’t need to assign or export those module level variables. You just need the wrap
function.
Like displaying on screen and also provide a downloadable rendered result, in this case PDF is a valid render target.
The thing with React/Preact/etc is that they create a VDOM. A virtual DOM. They later render those virtual nodes. They can render to PDF. To RSS. To HTML. To native. To CLIs.
Frameworks can do this. With the same nodes. Mapping them to different things. Why do you not do this? Why do you not take one node, and map it to PDFs and HTML and other things?
way too hacky and is not very portable
Looks fine to me.
Except that you must not expose jsxDEV
like that. In development, a different file is loaded. Expose jsx
and jsxs
and Fragment
from one file. Expose jsxDEV
and Fragment
from another file.
In this example,yes. But when rendered to a static site, it means I have to inject the wrap function and create a renderer manually in each generated page, or it's not instantly usable.
Why do you not do this? Why do you not take one node, and map it to PDFs and HTML and other things?
For performance. I use JSX like what Solid does but don't want to introduce too much complexity distinguishing between server build and client build, in order to keep the framework simple and portable.
I don’t think switching at runtime, per component, is good for performance. If you want performance, use a specific HTML runtime. A specific RSS runtime. A specific PDF runtime. That’s fast.
The automatic runtime is an improvement for performance. I recommend you use it.
If you want performance, use a specific HTML runtime. A specific RSS runtime. A specific PDF runtime. That’s fast.
For doing one-shot render, that's true, but when the render context is preserved and only little modification is needed for a new render, my approach is much faster since it doesn't need to construct everything from scratch every time.
That’s what React and friends also optimize for. Diffing virtual DOMs. Only applying the patches
I don't need the diffing phase, changes are applied directly and precisely on where they need to change.
You just explained applying patches. Patches means diffs?
There's no diff happening when rendering, that means there're no patches generated to be applied.
It works almost in the same way Solid does, with some differences in implementation details.
For doing one-shot render, that's true, but when the render context is preserved and only little modification is needed for a new render, my approach is much faster since it doesn't need to construct everything from scratch every time.
I understand this as patches. And something is diffing there.
Regardless, say you call these “little modifications” something else. How do these “little modifications” happen to a string of static HTML? To a string of static XML in an RSS? To a PDF? Wouldn’t The little modifications only really work, usefully, with a live DOM? Of which there is probably only one?
Two separate apps are created in your example: https://github.com/mdx-js/mdx/issues/2547#issuecomment-2422246133. Only the DOM version has some live binding, recalculation thing.
That's not true. All of them have live bindings, just the HTML app isn't assigned to a variable.
import { signal. nextTick } from 'refui'
import { createDOMRenderer } from 'refui/dom'
import { createHTMLRenderer } from 'refui/html'
import { defaults } from 'refui/browser'
const DOMRenderer = createDOMRenderer(defaults)
const HTMLRenderer = createHTMLRenderer()
const count = signal(0)
const App = () => {
const increment = () => {
count.value += 1
}
return (R) => (
<>
<h1>Hello, rEFui</h1>
<button on:click={increment}>Click me! Count is {count}</button>
</>
)
}
// Render directly onto the DOM
DOMRenderer.render(document.body, App)
// Render to string
const htmlApp = HTMLRenderer.createElement(App)
console.log(HTMLRenderer.serialize(htmlApp)
// yields
// <button>Click me! Count is 0</button>
count.value += 10
nextTick(() => {
console.log(HTMLRenderer.serialize(htmlApp))
// yields
// <button>Click me! Count is 10</button>
// Count rendered on DOM also changes
})
This is a different example. You miss what I am saying: it’s not useful.
I understand. You don't have use cases for this degree of freedom, but I need them so I created my frameworks in the first place(as all other frameworks are all coupled into web heavily, even assuming your environment is brower and abusing browser specific features) and won't limit their usable scenarios in the future.
I'll still try to find better ways to integrate into MDX but I still suggest to reconsider about classic transformations.
I don’t understand your use case. I don’t see a use case for live patches to a PDF.
I don’t agree with your point. You at least miss react-native and vadimdemedes/ink
.
I don't miss react-native as I have made literally any web frameworks usable on mobile platforms: https://github.com/SudoMaker/nativescript-dom-ng
JavaScript has much more potentials and I don't want people limiting all their possibilities to web. The JS runtime I mentioned above can even run on embedded devices that have only 8MB of physical ram, yet rendering GUI applications at 60fps.
I understand that you can't understand what I'm talking about, since seldom people have vision across multiple fields that seem to be distant.
Now you are insulting me.
If you can’t explain your use case, perhaps that’s something you should improve.
MDX is not coupled to the web.
Something isn't explainable if the other participants don't have knowledge in the topic on the same level. I don't mean insulting, and sorry for that if that makes you feel uncomfortable.
I'm bad at explaining things so forgive me if I couldn't make it clear to you. As I have said,
I'll still try to find better ways to integrate into MDX but I still suggest to reconsider about classic transformations.
OK. Thanks.
This issue tracker is for MDX. The context you provide with your question is not about MDX.
Initial checklist
Problem
There're frameworks that solve the problem React tried to solve with
jsxFactory
in different ways. The render function is passed to the render method returned by the component dynamically, thus eliminates the requirements for ajsxFactory
or apragmaImportSource
to be imported globally. Removingclassic
support would break these frameworks from functioning with MDX.For example, with rEFui, components return a render method that accepts a renderer:
which yields
This behavior mentioned above is supported in almost all JSX transpilers on the market, including esbuild, rollup and babel.
Solution
Keep
classic
option forjsxRuntime
and allow specifyingnull
topragmaImportSource
for not generating pragma imports.Alternatives
None