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.
208 lines
9.2 KiB
208 lines
9.2 KiB
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 a 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 is our gateway, it uses an `AltoRouter` that dispatches the request's process 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`
|
|
```php
|
|
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 using a specific `render(any)` function.
|
|
This function __must__ figure in the imported view file in order to work.
|
|
|
|
```html
|
|
<!--
|
|
here's the magic.
|
|
imports the given view URL, and assume that the view exports a function named `render` that
|
|
takes exactly one object argument.
|
|
If the imported file does not export a function with signature `render(arguments: any)`,
|
|
the call wont work thus the view will not be displayed
|
|
-->
|
|
<script type="module">
|
|
import {render} from "<?= asset($url) ?>"
|
|
render(<?= 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).
|
|
You can see that the react view is rendered using a `render` function.
|
|
This function **must figure in the view's file, and be exported**.
|
|
We'll talk about an important coding convention with react views that this script block requires later.
|
|
|
|
But now let's talk about our server profiles !
|
|
## 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
|
|
```php
|
|
const FRONT_URL_CONSTANT = "http://localhost:5173";
|
|
|
|
function _asset(string $assetURI): string {
|
|
return FRONT_URL_CONSTANT . "/" . $assetURI;
|
|
}
|
|
```
|
|
The simplest profile, simply redirect all assets to the development server
|
|
|
|
### Production profile
|
|
Before the CD 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 :
|
|
|
|
```php
|
|
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.
|
|
```php
|
|
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);
|
|
}
|
|
```
|
|
|
|
## React views conventions.
|
|
Conventions regarding our react views __must be respected in order to be renderable__.
|
|
|
|
### The `render(any)` function
|
|
__any react view file__ should __export__ a function with signature `render(arguments: any)`, which responsibility is to render the view.
|
|
The `arguments` parameter is used to pass data to the react component.
|
|
|
|
If you take a look at the `front/views/SampleForm.tsx` view, here's the definition of its render function :
|
|
|
|
```ts
|
|
/// Here's the definition of the view
|
|
function SampleForm() {
|
|
... react jsx code here
|
|
}
|
|
|
|
// the `SampleForm` does not inputs arguments but the parameter IS STILL REQUIRED
|
|
export function render(args: any) {
|
|
const root = ReactDOM.createRoot(
|
|
document.getElementById('root') as HTMLElement
|
|
);
|
|
root.render(
|
|
<React.StrictMode>
|
|
<SampleForm /> //here's our view component
|
|
</React.StrictMode>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Pass arguments to our react views
|
|
We'll take the example of the view in charge of displaying the SimpleForm's fields values.
|
|
First, let's take a look at its React Component definition :
|
|
|
|
```ts
|
|
function DisplayResults({password, username}: any) {
|
|
return (
|
|
<div>
|
|
<p>username: {username}</p> //arguments are used heres
|
|
<p>password: {password}</p>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
The components takes two arguments, an `username` and a `password` string.
|
|
|
|
Now, let's take a look at its `render` function :
|
|
```ts
|
|
export function render(args: any) {
|
|
const root = ReactDOM.createRoot(
|
|
document.getElementById('root') as HTMLElement
|
|
);
|
|
root.render(
|
|
<React.StrictMode>
|
|
<DisplayResults username={args.name} password={args.password} />
|
|
</React.StrictMode>
|
|
);
|
|
}
|
|
```
|
|
especially this line:
|
|
```
|
|
<DisplayResults username={args.name} password={args.password} />
|
|
```
|
|
`DisplayResults` is the name of our React Component (the function).
|
|
To pass arguments to the `DisplayResults` function, we use the syntax `<function parameter name>={value}`. (somewhat like regular html/xml components).
|
|
Use the render's function `args` parameter to access to the php's array values.
|