Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-engine-jsx

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-engine-jsx

JSX engine for ExpressJS

  • 3.2.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
36
decreased by-26.53%
Maintainers
1
Weekly downloads
 
Created
Source

express-engine-jsx

Build Status

Example of users.jsx view file

const Layout = require('./layout');

<Layout>
  <ul class="users">
    {users.map(user => (
      <li key={user}>{user.name}</li>
    ))}
  </ul>
</Layout>

Example of layout.jsx view file

<html lang={lang}>
<head>
  <meta charset="UTF-8"/>
</head>
<body>{children}</body>
</html>

Example of router

app.get('/users', function (req, res) {
  res.locals.lang = 'en';
  res.render('users', {
    users: [
      {name: 'Max'},
      {name: 'Bob'}
    ]
  });
});

Output html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"/></head>
<body><ul class="users"><li>Max</li><li>Bob</li></ul></body>
</html>

How it works

When you render some view, this engine takes jsx file like this

const Layout = require('./layout');

<Layout>
  <ul class="users">
    {users.map(user => (
      <li key={user}>{user.name}</li>
    ))}
  </ul>
</Layout>

and compiles it to js file like this

const React = require('react');
const requireJSX = require('express-engine-jsx/require');
const Context = require('express-engine-jsx/Context');

module.exports = function (props) {
  const __components = [];
  const context = React.useContext(EngineContext);
  const locals = context.locals || {};
 
  with (locals) {
    with (props) {
      const Layout = requireJSX('./layout');

      __components.push(
        React.createElement(
          Layout, 
          null,
          React.createElement(
            'ul',
            {className: 'users'},
            users.map(user => (
              React.createElement(
                'li',
                {key: user},
                user.name
              )
            ))
          )
        )
      );
    }
  }
  
  return __components;
};

and now this component can be rendered to html with ReactDOM.renderToStaticMarkup().

As you can see, each jsx view file returns array of components and standard html attributes are converted to react attributes

<div class="first" tabindex="1"></div>
<div class="second" tabindex="2"></div>
//...
__components.push(React.createElement('div', {className: 'first', tabIndex: '1'}));
__components.push(React.createElement('div', {className: 'second', tabIndex: '2'}));
//...

return __components;

Usage

const express = require('express');
const app = express();
const engine = require('express-engine-jsx');

server.set('views', '/path/to/views');
server.set('view engine', 'jsx');
server.engine('jsx', engine);

// optionaly
engine.setOptions({
  doctype: "<!DOCTYPE html>\n", // prepended string to every output html
  templatePath: '/path/to/template.jsx', // path to base tamplete of component for all jsx templates. Default is "express-engine-jsx/template.jsx",
  replace: (html) => {return html}, // Modify final html with this callback 
  parserOptions: {}, // See https://babeljs.io/docs/en/babel-parser#options
});

That's it, you no need to do app.set('views', 'views') and so on, attachTo will do that for you

API

engine

const engine = require('express-engine-jsx');

It's a function which takes three arguments:

  • path - path to jsx file
  • locals - object with properties which will be local variables in jsx file
  • callback - optional Node style callback which will receive html string as second argument

If you pass to engine only path and locals then it will return html.

engine('/path/to/view', {prop: 'value'}, (err, html) => console.log(html));

const html = engine('/path/to/view', {prop: 'value'});

Also, it has method engine.setOptions(options) which can modify options

options

const options = require('express-engine-jsx/options');

Object with optional properties:

  • doctype - string which will be prepended to output html, default value is "<!DOCTYPE html>\n"
  • replace - function which will take output html (without doctype), and it should return new html
  • templatePath - path to wrapper of compiled jsx, default value is express-engine-jsx/template.jsx. Undefined variable BODY will be replaced with your compiled jsx code.
  • parserOptions - options for babel.parser
  • templateOptions - options for babel.template

require

const requireJSX = engine.require || require('express-engine-jsx/require');

This is a function which you can use as regular require but this one can run jsx files. It checks if path is jsx file and if it is then requireJSX will convert this file to js code and then run it.

It also can take optional second parameter - currentWorkingDir which should be an absolute path to file directory which calls require in case when you call require from some unusual place like debugger console.

Every compiled jsx file will be cached to requireJSX.cache object where key will be path to jsx file and value will be value of module.exports inside jsx file, usually react component. You can delete any key in this cache, requireJSX will recompile jsx file on next call.

convert

const convert = engine.convert || require('express-engine-jsx/convert');

It is a function which can convert jsx template code to js code.

Arguments:

  • code - string of jsx code
  • options
    • addOnChange - boolean, default true. Will add onChnage={() => false} to every <input> with value or checked attribute. Used to omit ReactDOM warning about value prop without onChange handler.
    • parserOptions - options for babel.parser
    • template - string of jsx code wrapper. You can pass false if you don't want to wrap your code with template
    • templatePath - string, path to jsx code wrapper
    • templateOptions - options for babel.template

It also has convert.cache object for compiled templates where keys are templatePath and values are functions created by babel.template

run

const run = engine.run || require('express-engine-jsx/run');

Function which can execute js code with independent context and returns result of module.exports inside js code.

Arguments:

  • code - string of js code
  • options
    • path - string, path to file, usually path to jsx file
    • context - object which properties will be global variables inside js code
    • scriptOptions - object options for vm.Script

Context

const Context = engine.Context || require('express-engine-jsx/Context');

React context which used to bypass locals to components

attr-map

const attrMap = require('express-engine-jsx/attr-map');

This is an object where keys are names of html attributes in lower case like class and values are valid React html attributes like className. You can modify this object if I forget about some attributes.

How to integrate to other engine

For example how to integrate to ejs

const express = require('express');
const app = express();
const engine = require('express-engine-jsx');
const {dirname, resolve} = require('path');

app.locals.component = function (path, props = {}) {
  props = Object.assign({}, this, props);

  return engine(resolve(dirname(this.filename), path), props);
};

Now we can use component() in ejs files like this

<div><%- component('path/to/jsx-view', {prop: 'value'}) %></div>

Problem with more than one component in template root

In javascript you can omit ; and write like this

"first"
"second"

It does nothing, but it's valid code. In JSX you can't do same thing with elements

<div>first</div>
<div>second</div>

It will throw compilation error. It's waiting for ; after first element. You have three options to solve this problem.

First - use ;

<div>first</div>;
<div>second</div>;

Second - use <Fragment>

<Fragment>
    <div>first</div>
    <div>second</div>
</Fragment>

Third - use short Fragment notation <>...</>

<>
    <div>first</div>
    <div>second</div>
</>

License

MIT, see LICENSE file

Keywords

FAQs

Package last updated on 20 Feb 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc