SkillAgentSearch skills...

Esx

Like JSX, but native and fast

Install / Use

/learn @esxjs/Esx
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

esx

Build Status Coverage js-standard-style

High throughput React Server Side Rendering

<img src="https://avatars1.githubusercontent.com/u/45238803?s=400&u=83a23d46289a2f151a58f18001458f1494174853&v=4" width="150" alt="esx demo">

For a simplified example of esx in action, check out esx-demo.

esx is designed to be a high speed SSR template engine for React.

It can be used with absolutely no code base changes.

Use it with a preloader flag like so:

node -r esx/optimize my-app.js

Note: transpiling is still experimental.

Alternatively babel-plugin-esx-ssr can be used to transpile for the same performance gains. The babel plugin would be a preferred option where speed of process initialization is important (such as serverless).

Optionally, esx is also a universal JSX-like syntax in plain JavaScript that allows for the elimination of transpilation in development environments.

  • For the server side, using esx syntax will yield the same high speed results as the optimizing preloader
  • For client side development, using esx syntax can enhance development workflow by removing the need for browser transpilation when developing in modern browsers
  • For client side production esx can be compiled away for production with babel-plugin-esx-browser, resulting in zero-byte payload overhead.

It uses native Tagged Templates and works in all modern browsers.

<p align="center"> <img src="assets/jsx-vs-esx.png" width="800" alt="esx demo"> </p>

Status

Not only is this project on-going, it's also following a moving target (the React implementation).

This should only be used in production when:

  • It has been verified to yield significant enough performance gains
  • It has been thoroughly verified against your current implementation

esx needs use cases and battle testing. All issues are very welcome, PR's are extremely welcome and Collaborators are exceptionally, extraordinarily, exceedingly welcome.

Install

npm i esx

Tests

There are close to 3000 passing tests.

git clone https://github.com/esxjs/esx
cd esx
npm i
npm test
npm run test:client # test client-side implementation in node
npm tun test:browser # test client-side implementation in browser

Syntax

Creating HTML with esx syntax is as close as possible to JSX:

  • Spread props: <div ...${props}>
  • Self-closing tags: <div />
  • Attributes: <img src="https://example.com/img.png"/> and <img src=${src}/>
  • Boolean attributes: <div draggable />
  • Components: <Foo/>
    • Components must be registered with esx: esx.register({Foo})

Compatibility

  • react v16.8+ is required as a peer dependency
  • react-dom v16.8+ is required as a peer dependency
  • esx is built for Node 10+
  • Supported Operating Systems: Windows, Linux, macOS

Limitations

esx should cover the API surface of all non-deprecated React features.

Notably, esx will not work with the Legacy Context API, but it will work with the New Context API.

While the legacy API is being phased out, there still may be modules in a projects depedency tree that rely on the legacy API. If you desperately need support for the legacy API, <a href="https://twitter.com/messages/compose?recipient_id=323355503">contact me</a>..

Usage

As an optimizer

Preload esx/optimize like so:

node -r esx/optimize my-app.js

That's it. This will convert all JSX and createElement calls to ESX format, unlocking the throughput benefits of SSR template rendering.

As a JSX replacement

Additionally, esx can be written by hand for great ergonomic benefit in both server and client development contexts. Here's the example from the htm readme converted to esx (htm is discussed at the bottom of this readme):

// using require instead of import allows for no server transpilation
const { Component } = require('react') 
const esx = require('esx')()
class App extends Component {
  addTodo() {
    const { todos = [] } = this.state;
    this.setState({ todos: todos.concat(`Item ${todos.length}`) });
  }
  render({ page }, { todos = [] }) {
    return esx`
      <div class="app">
        <Header name="ToDo's (${page})" />
        <ul>
          ${todos.map(todo => esx`
            <li>${todo}</li>
          `)}
        </ul>
        <button onClick=${() => this.addTodo()}>Add Todo</button>
        <Footer>footer content here</Footer>
      </div>
    `
  }
}
const Header = ({ name }) => esx`<h1>${name} List</h1>`
const Footer = props => esx`<footer ...${props} />`

esx.register({ Header, Footer })

module.exports = App

In a client entry point this can be rendered the usual way:

const App = require('./App')
const container = document.getElementById('app')
const { hydrate } = require('react-dom') // using hydrate because we have SSR
const esx = require('esx')({ App })
hydrate(esx `<App page="All"/>`, container)

And the server entry point can use esx.renderToToString for high speed server-side rendering:

const { createServer } = require('http')
const App = require('./App')
createServer((req, res) => {
  res.end(`
    <html>
      <head><title>Todo</title></head>
      <body>
        <div id="app">
        ${esx.renderToString `<App page="All"/>`}
        </div>
      </body>
    </html>
  `)
}).listen(3000)

API

The esx module exports an initializer function, which returns a template string tag function.

Initializer: createEsx(components = {}) => esx

The default export is a function that when called initializes an instance of esx.

import createEsx from 'esx'
const createEsx = require('esx')

The initializer takes an object of component mappings which it then uses to look up component references within the template.

When called, the Initializer returns a Template Engine instance.

Template Engine: esx`<markup/>` => React Element

The result of the Initializer is a Template Engine which should always be assigned to esx. This is important for editor syntax support. The Template Engine instance is a template tag function.

import createEsx from 'esx'
import App from 'components/App'
const esx = createEsx({ App }) // same as {App: App}
// `esx` is the Template Engine
console.log(esx `<App/>`) // exactly same result as React.createElement(App)

Component Registration

A component must be one of the following

  • function
  • class
  • symbol
  • object with a $$typeof key
  • string representing an element (e.g. 'div')

createEsx(components = {})

Components passed to the Initializer are registered and validated at initialization time. Each key in the components object should correspond to the name of a component referenced within an ESX template literal.

esx.register(components = {})

Components can also be registered after initialization with the esx.register method:

import createEsx from 'esx'
import App from 'components/App'
const esx = createEsx()
esx.register({ App })
// exactly same result as React.createElement(App)
console.log(esx `<App/>`) 

Each key in the components object should correspond to the name of a component as referenced within an ESX template literal.

esx.register.one(name, component)

A single component can be registered with the esx.register.one method. The supplied name parameter must correspond to the name of a component referenced within an ESX template literal and the component parameter will be validated.

esx.register.lax(components = {})

Advanced use only. Use with care. This is a performance escape hatch. This method will register components without validating. This may be used for performance reasons such as when needing to register a component within a function. It is recommended to use the non-lax methods unless component validation in a specific scenario is measured as a bottleneck.

esx.register.lax.one(name, component)

Advanced use only. Use with care. This is a performance escape hatch. Will register one component without validating.

Server-Side Rendering: esx.renderToString`<markup/>` => String

On the server side every Template Engine instance also has a renderToString method. The esx.renderToString method is also a template literal tag function.

This must be used in place of the react-dom/server packages renderToString method in order to obtain the speed benefits.

import createEsx from 'esx'
import App from 'components/App'
const esx = createEsx()
esx.register({ App })
// same, but faster, result as ReactDomServer.renderToString(<App/>)
console.log(esx.renderToString `<App/>`)

Alias: esx.ssr

esx.renderToString(EsxElement) => String

The esx.renderToString method can also accept an element as its only parameter.

import createEsx from 'esx'
import App from 'components/App'
const esx = createEsx()
esx.register({ App })
const app = esx `<App/>`
// same, but faster, result as ReactDomServer.renderToString(app)
console.log(esx.renderToString(app))

Elements created with esx contain template information and can be used for high performance rendering,

View on GitHub
GitHub Stars660
CategoryDevelopment
Updated1mo ago
Forks11

Languages

JavaScript

Security Score

95/100

Audited on Feb 2, 2026

No findings