MetaTemplate 🦚
MetaTemplate is a web template generator that can take a single template definition and output...
- React in JavaScript or TypeScript, with or without Styled-Components
- Vue (beta)
- Angular (beta)
- Mustache/Handlebars (beta)
- Twig (Drupal / PHP) (beta)
- CSS/SCSS with SCSS Variables and CSS Variables
- HTML
- SilverStripe Components (alpha)
This is particularly useful for Design Systems and Pattern Libraries where a single template definition could be converted into multiple formats.
:gift: Features
- Single-source template generator.
- MetaTemplate bundles only the CSS relevant to your HTML, so give it your whole CSS file and then MetaTemplate will try to 'tree shake' your CSS, SCSS, and Styled Components declarations.
- It can generate code examples to show example usage of these component formats.
- SCSS/CSS Variable replacement... define substring matches in CSS values and replace them with Scss Variables and CSS Variables. Match a colour of
"#336699"
and replace it with variable named theme-color-background
that will be replaced in situ with references to CSS Variables of --theme-color-background
, and those will also be Scss/CSS variables that you can define at ./scss/_settings.scss
.
:palm_tree: Examples
The input format to generate these is standard CSS, and almost standard HTML called MetaHTML.
🌰 Very basic example: input tag
Input: MetaHTML and standard CSS.
Output: React JS, React TS, React JS with Styled Components, React TS with Styled Components, Mustache/Handlebars, Vue, Twig, Angular, Sass (SCSS), HTML, CSS, SilverStripe Components.
These next two examples come from FlexBoxGrid.com and we've chosen two components with different complexities.
:seedling: Slightly more complicated example: FlexBox Container
Input: MetaHTML and standard CSS.
Output: React JS, React TS, React JS with Styled Components, React TS with Styled Components, Mustache/Handlebars, Sass (SCSS), Vue, Twig, Angular, HTML CSS, SilverStripe Components.
:deciduous_tree: Complex example: FlexBox Column
Input: MetaHTML and standard CSS.
Output: React JS, React TS, React JS with Styled Components, React TS with Styled Components, Mustache/Handlebars, Sass (SCSS), Vue, Twig, Angular, HTML, CSS, SilverStripe.
Install
npm i @springload/metatemplate
or yarn add @springload/metatemplate
.
:crystal_ball: Future
- More template formats... contribute your favourite!
- Better CSS support.
- Loops, although because we support
children
values (childNodes) you could just nest other components instead. Maybe we don't need this. - More tests..we have basic Jest tests, and basic React tests.
:warning: Limitations
- The CSS 'tree shaking' can't handle complicated CSS such as
:not(.class)
and probably other features too, so check the output formats yourself. - This library uses
JSDOM
or Puppeteer
to parse HTML/CSS which mimics a browser environment inside Node.js. The JSDOM developers themselves note that it's possible to escape their sandbox when given malicious input, so don't use untrusted input, ya dingus.
:satellite: API
TypeScript types are provided.
makeTemplate
async function makeTemplates(template, formatIds, options) => {}
The purpose of this function is to return templates in a variety of formats.
It's an async function that takes a Template
object, an optional array of template format ids (["react-ts", "angular"]
etc...). If the 2nd argument isn't provided a default list of template format ids is used instead. options
is an Object shaped like { async: true, dom: "jsdom", log: false }
. The async
configures the internal processing of templates as either syncronous or asyncronous (the default). The dom
can be either jsdom
(the default) or puppeteer
. Finally, log
just makes MetaTemplate console.log
a few more details about the conversion, like a verbose mode.
Returns a promise that resolves to a { metaTemplates, disposeAll }
.
metaTemplates
is an array of { templateFormat, files }
where
files
is an Object that represents a file archive, with Object keys as paths and values as strings of the templates. ie, { 'scss/button.scss': 'scss file data', 'mustache/button.mustache': 'mustache template data' }
.templateFormat
is a string of the template format (react-js
or scss
or react-ts-styled-components
etc).
disposeAll
is a function to dispose of shared resources and after you finish using MetaTemplate. disposeAll
should be called to avoid memory/CPU waste. This should be called regardless of your configuration, however this is most important for people using Puppeteer rather than JSDOM (JSDOM is the default). Why disposeAll
? Well if MetaTemplate automatically cleaned up and called disposeAll
internally before returning your templates then it would be slower at batch processing, which is what MetaTemplate is typically used for. Perhaps this behaviour should be in options
.
The 1st argument Template
Object looks like,
{ id, html, css, cssVariables }
id
is a required string that is used as the TemplateId
. This is your arbitrary but unique name for this template so use something meaningful. ie, FlexColumn.html
is a required string of MetaHTML.css
is a required string of standard CSS.cssVariables
is an optional Array of Objects shaped like { id, defaultValue, nameMatch, valueMatch, valueSubstringMatch }
,
id
is a required string for the variable name that will be made in Scss Variables and CSS Variables.defaultValue
: is a required string of your preferred default value for this variable.nameMatch
, valueMatch
, and valueSubstringMatch
are all optional strings, and you would choose one of them to match the CSS that you want to insert a variable at. If you want to replace a substring ie, "#000000" with "theme-color-dark" then you might write [{ id: 'theme-color-black', defaultValue: '#000000', valueSubstringMatch: '#000000' }]
to match that substring and replace it with variables. Currently there's no way of not outputting CSS Variables.
MetaHTML ?
The reason why we need to use non-standard HTML is to know which parts should be configurable, as variables.
MetaHTML is standard HTML with two types of template variables:
There is also template if
support as <mt-if key="isShown">thing to show</mt-if>
.
makeIndexImports
async function makeIndexImports( files, cssVariables ) => {}
The purpose of this function is to provide "index" definitions for each format. The exact details vary by format, but the Sass (Scss) makes an index.scss
file with lots of @import "thing.scss"
, and a _settings.scss
for the Scss variables (hence the cssVariables
argument). The JavaScript/TypeScript templates have lazy-loaded imports in index.js
or index.ts
.
The files
Object is a required variable that represents a file archive, with Object keys as paths and values as strings of the file data. Typically you'd want to return the files
object returned by the default export.
cssVariables
is an optional Object with the same shape as the cssVariables
argument given to the default export.
Returns a files
Object that represents a file archive, but now it has index files for each format (ie, "scss/index.scss"
) to assist with importing files for that format.
makeUsage
async function makeUsage( code, templates, formatIds ) => {}
The purpose of this function is to convert a single code example (eg, in documentation) into examples from a variety of template formats.
code
is a code example,
- TIP: Try
jsxToUsageCode
for a slightly easier way of generating code
.
It's datastructure is an Array of TemplateConfig
Objects shaped like,
{ templateId, variables }
Where templateId
is a string of the TemplateId
(same as the default export... your arbitrary id for the template), and variables
is an Object keyed by variableName
s whose values can be strings or other TemplateConfig Objects. ie, [{ templateId: 'H1', variables: { children: 'Hello' } }]
or [{ templateId: 'H1', variables: { children: [{ templateId: 'A', variables: { href: 'https://html5zombo.com/', children: 'Click me' } }] } }]
.
templates
is a required Object keyed by strings of TemplateId
s whose values are Template
Objects (like the default export). This must include every templateId
referenced in code
.
formatIds
is an optional array of strings of the formats to use, with a complete list of formatIds as the default.
jsxToUsageCode
async function jsxToUsageCode( jsx ) => {}
A convenience function that parses a string of React JSX and returns a code
variable for the makeUsage function.
- jsx is a required string of JSX ie,
'<H1><A href="https://html5zombo.com/">Click me</A></H1>'
will return [{ templateId: 'H1', variables: { children: [{ templateId: 'A', variables: { href: 'https://html5zombo.com/', children: 'Click me' } }] } }]