You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/Documentation/how-to-dev.md

7.1 KiB

THIS FILE IS DEPRECATED

See #107 for more details


This documentation file explains how to start a development server on your machine, and how it works under the hood.

How to run the project on my local computer

  1. Use phpstorm to run a local php server:
  • Go to configuration > add new configuration
  • Select "PHP Built-in Web Server", then enter options as follow: - port 8080 - name the configuration "RunServer" to be more explicit - place the "Document Root" in /public - host is localhost
  • Click apply, OK
  • Now run it.

If you go to http://localhost:8080 you'll see a blank page.
This is expected ! On your browser, open inspection tab (ctrl+shift+i) go to network and refresh the page.

We can see that the browser requested the SampleForm.tsx react view (located in /front/views), but the server could not find it.
But, on what server was it requested ?
Remember that the localhost:8080 is a php server, and thus not able to handle requests about our react / typescript files.
If we take a look at the request, we'll see that the url does not targets localhost:8080, but localhost:5173.

localhost:5173 is the react development server, it is able to serve our react front view files.
Let's run the react development server.
It is as simple as running npm start in a new terminal (be sure to run it in the repository's directory).

You should see something like this, it says that the server was opened on port 5173, thats our react development server !
Now refresh your page, you should now see all request being fulfilled and a form appearing !

Caution: NEVER directly connect on the localhost:5173 node development server, always pass through the php (localhost:8080) server.

How it works

I'm glad you are interested in how that stuff works, it's a bit tricky, lets go.
If you look at our index.php (located in /public folder), you'll see that it define our routes, it uses an AltoRouter then delegates the request's action processing to a controller.
We can see that there are two registered routes, the GET:/ (that then calls SampleFormController#displayForm()) and POST:/result (that calls SampleFormController#displayResults()).
Implementation of those two methods are very simple: there is no verification to make nor model to control, thus they directly sends the view back to the client.

here's the implementation of the SampleFormController

require_once "react-display.php";
class SampleFormController {
    public function displayForm() {
        send_react_front("views/SampleForm.tsx", []);
    }

    public function displayResults(array $request) {
        send_react_front("views/DisplayResults.tsx", $request);
    }
}

As our views are now done using react (and defined under the front/views folder), we need to use the send_react_front($viewURI, $viewArguments) php function (located in the src/react-render.php file) to render a react view.

If you look at the send_react_front($viewURI, $viewArguments) function, you'll see that is simply loads the file src/react-display-file.php with given arguments.
The file is a simple html5 template with a <script> block in the <body> section.
The script block imports the requested view and will render it.
The view entry is a function, named in PascalCase, which must be be exported by default (export default function MyReactView(args: {..})).

<!--
here's the magic.
imports the given view URL, and assume that the view exports a function named `Component`.
see ViewRenderer.tsx::renderView for more info
-->
<script type="module">
    import {renderView} from "<?= asset("ViewRenderer.tsx") ?>"
    import Component from "<?= asset($url) ?>"
    renderView(Component, <?= json_encode($arguments) ?>)
</script>

here's how it renders if you do a request to http://localhost:8080/.


The index.php's router says that for a GET on the / url, we call the SampleFormController#displayForm method.
This method then uses the send_react_front, to render the views/SampleForm.tsx react element, with no arguments (an empty array).
The view file must export by default its react function component.

Server Profiles

If you go on the staging server, you'll see that, for the exact same request equivalent, the generated src/render-display-file file changes :
(we can also see that much less files are downloaded than with our localhost aka development server).

Remember that react components and typescript files needs to be transpiled to javascript before being executable by a browser.
The generated file no longer requests the view to a localhost:5173 or a maxou.dev:5173 server, now our react components are directly served by the same server, as they have been pre-compiled by our CI (see /ci/.drone.yml and /ci/build_react.msh) into valid js files that can directly be send to the browser.
If you go back to our index.php file, you'll see that it requires a ../config.php file, if you open it, you'll see that it defines the asset(string $uri) function that is used by the src/react-display-file.php, in the <script> block we talked earlier.

By default, the /config.php file uses the dev-config-profile.php profile, the file is replaced with prod-config-file.php by the CI when deploying to the staging server (see the pipeline "prepare php" step in /ci/.drone.yml)

The two profiles declares an _asset(string $uri) function, used by the /config.php::asset method, but with different implementations :

Development profile

$hostname = getHostName();
$front_url = "http://$hostname:5173";

function _asset(string $assetURI): string {
    global $front_url;
    return $front_url . "/" . $assetURI;
}

The simplest profile, simply redirect all assets to the development server

Production profile

Before the CD workflow step deploys the generated files to the server, it generates a /views-mappings.php file that will map the react views file names to their compiled javascript files :

const ASSETS = [
    // react / typescript path (relative to /front) => its compiled js file name.
    'views/SampleForm.tsx' => 'front/views/SampleForm.tsx-82fdeb9a.js',
    'views/DisplayResults.tsx' => 'front/views/DisplayResults.tsx-ed098cf4.js',
    ... // other files that does not have to be directly used by the `send_react_front()` function
];

The _asset function will then get the right javascript for the given typescript file.

require "../views-mappings.php";

function _asset(string $assetURI): string {
    // use index.php's base path
    global $basePath;
    // If the asset uri does not figure in the available assets array,
    // fallback to the uri itself.
    return $basePath . "/" . (ASSETS[$assetURI] ?? $assetURI);
}