Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 7 - Nasazení na server

V minulém díle, Uživatelské rozhraní, jsem ukazoval výrobu user interface pro hru.

V tomto díle ukáži nasazovaní celého projektu na server.

Webová hra - WebGL a BabylonJS - 3D webová hra

Nasazování na server

První polovinu tutoriálu jsem vyráběl statické JavaScriptové soubory. Ty se dají lehce nakopírovat na server např. pomocí FTP. Nevýhodou tohoto postupu je, že po každé změně musím aktualizované soubory překopírovat ručně. V průběhu kopírování nastává doba, kdy jsou na serveru smíchané soubory ze staré a nové verze. A pokud kopírování selže, může se produkční verze rozbít úplně.

Potom jsem ukázal, jaké jsou nevýhody čistého JavaScriptu a přešel jsem na TypeScript. Teď už nemohu soubory překopírovat přímo. Mohu si ale nechat vytvořit transpilovaný JavaScriptový soubor a dále postupovat úplně stejně:

npm build

To, co se mi vytvoří do složky build, nakopíruju na server.

Tento postup je OK, pokud budu aktualizovat aplikaci několikrát ročně, navštěvuje ji málo lidí a není potřebná příliš velká spolehlivost. Pokud bych chtěl aktualizovat častěji např. každý den či týden, bylo by dobré celý postup automatizovat.

Continuous integration

Mnoho hostingů má podporu continuous integration. To je proces, který převede zdrojové kódy aplikace na stav, kdy je nová verze nasazená pro uživatele. Pokud máš vlastní (nebo virtuální) server můžeš si nainstalovat některý z continuous integration nástrojů. Jedním z nich je např. Strider.

Impulzem pro nasazení nové verze může být tlačítko v administrace, příkaz v konzoli nebo nový commit v git repozitáři (obvykle ve větvi production). Potom se spustí několik kroků:

  1. Vytvoří se nějaké oddělené místo (např. nová složka) pro novou verzi aplikace.
  2. Do tohoto místa se naklonuje git repozitář na commitu, který má být nasazen.
  3. Spustí se npm install. To nainstaluje všechny závyslosti, které máme nastavené v package.json.
  4. Spustí se npm build. To vytvoří ze zdrojových souborů a nainstalovaných závyslostí jeden produkční JavaScriptový soubor.
  5. Spustí se testy. (Popíšu dále v článku.)
  6. Spustí se samotná aplikace. Zde si liší jednoduché hostingy (např. GitHub Pages), které prostě přes https odesílají vytvořené produkční soubory a opravdové node.js hostingy (např. Heroku), které spustí přednastavený node.js skript.
  7. Stará verze se přepne se za novou.

My použijeme výše zmíněné GitHub Pages. Nejdříve nainstalujeme nástroj, který umí s GitHub Pages pracovat:

npm install gh-pages --dev

Do package.json přidáme url hry na GitHub pages pod hodnotu homepage (ta je ve formátu https://[uživa­tel].github.i­o/[projekt]/). A do scripts přidáme predeploy a deploy.

{
  "name": "web-game",
  "homepage": "https://webappgames.github.io/web-game/",
  "dependencies": {
    //...
  },
  "devDependencies": {
    "gh-pages": "^1.0.0",
    //...
  },
  "scripts": {
    //...
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build"
  }
}

Nyní stačí v administraci GitHubu nastavit GitHub Pages na větev "gh-pages".

Testy

Pokud commitnu něco chybného, proces continuous integration zachová původní verzi a mě pouze upozorní. Tím se vyhnu nasazení vadné verze pro uživatele či znefunkčnění celé webové stránky. Existuje několik nejběžnějších druhů chyb:

  • Chybu v syntaxi (např. chybějící závorku) odhalí TypeScript transpilátor.
  • Chybu v typování odhalí TypeScript transpilátor. Pokud bychom nepoužívali TypeScript, tento druh chyb by se projevil až za běhu, což by mohlo mít mnohem horší následky.
  • Chyba za běhu (např. komponenta vyhodí chybu při rendrování).
  • Logická chyba (např. akce změní stav aplikace tak, jak jsme neočekávali).

Chyby v syntaxi a typování jsou otravné, odhalí se ale ještě před nasazením programu na produkci. Logické chyby a chyby za běhu se odhalují mnohem hůře. Mít chybu v běžící aplikaci je nepříjemné a často velmi drahé. Proto se píší automatizované testy, které odhalují chyby ještě před nasazením aplikace pro uživatele. Jak správně psát testy je velmi složitá disciplína. Já pro hru napíši několik jednoduchých testů:

components.test.ts

import * as React from "react";
import * as ReactDOM from "react-dom";
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import * as injectTapEventPlugin from 'react-tap-event-plugin';
import {createStore} from 'redux';
import { Provider } from 'react-redux';
import {stateReducer} from '../redux-reducers/index';
import Root from "../react-components/root";
import Heading from "../react-components/heading";
import BlockColor from "../react-components/block-color";
injectTapEventPlugin();

const store = createStore(stateReducer, {});

it('Root renders without crashing', () => {
    const div = document.createElement('div');
    ReactDOM.render(
        <Provider store={store}>
            <MuiThemeProvider>
                <Root/>
            </MuiThemeProvider>
        </Provider>
        , div);
});

it('Heading renders without crashing', () => {
    const div = document.createElement('div');
    ReactDOM.render(
        <Provider store={store}>
            <MuiThemeProvider>
                <Heading/>
            </MuiThemeProvider>
        </Provider>
        , div);
});

it('BlockColor renders without crashing', () => {
    const div = document.createElement('div');
    ReactDOM.render(
        <Provider store={store}>
            <MuiThemeProvider>
                <BlockColor/>
            </MuiThemeProvider>
        </Provider>
        , div);
});

state.test.ts

import {createStore} from 'redux';
import {stateReducer} from '../redux-reducers/index';

const store = createStore(stateReducer, {});

describe('blocks', () => {

    it('should increase number of blocks after dispatch BLOCK_ADD', () => {
        const oldState = store.getState();
        store.dispatch({type:'BLOCK_ADD',newBlock:{}});
        const newState = store.getState();
        expect(newState.blocks.length).toBe(oldState.blocks.length+1);
    });

    it('should descrease number of blocks after dispatch BLOCK_DELETE', () => {
        const oldState = store.getState();
        store.dispatch({type:'BLOCK_DELETE',blockId:oldState.blocks[0].id});
        const newState = store.getState();
        expect(newState.blocks.length).toBe(oldState.blocks.length-1);
    });

});

describe('ui', () => {

    it('should toggle drawer after dispatch UI_DRAWER_TOGGLE', () => {
        const oldState = store.getState();
        store.dispatch({type:'UI_DRAWER_TOGGLE'});
        const newState = store.getState();
        expect(newState.ui.drawer).toBe(!oldState.ui.drawer);
    });

    it('should change color after dispatch UI_COLOR_SET', () => {
        store.dispatch({type:'UI_COLOR_SET',value:'#123456'});
        const newState = store.getState();
        expect(newState.ui.color).toBe('#123456');
    });

});

Dokončenou hru si můžeš stáhnout pod článkem, nebo jít do Git repozitáře, kde najdeš nejnovější verzi zdrojových kódů. Nebo si ji rovnou můžeš vyzkoušet na webappgames.git­hub.io/web-game.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 77x (9.89 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
Uživatelské rozhraní
Všechny články v sekci
WebGL a BabylonJS - 3D webová hra
Článek pro vás napsal Pavol Hejný
Avatar
Uživatelské hodnocení:
1 hlasů
/^(web )?(app )?developer$/
Aktivity