-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This is a Babel transform for rendering a template friendly version of your JSX app.
It generates the markup + code to be used in a pre-render build for achieving SSR in environments which don't support JavaScript rendering.
Currently supports 2 output languages:
Custom language definitions are also supported.
Template variables are variables in your components which you want to expose so that they can be used in another templating langauage.
They will usually be variables coming from an external data source, such as a database or an API.
The idea is that this transform will replace selected variables (across the components you specify) with the correct code or tag corresponding to your chosen language.
In Handlebars this might be: {{name}}
and in PHP it might look like this: <?php echo $name ?>
.
Using this transform you will be able to use the same JSX code you've written, to output a Handlebars or PHP version of the same application.
Remember, it won't be interactive, this is only for generating an initial pre-render to achieve SSR.
There are a fair few limitations so your mileage may vary.
- Assumes you already have a React/Preact app with your development/production builds setup.
- Create an additional build, a pre-render - which renders your app and extracts the rendered html (markup after running your app) into a file so it can be processed later on your server.
- Add this plugin to the pre-render build to add the template vars to the html output.
- Configure by adding
.templateVars
to components that have dynamic data. - Via your server side language, process the saved template file and pass in your data to get an SSR compatible pre-render.
npm install babel-plugin-jsx-template-vars
This should only be added to your pre-render build.
{
test: /\.(js|jsx|tsx|ts)$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
plugins: [
'babel-plugin-jsx-template-vars'
],
presets: []
}
},
There are some additional initialisation options and things to watch out for.
Add a templateVars
property to your component to specificy which variables will be exposed.
The format is an array, of strings (or arrays with additional config):
const Person = ( { name, favoriteColor } ) => {
return (
<>
<h1>{ name }</h1>
<p>Favorite color: { favoriteColor }</p>
</>
);
};
Person.templateVars = [ 'name', 'favoriteColor' ];
There are 3 types of variables that have different behaviours.
Note There are significant limitations with
control
andlist
type variables, check the docs for more information.
Replacement variables are variables that will need to be replaced by a dynamic variable.
In Handlebars this would be: {{name}}
, and if using PHP this would be: <?php echo $data['name'] ?>
.
The default variable type is a replacement variable:
Person.templateVars = [ 'name' ];
The type can also be passed as an argument:
Person.templateVars = [ [ 'name', { type: 'replace' } ] ];
Depending on the value of a specific variable, you might wish to show or hide content in your component. Use the control
type variable to signify this.
E.g.:
Person.templateVars = [ 'name', [ 'show', { type: 'control' } ] ];
In this example show
is used a control variable.
It is important to have a mechanism for showing repeatable content like arrays or lists.
This is supported with some limitations, and is signified by the list
variable type:
Person.templateVars = [ 'name', [ 'favoriteColors', { type: 'list' } ] ];
More information on Variable Types can be found in the Wiki.
The above example uses variables derived from destructured props
passed into a component.
Any variable (identifier) that resides directly in the components scope can be used:
const Person = () => {
const [ name, setName ] = useState( '' );
let favoriteColor = 'green';
return (
<>
<h1>{ name }</h1>
<p>Favorite color: { favoriteColor }</p>
</>
);
};
Person.templateVars = [ 'name', 'favoriteColor' ];
Object properties (e.g. aPerson.favoriteColor
) are not yet supported but it should be possible to add support for this in the future. In these cases you can destructure the object and use the object properties as template variables:
const aPerson = {
name: 'Mary',
favoriteColor: 'green'
};
const Person = () => {
const { name, favoriteColor } = aPerson;
return (
<>
<h1>{ name }</h1>
<p>Favorite color: { favoriteColor }</p>
</>
);
};
Person.templateVars = [ 'name', 'favoriteColor' ];
There is a working example using PHP output provided here.
There is a working example using Handlebars output provided here (also, using PHP).
Please open an issue if you have a demo project in other languages and we'll add it here.
I think I mentioned that there are significant limitations with the different variable types - its important to understand how these work in order to use this transform effectively.
More information is being added to the docs, currently on our github Wiki.
This is an exploration on a concept of semi automating the generation of Handlebars templates from JSX apps - its a first pass with a lot of holes and things to do as such its marked as alpha.
I'd be grateful for any help with the project / suggestions and alternative ideas for exploration / bug reports.
One thing to watch out for is data fetching and loading.
In complex applications, vars/props will often get passed down into various data fetching routines, and if they are replaced with template tags too early, such as {{name}}
it might cause them to fail. They need to succeed and continue as usual to get a true pre-render.
To work around this you can try to set your template vars only on components that live underneath the data requests (futher down the tree). This will ensure that the data is loaded before the template vars are replaced.
In some cases, you might need the template variable passed into the data fetching routine - this is not supported and a limitation of this approach.
This transform supports nested vars for children (arrays and objects), but only supports 1 level of depth.
It is recommended to set template vars on components that reside further down the tree and deal with those nested props directly.
- Overview
-
Installation
- Creating a pre-render build
- Output languages
- Variable types
- Example with all supported features