Migrate your Dust.js codebase to pure components and jsx ( bit by bit ).
If you use Dust.js as your primary templating language and you have plans to migrate to React or at least to step closer to component-based approach, then this repo will probably be interesting for you. With dust-components it's possible to use pure React components in form of regular dust helpers.
Lets go through some refactoring steps of an example template:
<div>
<div class="container {containerClass}">
<h1>{containerHeaderText}</h1>
<div class="container-body">
{#authors}
<div class="author {itemClass}">
<div class="author-name">{name}</div>
<div class="author-surname">{surname}</div>
<button class="button button-vote">Like!</button>
</div>
{/authors}
</div>
</div>
</div>
At every step we will extract some part of a template markup into a component.
const cx = require('classnames');
function Button(props) {
return (
<button className={cx('button', props.className)}
name={props.name}
id={props.id}
disabled={props.disabled}>{props.text}</button>
);
}
module.exports = Button;
Now we can rewrite original template as follows:
<div>
<div class="container {containerClass}">
<h1>{containerHeaderText}</h1>
<div class="container-body">
{#authors}
<div class="author {itemClass}">
<div class="author-name">{name}</div>
<div class="author-surname">{surname}</div>
{@Button className="button-vote" text="Like!"/}
</div>
{/authors}
</div>
</div>
</div>
Note: to be able to use @Button helper in template above, we had to import and register Button component first. See How to setup section for all instructions on doing that
const cx = require('classnames');
const Button = require('./Button');
function Author(props) {
return (
<div className={cx('author', props.className)}>
<div className="author-name">{props.name}</div>
<div className="author-surname">{props.surname}</div>
<Button className="button-vote" text="Like!"/>
</div>
);
}
module.exports = Author;
Refactored template:
<div>
<div class="container {containerClass}">
<h1>{containerHeaderText}</h1>
<div class="container-body">
{#authors}
{@Author className="{itemClass}" name="{name}" surname="{surname}"/}
{/authors}
</div>
</div>
</div>
Note: notice that button's component could be used both in dust templates as a helper and in other components as a regular component.
const cx = require('classnames');
const Author = require('./Author');
function AuthorsList(props) {
const authors = props.authors || [];
return (
<div className="authors-list">
{
authors.map(function (author) {
return <Author className={cx(props.itemClass)} name={author.name} surname={author.surname}/>;
})
}
</div>
);
}
module.exports = AuthorsList;
Refactored template:
<div>
<div class="container {containerClass}">
<h1>{containerHeaderText}</h1>
<div class="container-body">
{@AuthorsList itemClass="{itemClass}" authors=authors/}
</div>
</div>
</div>
const cx = require('classnames');
function Container(props) {
return (
<div className={cx('container', props.className)}>
<h1>{props.headerText}</h1>
<div className="container-body">
{props.children}
</div>
</div>
);
}
module.exports = Container;
Refactored template:
<div>
{@Container className="{containerClass}" headerText="{containerHeaderText}"}
{@AuthorsList itemClass="{itemClass}" authors=authors/}
{/Container}
</div>
- Most part of existed code migrated to isolated components, compatible with React
- Dust.js template slimmed down to it's minimum declarative form
with npm:
npm i --save dust-components
with yarn:
yarn add dust-components
Before components can be used - they have to be transformed with custom pragma function:
{
loader: 'babel-loader',
options: {
plugins: [
["transform-react-jsx", {
"pragma": "dcNode"
}]
]
},
// ...
plugins: [
new webpack.ProvidePlugin({
dcNode: ['dust-components', 'pragmaFunction']
})
]
Components has to be registered as helpers in order to be used in Dust.js templates. To do that use HelperFactory that goes with this repo:
// Import components:
const Button = require('components/Button');
const Author = require('components/Author');
const AuthorsList = require('components/AuthorsList');
const Container = require('components/Container');
// Setup helper factory:
const dust = require('dustjs-linkedin');
const createHelper = require('dust-components').HelperFactory(dust);
// Register components:
dust.helpers['Button'] = createHelper(Button);
dust.helpers['Author'] = createHelper(Author);
dust.helpers['AuthorsList'] = createHelper(AuthorsList);
dust.helpers['Container'] = createHelper(Container);
Note: probably it's a good idea to generate such registration code on build phase
To run project tests:
yarn run test
Check project tests directory to see migration examples from this README, other usecases or to add more tests.
TODO: