8.3 KiB
Web application
Description
The WebApp is the default user interface of the ReCodEx project. It is a website 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 library developed by Facebook is used to manage the user interface and the Redux 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 and Format.js by Yahoo via redact-intl integration library.
Multiplatform approach
Since the runtime environment of WebApp is user's web browser it does not need any installation on enduser's device and does not require any particular platform or non-standard software installed on user's device. This application is designed and implemented in a way which should be suitable for modern web browsers on both desktop and mobile devices.
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 transpiler and bundled into a single script file using the webpack 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.
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 it's own internal state. Components can instantiate each other with specific props and create a complex component tree throughout composition.
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.
This allows the components to be written declaratively and makes them highly readable and truly reusable.
Presentational and stateful components
There are two basic types of React components - presentational and stateful components.
-
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.
-
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
andsrc/pages
.- 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.
The Redux architecture and state management
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:
- 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
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.
Installation
Web application requires NodeJS server as its runtime environment. Stable versions of 4th and 6th series are sufficient, using at least 6th series is highly recommended. Please check version of NodeJS in your distribution's repositories, there is often too old one. However there are some third party repositories for all main linux systems.
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:
# npm install pm2 -g
For production it's also recommended to use full fledged web server like Apache or Nginx as a proxy providing HTTPS encryption and caching of static files.
Configuration and usage
The application can be run in two modes, development and production.
- 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.
$ npm run dev
- Production mode us 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
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.
The production mode can be run also as a demon controled by pm2
tool. First the web application has to be built and then the server javascript file can run as a daemon.
$ npm run build
$ pm2 start bin/server.js
The pm2
tool has several options, most notably status, stop, restart and logs. Further description is available on project website.
Configurable items
Description of configurable options. Bold are required values, optional ones are in italics.
- NODE_ENV -- mode of the server
- API_BASE -- base address of API server, including port and API version
- PORT -- port where the app is listening
- WEBPACK_DEV_SERVER_PORT -- port for webpack dev server when running in development mode. Default one is 8081, this option might be useful when this port is necessary for some other service.
Example configuration file
NODE_ENV=production
API_BASE=https://recodex.projekty.ms.mff.cuni.cz:4000/v1
PORT=8080