create-sbspa
v1.0.0-alpha.2
Published
Scripts for creating Single-page application with React and Spring Boot
Downloads
5
Maintainers
Readme
(React-GraphQL-Spring-boot) Single-page generator
Single-page generator with React frontend and Spring-boot backend supports options to separately generate parts of an application. It uses plop to generate source code from templates. The generator provides boilerplate for creating PWA applications.
This boilerplate provides an array of features that make it different from other frameworks:
- Webpack configuration - development and production build
- Jest, Tslint and TypeScript configuration
- DockerFile for build automation
- Redux, Saga configuration - async Saga and Reducer injection
- GraphQL configuration
- Checkstyle and FindBugs configuration
- Gradle build configuration for both frontend and backend
- Interactive generator console with variety of options
- Iterative updates with "modify" option
- PWA configuration
- Sample components and examples of usage
- Plug&Play configuration
Tool is build for easy generation of single-page applications with usage of best practices in web development. Provides better maintenance, testing, cooperation and deployment.
Getting Started
Install yarn.
npm install -g yarn
Install create-sbspa tool.
npm install -g create-sbspa
Prerequisites
Generating
After installing create-sbspa tool run
create-sbspa
Options:
- All - Generates Frontend and Backend with Docker, GraphQL configuration.
- Frontend - Generates Frontend.
- Backend - Generates Backend without GraphQL configuration.
- Docker configuration - Generates Docker configuration for Frontend and Backend.
- GraphQL configuration - Generates GraphQL configuration with example
Build and Run application
Application uses gradle automation build and deployment tool. Project modules are defined in settings.gradle and in build.gradle files.
Frontend (in <frontend_folder> folder)
Build application DEV
yarn install && yarn build:dev
Build application PROD
yarn install && yarn build
Gradle:
gradle build
Run application in DEV mode
yarn start:dev
Run application in PROD mode
yarn start
Gradle:
gradle runWeb
Available at localhost:3000.
Backend (in <backend_folder> folder)
Build application
gradle build
Run application
gradle runApi
Available at localhost:8080.
GraphQL console is available at localhost:8080/graphiql.
Running the tests
Frontend
Run tests with yarn
yarn run test
Run tests on changed files
yarn run test:changed
Run tests with coverage
yarn run test:coverage
Update tests
yarn run test:update
Backend
Run checkstyle (build/reports/checkstyle.html)
gradle checkstyleMain
Run findbugs (build/reports/findbugs.html)
gradle findbugsMain
Coding style tests
- Coding styles for Backend are defined in <backend_folder>/config
- Coding styles for Frontend are defined in <fronted_folder>/tslint.json
Check tests for backend and frontend for more information.
Hooks
Frontend application uses prepush and precommit hooks.
- Prepush is invoked before push to central repository with command:
yarn run test:coverage
Coverage threshold can be set in jest.config.js.
- Precommit is invoked before commit. Calls lint (static analyzer) to check coding styles.
yarn run lint-staged
Static analyzer can be modified in tslint.json.
Deployment
Deploy frontend or backend with provided docker configuration. In root frontend or backend directory run
docker build . -t <name>:<version>
Modules
Root container .tsx (<frontend_folder>/src/modules)
Main application class with Async route definition. Each page (container/component) can be asynchronously loaded with support of Webpack chunks.
Route definition: SamplePage route with root component in "./shared/components/ReplaceMeComponent".
Important: path is made from Router.tsx component.
export const routes = {
samplePage: () =>
// @ts-ignore
lazy(() =>
import(/* webpackChunkName: "SamplePage" */ "./shared/components/ReplaceMeComponent"),
),
};
Routes are evaluated in Router.tsx class (modules/shared/components/Router.tsx).
You can freely change loading component and other properties of the DynamicRouter component.
Redux and Sagas
Generator provides support for redux and sagas with async injection feature.
Store
Store is defined in common/store/store.tsx. It containes store setup with reducers and sagas. Also includes Redux devtools extension for development.
You can add your reducer directly to store or inject it asynchronously.
Adding directly to store
Create your reducer myReducer.tsx
import {combineActions, handleActions} from "redux-actions";
const defaultState = "";
const reducer = handleActions(
{
["MY_REDUCER_ACTION"]:
(state, {payload: {value}}) => value,
},
defaultState,
);
export default reducer;
Add it to reducerRegistry reducerRegistry.tsx
import myReducer from "./reducers/myReducer"
...
public getReducers() {
return {
myReducer: myReducer,
...this._reducers};
}
...
Adding asynchronously to store
Reducers and sagas can by injected asynchronously with implemented helper function in common/store/helpers.tsx.
Example usage of async reducer and saga
Create an app container
import {compose} from "redux";
import * as React from "react";
import {connect} from "react-redux";
import reducer from "./reducers/myReducer";
import {withInjectedReducersAndSagas} from "../../common/store/helpers";
import saga from "./sagas/mySaga";
import {myReducerAction} from "./actions/myActions";
const ExampleContainer = ({value, myReducerAction}) =><div onClick={()=>myReducerAction("click")}>{value}My container!</div>
export default compose(
withInjectedReducersAndSagas({
reducers:[
{
key: "MY_REDUCER",
value: reducer
}
],
sagas:[
{
key: "MY_SAGA",
value: saga
}
]
}),
// after async injection u can easily connect to store
connect(
(state)=>({
value: state["MY_REDUCER"].value
}),
(dispatch)=>({
myReducerAction: value => dispatch(myReducerAction(value))
})
)
)(ExampleContainer);
Reducer definition ./reducers/myReducer
import {combineActions, handleActions} from "redux-actions";
const defaultState = "";
const reducer = handleActions(
{
["MY_REDUCER/MY_REDUCER_ACTION"]:
(state, {payload: {value}}) => value,
},
defaultState,
);
export default reducer;
Saga definition ./sagas/mySaga
import {takeEvery} from "redux-saga/effects";
const watchAction = function* watchAction() {
yield;
};
function* rootSaga() {
yield takeEvery("MY_REDUCER/MY_REDUCER_ACTION", watchAction);
}
export default rootSaga;
Actions definition ./actions/myActions
export const {
myReducer: {myReducerAction},
} = createActions({
["MY_REDUCER"]: {
[`MY_REDUCER_ACTION`]: value => ({value}),
},
});
GraphQL modules (<backend_folder>/)
Resolvers (/resolver)
Resolvers are used for postprocessing of model fields. For blog we can acquire data, which is postprocessing of author object.
DAO (/dao)
Each DAO object contains functions called from Query.
Schema (/resources/graphql/*.graphqls)
Schema definition with supporoted queries.
Built With
- React - The web framework used
- GraphQL - The api framework used
- Spring-boot - The backend framework used
Authors
- Norbert Durcansky - Initial work - norbertdurcansk
License
This project is licensed under the MIT License.
Examples
Toreator - Single-page application with GraphQL proxy for searching IP addresses in TOR network.