Fullstack react boilerplate production ready.
This is the official generator to scaffold a retax app.
npm install -g yo generator-retax
To generate a retax-seed based on this project run:
yo retax MyAppName
The first argument of this generator is the project name (dash case). It is required.
The generator will prompt for:
- The repo url
- The author name
yo retax:actions-creator blog
The first argument of this generator is the actions creator name (camel case). It is required.
The generator will prompt for:
- The first action name created by the generated actions creator. (default:
DEFAULT_ACTION
)
This actions creator uses retax-components element.
The previous command will generate:
// actions/blog.js
import { actionsCreatorFactory } from 'retax';
import { annotator, AbstractActionsCreator } from 'retax-components';
import {
DEFAULT_ACTION,
} from 'constants/actions/blog';
@annotator.ActionsCreator() // eslint-disable-line
export default class BlogActionsCreator extends AbstractActionsCreator {
@annotator.action()
defaultAction = actionsCreatorFactory(DEFAULT_ACTION);
}
// actions/__tests__/blog-test.js
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';
import dirtyChai from 'dirty-chai';
chai.use(sinonChai);
chai.use(dirtyChai);
import {
DEFAULT_ACTION,
} from 'constants/actions/blog';
describe('blogActionsCreator', () => {
it('should exists', () => {
const BlogActionsCreator = require('../blog');
expect(BlogActionsCreator).to.be.ok();
});
it('should test the defaultAction creator', () => {
const BlogActionsCreator = require('../blog');
const ac = new BlogActionsCreator();
expect(ac).to.be.ok();
expect(ac.defaultAction(1)).to.deep.equal({
type: DEFAULT_ACTION,
payload: 1,
});
});
});
/// constants/actions/blog.js
export const DEFAULT_ACTION = 'DEFAULT_ACTION';
And update all folder index.js
accordingly.
yo retax:reducer blog
The first argument of this generator is the reducer name (camel case). It is required.
The generator will prompt for:
- The first action name handled by the generated reducer. (default:
DEFAULT_ACTION
)
The previous command will generate:
// reducers/blog.js
import { reducerFactory } from 'retax';
import { fromJS } from 'immutable';
import {
DEFAULT_ACTION,
} from 'constants/actions/blog';
function getInitialState() {
return fromJS({
value: {},
});
}
export default reducerFactory(
getInitialState(),
{
[DEFAULT_ACTION](state, action) {
return state.setIn(['value'], action.payload);
},
}
);
// reducers/__tests__/blog-test.js
import chai, { expect } from 'chai';
import dirtyChai from 'dirty-chai';
chai.use(dirtyChai);
import { fromJS } from 'immutable';
import {
DEFAULT_ACTION,
} from 'constants/actions/blog';
import blog from '../blog';
describe('Blog Reducer', () => {
it('should exists', () => {
expect(blog).to.be.ok();
});
it('should handle the DEFAULT_ACTION', () => {
let state = fromJS({ value: 0 });
const action = {
type: DEFAULT_ACTION,
payload: 1,
};
expect(state.get('value')).to.equal(0);
state = blog(state, action);
expect(state.get('value')).to.equal(1);
});
});
And update all folder index.js
accordingly.
yo retax:selector blog
The first argument of this generator is the selector name (camel case). It is required.
This selector is an idiomatic reselect selector.
The previous command will generate:
// selectors/blog.js
import { createSelector } from 'reselect';
export function blogSelector(state) {
return state.blog;
}
export const blogMapSelector = createSelector(
blogSelector,
blog => blog.get('value')
);
// selectors/__tests__/blog-test.js
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';
import dirtyChai from 'dirty-chai';
chai.use(sinonChai);
chai.use(dirtyChai);
import { fromJS } from 'immutable';
describe('blog Selector', () => {
it('should exists', () => {
const blog = require('../blog');
expect(blog).to.be.ok();
});
it('should test the blogMapSelector selector', () => {
const blog = require('../blog');
expect(blog.blogMapSelector({
blog: fromJS({
value: 0,
}),
})).to.equal(0);
});
});
And update all folder index.js
accordingly.
yo retax:component BlogPost
The first argument of this generator is the component name (Upper camel case). It is required.
The generator will prompt for:
- Should the component be pure (ie: use pure-render-decorator)
The previous command will generate:
// components/BlogPost/BlogPost.js
import React, { Component } from 'react';
import pureRender from 'pure-render-decorator';
@pureRender
export default class BlogPost extends Component {
static propTypes = {
};
render() {
return (
<div className="flex layout vertical">
Yay!
</div>
);
}
}
// components/BlogPost/__tests__/BlogPost-test.js
import chai, { expect } from 'chai';
import dirtyChai from 'dirty-chai';
chai.use(dirtyChai);
import { shallow } from 'enzyme';
import React from 'react';
describe('BlogPost', () => {
it('should exists', () => {
const BlogPost = require('../BlogPost');
const wrapper = shallow((
<BlogPost />
));
expect(wrapper).to.have.length(1);
});
it('should render inner components', () => {
const BlogPost = require('../BlogPost');
const wrapper = shallow((
<BlogPost />
));
expect(wrapper.find('div')).to.have.length(1);
});
});
And update all folder index.js
accordingly.
yo retax:route blog
The first argument of this generator is the route name (camel case). It is required.
The generator will prompt for:
- The url of the route (default
/lowercase(routeName)
) - Should this route be asynchronous dynamic-routing
- The require access level to access this route (public, user, admin) (this is defined in here in retax-seed)
- Should this route have child routes
- Should this route have an index route
- Should this route be pure (ie: use pure-render-decorator)
- Should this route use redux
- Should this route use reselect
It will generate a lot of files in the folder: routes/blog
.
A route folder has the following structure:
index.js
: the react-router route definitioncontainer/{page,index}
: these are container components (smart components that connect to redux store) for the page and the index page.component/{page,index}
: dumb components called by the smart component respectively. These components should use only presentationnal components from the foldersrc/components
selector/{page,index}
: reselect selectors for the smart component.
This generator should not be used in a retax-seed project. It should be called in am empty folder.
It generates a standalone component that could be exported to github/npm. See react-component-seed.
yo retax:seed-component BlogPost
The first argument of this generator is the component name (Upper camel case). It is required.
The generator will prompt for:
- The repo url
- The author
MIT © retaxJS