An intuitive way of creating templates and rendering them using the JSX syntax
With this tool you can easily create templates and render them to a string. It uses the JSX syntax from React to make templates. It is the perfect tool for backends that serve HTML content.
This is an npm package you can install in your project like this:
npm install --save template-jsx
This package is made for transpilers. So make sure to use either Babel or TypeScript. To correctly use the JSX functions, make sure to import the package in every file, like React:
import * as jsxt from "template-jsx";
When you use TypeScript, you will have to set the jsx
flag to react
in your tsconfig.json file. You also have to specify the factory functions:
"jsx": "react",
"jsxFactory": "jsxt.createElement",
"jsxFragmentFactory": "jsxt.Fragment",
When using Babel, you will need a JSX transform plugin and you have to specify the JSX factory.
When you have installed and configured it you are ready to go. Create some elements using JSX. Even element generator functions and fragments are supported. But try it yourself. To get the final output, you have to use the jsxt.render
function. It will take the root element and return a string representation of the JSX elements:
const app = <div>Other elements...</div>;
const rendered = jsxt.render(app);
For generator functions there is a special type:
const Greeting: ElementGenerator<{ name: string }> = (props) => (
<>Hello {props.name}!</>
);
As you can see in this example, you can use so called "fragments" to simply return text or connect multiple elements without a parent.
There are several options you can specify. The most important one is the "indent" option. It lets you set if the resulting code should be indented. It is false by default. Take a look at this:
const app = <div>sub elements</div>;
jsxt.render(app, { indent: false });
/*
<div>sub elements</div>
*/
jsxt.render(app, { indent: true });
/*
<div>
sub elements
</div>
*/
If you don't want the indent to be set to 4 spaces, you can change the amount with the indentSize
option. If you don't even want to use spaces, if you prefer tabs for example, you can use indentString
. Note: indentString
will be used before indentSize
.
When rendering HTML pages, there is a very helpful predefined component called HtmlPage
. All attributes specified will be applied to the html
tag in the output. The output also includes a DOCTYPE
element. All children will be put into the body
element:
const app = <HtmlPage>
<div>sub elements</div>
</HtmlPage>;
jsxt.render(app, { indent: false });
/*
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>sub elements</div>
</body>
</html>
*/
When this library is not made for frontend, what else would you need it for than webservers? This package has great support for express. There is an extra function called create
, which takes the options and creates a renderer function. It has the HtmlPage
component built-in, so if you don't pass one, it will automatically generate one. This is the basic usage:
const render = jsxt.create({
indent: true,
indentSize: 2,
});
app.get("/", (req, res) => {
res.send(render(<Home />));
});
If you don't need any other action in the request handler, you can just use the createHandler
method from jsxt.create
. The component will get the request and response object to do something with it:
const { createHandler } = jsxt.create({
indent: true,
indentSize: 2,
});
app.get("/", createHandler(Home));
Optionally you can set a specific status code as a second parameter. It defaults to 200. When spreading the pages up to different files it might be helpful to specify a status
attribute on an HtmlPage
. Note: the createHandler
parameter is preferred.
app.get("*", createHandler(NotFound, 404));
In this case the NotFound
component can access the request object to output the incorrect path.
If you look at options.useSelfCloseTags
, the jsxt.create
function has the HTML self-closing tags already preset. Of course you can override it.
Bored of writing crazy expressions for conditional elements? Then you can use the built-in If
Component. It takes an expression and if that expression is true it outputs the elements.
const MyApp: ElementGenerator = () => {
return (
<>
<div id="header"></div>
<div id="content"></div>
<If cond={Math.random() > 0.98}>
<div id="big">
<a href="https://www.youtube.com/watch?v=j8PxqgliIno">
Watch this video
</a>
</div>
</If>
</>
);
};
There is another feature called Switch
that (you guessed it!) switches over different cases. The usage is really simple:
const MyApp: ElementGenerator = () => {
return (
<Switch expr={Math.round(Math.random() * 10)}>
<Case c={1}>Case 1</Case>
<Case c={2}>Case 2</Case>
<Case c={3}>
Case 3<br />
Lorem ipsum dolor
</Case>
<Case c={4}>
Case 4 (You can put different things than just "Case x" in here
:-) )
</Case>
<Case c={5}>
<a href="https://www.youtube.com/watch?v=j8PxqgliIno">
Watch this video
</a>
</Case>
<Default>No case was matched.</Default>
</Switch>
);
};
As you can see, there are Case
elements nested in it. (Including a default case with Default
)
options.indent: boolean
- This option specifies if the resulting code should be formatted and indented. If it is set tofalse
, the whole output will be in one line.options.indentSize: number
- Sets the amount of whitespaces used for indenting. Only used whenoptions.indent
is true.options.indentString: string
- If you don't want to use whitespaces, if you want to use tabs, for example, you can set this to your indentation string. If bothoptions.indentString
andoptions.indentSize
are set, this one (options.indentString
) will be preferred.options.useSelfCloseTags: boolean | string[]
- When you don't have children in an element, it will be outputted like<div />
. If this is set to false, it will normally output both tags. If you even specify a list of strings, the self-closing will only be rendered for tags in that list. This is very useful when rendering web pages withimg
orinput
elements inside.
This project is licensed under the MIT license. Read it here.