Petr Stefan 8 years ago
commit 0ce9073430

@ -2,14 +2,14 @@
## Description
The *WebApp* is the default user interface of the ReCodEx project. It is a website which users access through their web browsers.
The *WebApp* is the default user interface of the ReCodEx project. It is a Single Page Application (SPA) which users access through their web browsers.
This user interface allows students to join *groups* corresponding to their school classes, submit new *solutions* and see the results as soon as the solution is evaluated by the backend.
Teachers can manage their *groups* by adding and removing *students*, assigning *exercises* and examining the *automatically evaluated solutions* of their students and their total score gained throughout the semester.
The actions performed by the user are sent to the *API server* over the HTTPS protocol and the web application does not modify the database or access files on ther server directly and all the inputs sent
from the web application are additionally *validated* on the *API server*.
The *WebApp* is written in *ECMAScript* (often refered to as JavaScript) and HTML5. The [React](https://facebook.github.io/react) library developed by Facebook is used to manage the user interface and the [Redux](http://redux.js.org/) framework
The *WebApp* is written in *ECMAScript* (often referred to as JavaScript) and HTML5. The [React](https://facebook.github.io/react) library developed by Facebook is used to manage the user interface and the [Redux](http://redux.js.org/) framework
created by Dan Abramov is used to manage the application state. Both of these frameworks are industry standards used in production by many companies worldwide. Many other smaller libraries and components are used, notably the [Immutable.js](https://facebook.github.io/immutable-js) and [Format.js](http://formatjs.io/) by Yahoo via *redact-intl* integration library.
### Multiplatform approach
@ -19,59 +19,62 @@ This application is designed and implemented in a way which should be suitable f
## Architecture
The whole project is written using the next generation of JavaScript refered to as *ECMAScript 6* (also known as *ES6*, *ES.next*, or *Harmony*). Since not all the features introduced in this standard are implemented in today's modern web browsers (like classes and spread operators) and hardly any are implemented in older versions of web browsers which are currently still in use, the source code is transpiled into the older standard *ES5* using [Babel.js](https://babeljs.io/) transpiler and bundled into a single script file using the [webpack](https://webpack.github.io/) moudle bundler. The need for a transpiler also arises from the usage of the *JSX* syntax for declaring React components. To read more about these these tools and their usage please refer to the [installation section](#Installation).
The whole project is written using the next generation of JavaScript referred to as *ECMAScript 6* (also known as *ES6*, *ES.next*, or *Harmony*). Since not all the features introduced in this standard are implemented in today's modern web browsers (like classes and spread operators) and hardly any are implemented in older versions of web browsers which are currently still in use, the source code is transpiled into the older standard *ES5* using [Babel.js](https://babeljs.io/) transpiler and bundled into a single script file using the [webpack](https://webpack.github.io/) moudle bundler. The need for a transpiler also arises from the usage of the *JSX* syntax for declaring React components. To read more about these these tools and their usage please refer to the [installation section](#Installation). The whole bundling process takes place at deployment and is not repeated afterwards.
### Declarative UI components
The *React* UI framework enforces the use of reusable components. These components receive input data through so called *props* and can hold its own internal state. Components can instantiate each other with specific *props* and create a complex component tree throughout composition.
The implementation of *WebApp* is split across more than a hundred small components which are composed together. There are two basic types of React components - presentational and stateful components.
React automatically re-renderes the components' subtrees whenever some *props* or component's inner *state* changes. To prevent unnecessary renderings and especially slow *DOM* manipulations React uses sophisticated diffing algorithms and minimizes the number of the underlying DOM manipulations like inserting or deleting DOM nodes.
- **Presentational components** are in fact pure functions which yield their output based solely on the input *props* and application's *context* (e. g. current language has effect on URLs). These components are preferred and should be as simple as possible. These components are placed in the subfolders of `src/components` directory.
This allows the components to be written declaratively and makes them highly readable and truly reusable.
- **Stateful components** are *connected* to the *redux store* and yield information based on the either the *props* and *context*, but also on the current state of the application. These components are more complicated and often make use of React's components' life cycle methods. *Stateful components* are often referred to as *containers* and the source code files are placed in a separate directories called `src/containers` and `src/pages`.
#### Presentational and stateful components
- There is no technical difference between *containers* and *pages*. *Pages* are used as "root" components for different pages and are registered in the app's [router](https://github.com/ReactTraining/react-router).
There are two basic types of React components - presentational and stateful components.
As was mentioned earlier in the text, there is over a hundred components in the whole application and most of them are very simple. Some of the most important and widely used components and described in the following paragraphs.
- **Presentational components** are in fact pure functions which yield their output based solely on the input *props* and application's *context* (i.e. current language). These components are prefered and should be as simple as possible.
#### `PageContent`
- **Stateful components** are *connected* to the *redux store* and yield information based on the either the *props* and *context*, but also on the current state of the application. These components are more complicated and often make use of React's components' lifecycle methods. *Stateful components* are often refered to as *containers* and the source code files are placed in a separate directories called `src/containers` and `src/pages`.
#### `ResourceRenderer`
- There is no technical difference between *containers* and *pages*. *Pages* are used as "root" components for different pages and are registered in the app's router.
#### `Page`
### The Redux architecture and state management
#### Bootstrap and AdminLTE theme
*Redux* is an architecture and a library of a predictible state container. The idea comes from the *Flux* architecture which was published by Facebook alongside *React*. This architecture introduces a so-called *unidirectional data flow*:
The UI of the application is built using the stylesheets from the [Bootstrap framework](http://getbootstrap.com/) from Twitter and the [AdminLTE](https://almsaeedstudio.com/) theme from Abdullah Almsaeed. None of the JavaScript plugins from these libraries is used.
- *User* creates **actions** which are then processed by the *dispatcher*
- **Dispatcher** processes *actions* and updates the application state stored in **stores**
- **Stores** which are updated according to the *actions* inform all *components* listening for changes
- **Components** display the new state to the user
- **User** decides on his/her next actions according to the updated information displayed by the *components*
A package [react-bootstrap](https://react-bootstrap.github.io/) is used. Components sepcific to the *AdminLTE* theme are implemented and stored in the `src/components/AdminLTE` folder and its subfolders.
*Redux* simplifies this architecture by allowing only a single *store* and introducing a special pure function called *reducer* which deterministically transforms *old* state to a *new* state according to the given *action*. The *state* of app is represented by one plain javascript object (a tree) inside the *store*. *Reducer* is commonly a function composed by many simple functions which handle only a small subtree of the whole state.
#### Forms
### Redux middleware and helpers
- @todo: apiMiddleware
- @todo: resourceManager
## Installation
Web application requires NodeJS server as its runtime environment. This runtime is needed for executing JavaScript code on server and allowing for example prerender parts of pages before sending to clients, so the final rendering in browsers is a lot quicker. But some functionality is better in other full fledged web servers like Apache or Nginx, so common practice is to use tandem of both. NodeJS takes care of basic functionality of the app while the other server (Apache) is set as reverse proxy and providing additional functionality like SSL encryption, loadbalancing or caching of static files. The recommended setup contains both NodeJS and one of Apache and Nginx web servers for the reasons discussed above.
Web application requires [NodeJS](https://nodejs.org/en/) server as its runtime environment. This runtime is needed for executing JavaScript code on server and sending the pre-render parts of pages to clients, so the final rendering in browsers is a lot quicker and the page is accessible to search engines for indexing.
But some functionality is better in other full fledged web servers like *Apache* or *Nginx*, so the common practice is to use a tandem of both. *NodeJS* takes care of basic functionality of the app while the other server (Apache) is set as reverse proxy and providing additional functionality like SSL encryption, load balancing or caching of static files. The recommended setup contains both NodeJS and one of Apache and Nginx web servers for the reasons discussed above.
Stable versions of 4th and 6th series of NodeJS server are sufficient, using at least 6th series is highly recommended. Please check the most recent version of the packages in your distribution's repositories, there is often too outdated one. However there are some third party repositories for all main linux distributions.
Stable versions of 4th and 6th series of NodeJS server are sufficient, using at least 6th series is highly recommended. Please check the most recent version of the packages in your distribution's repositories, there are often outdated ones. However, there are some third party repositories for all main Linux distributions.
The app depends on several libraries and components, all of them are listed in `package.json` file in source repository. For managing dependencies is used node package manager (`npm`), which can come with NodeJS installation otherwise can be installed separately. To fetch and install all dependencies run:
```
$ npm install
```
To easy production usage there is additional package for managing NodeJS processes, `pm2`. This tool can run your application as a daemon, monitor occupied resources, gather logs and provide simple console interface for managing app's state. To install it globally into your system run:
For easy production usage there is an additional package for managing NodeJS processes, `pm2`. This tool can run your application as a daemon, monitor occupied resources, gather logs and provide simple console interface for managing app's state. To install it globally into your system run:
```
# npm install pm2 -g
```
## Configuration and usage
The application can be run in two modes, development and production. Development mode uses only client rendering and tracks code changes with rebuilds of the application in real time. In production mode the compilation (transpile to _ES5_ standard and bundle into single file using webpack) has to be done separately prior running. The scripts for compilation are provided as additional commands for `npm`.
The application can be run in two modes, development and production. Development mode uses only client rendering and tracks code changes with rebuilds of the application in real time. In production mode the compilation (transpile to _ES5_ standard using *Babel* and bundle into single file using *webpack*) has to be done separately prior to running. The scripts for compilation are provided as additional `npm` commands.
- Development mode can be use for local testing of the app. This mode uses webpack dev server, so all code runs on a client, there is no server side rendering available. Starting is simple command, default address is http://localhost:8080.
```
@ -80,7 +83,7 @@ $ npm run dev
- Production mode is mostly used on the servers. It provides all features such as server side rendering. This can be run via:
```
$ npm run build
$ npm run start
$ npm start
```
Both modes can be configured to use different ports or set base address of used API server. This can be configured in `.env` file in root of the repository. There is `.env-sample` file which can be just copied and altered.
@ -108,4 +111,3 @@ NODE_ENV=production
API_BASE=https://recodex.projekty.ms.mff.cuni.cz:4000/v1
PORT=8080
```

Loading…
Cancel
Save