Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved JSX transform for Server-Side Rendering #57468

Closed
6 tasks done
arthurfiorette opened this issue Feb 21, 2024 · 4 comments
Closed
6 tasks done

Improved JSX transform for Server-Side Rendering #57468

arthurfiorette opened this issue Feb 21, 2024 · 4 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@arthurfiorette
Copy link

arthurfiorette commented Feb 21, 2024

πŸ” Search Terms

jsx precompile jsxAttr jsxEscape jsxTemplate Fastest Fast(est) JSX transform preact react jsxs jsxDEV typescript node deno runtime custom configuration ts

βœ… Viability Checklist

⭐ Suggestion

I'd like to propose the implementation of a new JSX transform optimized specifically for server-side rendering (SSR).

This proposal draws inspiration from a recent release in the Deno runtime, which introduced a highly efficient JSX transform for SSR purposes.

Traditionally, JSX has relied heavily on the Garbage Collector (GC) due to its origins as a templating engine primarily designed for client-side rendering (CSR). However, for SSR scenarios where performance and memory efficiency are critical, this reliance on the GC can lead to suboptimal performance and increased overhead.

The proposed JSX transform works by serializing the HTML parts of a JSX template into static string arrays at compile time. This approach significantly reduces the number of short-lived object allocations and minimizes the workload on the GC during runtime.

Expected benefits as observed in the official deno blog post:

  • Improved Performance: Significant reduction in rendering times (observed around 7-20x faster rendering times).
  • Reduced GC Overhead: Approximately 50% reduction in Garbage Collection times.
  • Framework Agnostic: Designed to be independent of any specific framework, providing flexibility for integration with various SSR solutions.
  • Customizable Configuration: Users can specify a custom JSX runtime module via configuration, enabling seamless integration with existing projects.

Library adoption:

Currently, only Preact has integrated support for this optimized JSX transformation, as evidenced by its recent pull request (and Flesh which doesn't count as it uses preact under the hood).

Given TypeScript's potential adoption of this feature, widespread support across various libraries is foreseeable, including popular frameworks like React, all of which stand to gain significant performance benefits.

Moreover, extending this optimization to other JSX runtimes could yield substantial improvements across the ecosystem.

As this feature is implemented, it could be highlighted as a major improvement in future releases, potentially under titles like: "New Typescript JSX for server-side rendering -> 20x Performance Boost." and other things the marketing team needs and likes to hear.

πŸ“ƒ Motivating Example

Consider the following input:

const pClass = 'foo ' + 'bar';
const name = 'world';

const html = (
  <div class="foo">
    <h1>this is a demo</h1>
    <p class={pClass}>some cool content {name}</p>
  </div>
);

Current output

import { jsx } from 'preact/jsx-runtime';

const pClass = 'foo ' + 'bar';
const name = 'world';

const html = jsxs('div', {
  class: 'foo',
  children: [
    jsx('h1', { children: 'this is a demo' }),
    jsxs('p', { class: pClass, children: ['some cool content ', name] })
  ]
});

With the new "jsx": "precompile"

(output copied from deno bundle for this repository)

import { jsxAttr, jsxEscape, jsxTemplate } from 'preact/jsx-runtime';

const pClass = 'foo ' + 'bar';
const name = 'world';

const $$_tpl_1 = [
  '<div class="foo"><h1>this is a demo</h1><p ',
  '>some cool content ',
  '</p></div>'
];

const html = jsxTemplate($$_tpl_1, jsxAttr('class', pClass), jsxEscape(name));

πŸ’» Use Cases

  1. Server-side rendering (SSR) applications: Improve performance and reduce garbage collection overhead in SSR applications with TypeScript and Node.js.

  2. Large-scale applications: Enhance performance for projects handling extensive JSX content, like complex UIs or dynamic content generation.

  3. Microservices architecture: Boost overall system performance by optimizing JSX rendering across multiple SSR services.

  4. Real-time applications: Achieve smoother user experiences in applications requiring frequent updates or real-time data rendering.

  5. Custom JSX runtimes: Allow developers to integrate with custom JSX runtimes for specific project needs, enhancing flexibility and modularity.

Good reads:

@RyanCavanaugh
Copy link
Member

What's the advantage of creating a second implementation compared to using jsx: preserve and the existing precompiler?

@arthurfiorette
Copy link
Author

arthurfiorette commented Feb 21, 2024

Which precompiler are you referring to? Deno now handles it automatically at runtime. The deno bundle CLI, used for pasting precompiled output above, is deprecated. Deno focuses on running TypeScript directly and deno bundle CLI merely "mimics" the actual code executed.

Also, a "official" TS implementation could be used in any JS runtime.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Feb 21, 2024

If Deno's just doing a code transform, then that should be usable as a standalone API, I would hope. If it's not, then it seems kinda weird for TS to be on the leading edge of JSX SSR. We're a type checker.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Out of Scope This idea sits outside of the TypeScript language design constraints labels Feb 22, 2024
@RyanCavanaugh
Copy link
Member

I'm not seeing the need for a second implementation with identical constraints. If this transform can be done from syntax only, then it doesn't make sense for TS to be doing it -- it can be a general tool that takes in any JSX, and belongs in a bundle/minify/etc step (and if it needs type info, type-directed emit is explicitly out of scope). React Compiler should be out soon and would presumably be the most logical place for this kind of functionality to live.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants