create-spa

A way to initial our spa project quickly, base on templates [vue, react, angular]. ##### How to use ``` - spa - webpack / vite / rollup - vue / react / angular - coffeescript ? - pug ? - jsex ? - theme support ?


Keywords
cli, spa, web, vue, react, angular
License
ISC
Install
npm install create-spa@1.0.5

Documentation

(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

Authors

License

This project is licensed under the MIT License.

Examples

Toreator - Single-page application with GraphQL proxy for searching IP addresses in TOR network.