jsxmin

3.0.1-jsxish • Public • Published

Heads up! This package (and its subpackages) has recently undergone a significant restructuring and there may be some missing functionality, missing documentation, or all of the above. Generally speaking, it is functional and usable, but stay tuned for continued updates.

jsxmin — minimal jsx templating.

jsxmin allows you to write JSX and transpile it to plain, vanilla javascript without React or any other runtime libraries.

Motivation

JSX provides an intuitive and straightforward syntax that's easy to learn, battle-tested, and capable of scaling to large teams and production implementations. However, there are times when using all of React isn't available on your toolchain or environment, or you may be looking for something that is ultra-portable, or maybe you just want to go back to the old days of simple js templating (🤗).

This project attempts to take JSX syntax and transpile it to plain javascript via template literals and function calls.

Example

A basic example:

const Button = (props) => <button class="btn primary">{props.label || props.children}</button>

Will output:

const Button = (props) => '<button class="btn primary">' + (props.label || props.children) + '</button>';

Which can then be called like this:

console.log(Button({
  label: 'Hello World'
}));
// '<button class="btn primary">Hello World</button>'

Slightly more advanced example using custom elements:

import { Button } from './ui';

class HighFive extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = <Button>🖐</Button>
    this.addEventListener('click', () => {
      console.log('High five!!');
    });
  }
}
customElements.define('high-five', HighFive);

And can be called like this (as a quick example):

<html>
  <body>
    <high-five></high-five> // High five!!
    <script src="..."></script>
  </body>
</html>

Slightly more advanced example in the vein of SPAs:

import { Button } from './ui';

const App = ({name}) => <>
    <p>Hello{name ? ' ' + name : ''}!</p>
    <Button>🖐</Button>
</>

document.body.innerHTML = <App/>

And can be called like this (as a quick example):

<html>
  <body>
    <script src="..."></script>
  </body>
</html>

See tests/test.js for more examples.

API

.transform(source, opts)

Transforms a string with jsx to plain javascript and is the primary function of this library.

source should be a string.

opts is an object with properties as defined below.


.execute(source, opts)

Transform and execute a string with jsx and get the resulting output.

source should be a string.

opts is an object with properties as defined below.

Note: Whatever [valid] JavaScript statement is on the last line is what will be returned. See Dynamic usage example below.

Options

allowReferencedTagsAsFunctions[=true]

Checks if a tag is a function (within the current scope) and, if so, evaluates it and uses its return value as the output.

allowScopedParameterAccess[=false]

Pass along the props (the first parameter) to each subsequent function call.

reactCompat[=true|'strict']

Enables a compatability mode

Compat Mode Property Input Output Implemented?
all className className={{container: true, content: false}} class="container" ✔️
strict className className={{container: true}} class="[object Object]" ✔️
all style style={{color: 'red', height: 10}} style="color: red; height: 10px;" ✔️
strict style style={{color: 'red', height: 10}} style="color: red; height: 10px;" ✔️
all any data-model={{id: 12345}} data-model="{&quot;id&quot;: 12345}" ✔️
strict any data-model={{id: 12345}} data-model="[object Object]" ✔️
all dangerouslySetInnerHTML dangerouslySetInnerHTML={'<a onclick=alert(1)>:)</a>'} - 𝘅
all htmlFor htmlFor="id" for="id" ✔️
all selected selected selected="selected" ✔️
See below for usage examples

Installation

To install and use as a module in your Nodejs/Babel toolchain, run:

npm install jsxmin

Or to install the babel plug-in, run:

npm install babel-plugin-jsxmin

And add this to your Babel configuration:

{
  ...
  plugins:  ['babel-plugin-jsxmin']
  ...
}

See babel-plugin-jsxmin/README for more details.

Direct Usage

Dynamic usage:

const Jsxmin = require('jsxmin');

const tmpl = await Jsxmin.execute(`
    ({name}) => <p>Hello {name || 'world'}</p>
`, {
  // NOTE: these are the default values and are only being passed here for demonstration purposes.
  allowReferencedTagsAsFunctions: true,
  reactCompat: true
});

console.log(tmpl({name: 'Github'})) // '<p>Hello Github</p>'

Build-time usage:

const Jsxmin = require('jsxmin');
const Fs = require('fs');

const source = Fs.readFileSync('./ui.jsx', 'utf-8');
const compiled = await Jsxmin.transform(source);

Fs.writeFileSync('./ui.js', compiled);

Integrations

Security

jsxmin does not currently escape or otherwise sanitize user input and thus could be vulnerable to content injection or XSS attacks (or a myriad of other attack vectors). Please ensure all user generated content has been sanitized before passing to any jsxmin compiled template or function. This project should probably not be considered production-ready until then.

TODO

  • [x] Finalize the main api (transpileFile vs transpileSource vs run) and add documentation.
  • [x] Support compiling jsx as ES modules (specifically importing and exporting)
    • [x] Support ES modules and additional Babel plugins in Fastify and Express plugins
    • [x] Resolve TODO on line 28 of babel-plugin/index.js
  • [x] Support async/await in Fastify and Express plugins
  • [x] Support spread operator for attributes (e.g., <Button {...props}></Button>)
  • [x] Use template literals instead of string literals for everything
  • [ ] Clean up internal directory structure:
    • Make releasing and incrementing on individual packages easier
    • Resolve relative vs absolute package name references
    • Ensure everything is installable and runnable
  • [x] Security and XSS sanitization
  • [ ] Add warnings for unsupported attributes (like className, dangerouslySetInnerHTML, htmlFor, onClick and other event listeners)
  • [ ] Add more examples
    • See tests/test.js for basic and advanced usecases (like partials, control flows, and plugin options)
  • [ ] Add more integrations
  • [x] Add support for including a shared/common util that could do the following:
    • Handle escaping and sanitizing user input
    • Add support for control structures and loops, etc
    • Reduce various manual checks
  • [ ] Support additional syntax via Babel plugin (e.g. @babel/plugin-syntax-decorators)
  • [ ] ...?

License

MIT

Package Sidebar

Install

npm i jsxmin

Weekly Downloads

2

Version

3.0.1-jsxish

License

MIT

Unpacked Size

46 kB

Total Files

16

Last publish

Collaborators

  • mattpowell