This commit is contained in:
Tomas Husak 2021-05-19 10:38:05 +02:00
Родитель 6dec8e8d14
Коммит be4611fe92
6 изменённых файлов: 71 добавлений и 68 удалений

Просмотреть файл

@ -154,8 +154,8 @@ Then a programmer avoids to use the workaround defined above.
\subsection{Interoperability}
The last feature to discuss in this section is interoperability between Javascript and PHP.
As we mentioned, Blazor allows calling Javascript functions from C\# \cite{online:interop1} and vice-versa \cite{online:interop2}.
We can utilize a Blazor service,\texttt{IJSRuntime}, injected by the dispatcher, to call Javascript functions.
Blazor allows calling Javascript functions from C\# \cite{online:interop1} and vice-versa \cite{online:interop2}.
Thus, a Blazor service,\texttt{IJSRuntime} injected by the dispatcher, can be utilized to call Javascript functions.
The service offers a specialized API for that.
Calling PHP from Javascript is more complex.
Peachpie enables calling PHP function by \texttt{Call} method of \texttt{Context}.
@ -167,37 +167,37 @@ These conditions lead us to create a new Peachpie context,\texttt{BlazorContext}
The context requests the mentioned services provided by the dispatcher and sets the reference by calling predefined code in \texttt{Peachpie.Blazor.js}.
The context will be the Peachpie context of the component.
Thus, it enables to call PHP methods defined in this context from Javascript by using the reference.
The advantage of this approach is that we can have two components inheriting \texttt{PhpComponent} with the same context when we set their context to the same instance.
Thus, we can call their functions by only one reference.
The advantage of this approach is that there can be two components inheriting \texttt{PhpComponent} with the same context when their context is set to the same instance.
Thus, we can call their functions only by one reference.
\subsection{Summary}
\begin{figure}[b!]
\begin{figure}[t!]
\centering
\includegraphics[scale=0.8]{./img/PhpComponentSolution}
\caption{Class diagram of the use case solution.}
\label{img17:solution}
\end{figure}
\par
We summarize the architecture of \texttt{PhpComponent} and solution of \textit{WebGame} use case.
This section summarizes the architecture of \texttt{PhpComponent} and solution of \textit{WebGame} use case.
The component hides the original function for rendering and replaces it with our version of the builder, as shown in Figure \ref{img17:solution}.
It results in transparent usage of the builder in the inherited class.
The builder is just a wrapper, so the programmer can use the original builder by accessing its property, \texttt{Builder}.
Additionally, there is a collection of classes for creating tags, making builder usage easier.
For assigning PHP handlers to C\# events, there is a universal helper class, \texttt{EventHelper}.
Furthermore, the last feature is a timer wrapper, which uses the C\# timer, offering a convenient API.
We can use our predefined API using \texttt{BlazorContext} for interoperability with Javascript.
Interoperability with Javascript is provided by our predefined API using \texttt{BlazorContext}.
These features are sufficient for implementing a game described in \textit{WebGame} use case.
Using PHP functions as handlers, we use the timer to update the game screen by \texttt{StateHasChanged}.
Using PHP functions as handlers, the timer is used to update the game screen by \texttt{StateHasChanged}.
The update consists of evaluating the position of game entities, which use the helper classes representing HTML entities.
Lastly, we use context preservation to keep the game state.
Lastly, context preservation is used to keep the game state.
\par
The last necessary thing is to pass assembly references containing the components into \texttt{Router}, which is a standard duty in Blazor.
\section{PhpScriptProvider}
At the beginning of this section, we introduce the main component parts, which gives us an overview of the component composition.
We divide component duties like navigation or script execution into subsections because the component consists of many processes, which are complex to describe at once in the structure.
The beginning of this section introduces the main component parts, which gives us an overview of the component composition.
Component duties like navigation or script execution are divided into subsections because the component consists of many processes, which are complex to describe at once in the structure.
The component functionality will be explained in these sections.
\par
\begin{figure}[b!]
@ -207,7 +207,7 @@ The component functionality will be explained in these sections.
\label{img18:provider}
\end{figure}
\par
We start with Figure \ref{img18:provider} describing the connections between the main parts.
Figure \ref{img18:provider} describes the connections between the main parts.
\texttt{PhpScriptProvider} is a class, representing a Blazor component.
The component manages the following features.
\par
@ -226,7 +226,7 @@ The context constructor accepts several Blazor services like \texttt{IJSRuntime}
The context initializes superglobals based on URL and submitted forms, manages files uploaded by a form, and controls \texttt{BlazorWriter} which redirects the script output to the render tree.
Lastly, \texttt{FileManager} reads submitted files, downloads them, or deletes them from Browser memory.
\par
We zoom in on \texttt{PhpScriptProvider} structure in order to better understand processes maintaining the features.
The following paragraph zooms in \texttt{PhpScriptProvider} structure in order to better understand processes maintaining the features.
The provider contains of many properties.
Some of them are injected by the dispatcher like \texttt{NavigationManager} or \texttt{IJSRuntime}, which is a service providing interoperability with Javascript.
Others can be parametrized, like \texttt{Type} determining the mode of provider, \texttt{ContextLifetime} determining the persistency of the script context, or \texttt{ScriptName} determining the executing script when the mode \textit{Script} is set.
@ -239,7 +239,7 @@ Some of these methods are called by Blazor framework providing the component lif
\subsection{Navigation}
Now, we explain navigation in \texttt{PhpScriptProvider} for each of its modes.
The section explains navigation in \texttt{PhpScriptProvider} for each of provider modes.
We have to clarify how the component is instantiated and maintained by Blazor.
There are two ways how to use the component.
The first of them is to set it in \texttt{WebAssemblyBuilder} as a root component,
@ -253,34 +253,35 @@ Then, when the parameters are changed, Blazor automatically calls the inner comp
This fact is because the Blazor framework can not decide if the parameters, which are complex types, were changed.
\par
The \textit{Router} mode is designed to be used when the component is a root component.
Then we are sure, that \texttt{Attach} and \texttt{SetParameters} methods are called only once.
Thus, we register navigation handler in the \texttt{Attach} method, which should handle further navigation.
When the navigation occurs, we create a new context if the context should not be persistent and call \texttt{Refresh}.
We create a new context and call \texttt{Refresh} method in \texttt{SetParameters} as well, but the method is called only once at the beginning of the application.
Then, it is certain that \texttt{Attach} and \texttt{SetParameters} methods are called only once.
Thus, navigation handler is registered in the \texttt{Attach} method, which should handle further navigation.
When the navigation occurs, a new context is created if the context should not be persistent, then the \texttt{Refresh} method is called.
\texttt{SetParameters} creates a new context and calls the \texttt{Refresh} method as well, but the method is called only once at the beginning of the application.
Then the \texttt{Refresh} method parses the query part of URL \cite{online:querryStrings}, obtained from \texttt{NavigationManager} and gets the script name from the URL.
When we determine the script name, we call the \texttt{Render} method, where we decide if it is a script or a component defined in a script based on \texttt{.php} extension.
If the extension is missing, we try to find a component defined in scripts, which has correct \texttt{RouteAttribute} by \texttt{PhpComponentRouteManager}.
Otherwise, we ask the Peachpie context for obtaining the script representation as \texttt{ScriptInfo}.
When the script name is determined, the method calls the \texttt{Render} method, where it decides if it is a script or a component defined in a script based on \texttt{.php} extension.
If the extension is missing, it tries to find a component defined in scripts, which has correct \texttt{RouteAttribute} by \texttt{PhpComponentRouteManager}.
Otherwise, it asks the Peachpie context for obtaining the script representation as \texttt{ScriptInfo}.
Additional manager duty is to assign assembly references containing scripts, to the context, at the beginning of the application.
The context does not have to know the script name, or the component does not have to exist.
Then we render predefined \textit{not found} page, which can be set by \texttt{PhpScriptProvider} parameters.
Otherwise, we render the script or the component.
Additionally, when we navigate the component, we set its context by our context.
It results in using the interoperability by either provider or the component because we can use the same context reference in Javascript code.
Then, the \texttt{Render} method renders predefined \textit{not found} page, which can be set by \texttt{PhpScriptProvider} parameters.
Otherwise, it renders the script or the component.
Additionally, when the component is navigated, the method sets its context by the current provider context.
It results in using the interoperability by either provider or the component because there is the same context reference in Javascript code.
\par
Next modes, \textit{ScriptProvider} and \textit{Script}, are similar.
They are defined in a Razor page and initialized when the page is navigated.
The difference is finding the script by name, where the \textit{Script} always uses the name defined in the component parameter and \textit{ScriptProvider} finds script based on URL.
As we said, the \texttt{SetParameters} can be called multiple times, so we call \texttt{Refresh} only by the first time in the method.
As we said, the \texttt{SetParameters} can be called multiple times, so the method calls \texttt{Refresh} only by the first time.
Additional rendering is initiated by the navigation handler.
Thus, when the navigation occurs, we find and update the page, or the component is disposed if \texttt{Router} matches another Razor page.
We create the new context based on the \texttt{ContextLifetime} mode.
Thus, when the navigation occurs, it finds and update the page, or the component is disposed if \texttt{Router} matches another Razor page.
A new context is created based on the \texttt{ContextLifetime} mode.
It differs from common PHP behavior, where the context is disposed after scritps handles the request.
This unusual approach allows calling functions defined in the context after the component is rendered, which is a part of Javascript interoperability when we can call PHP functions by Javascript.
This unusual approach allows calling functions defined in the context after the component is rendered, which is a part of Javascript interoperability when PHP functions can by called by Javascript.
We should check if the component has not already been disposed by \texttt{Router} before calling the \texttt{Refresh}.
Obtaining the script is similar to \textit{Router} mode.
\subsection{Script Execution}
We start with \texttt{BlazorWriter}, which inherits \texttt{TextWriter}.
The inheritance allows using the writer as \texttt{BlazorContext} output writer, which manipulates with script output.
The writer consists of a buffer and \texttt{RenderTreeBuilder}.
@ -303,17 +304,17 @@ handling, which is described in the following section.
\subsection{Forms}
Typically, web forms are not handled by Blazor, and the are sent to the server.
We use Javascript interoperability to evaluate them on the client side.
It starts in \texttt{AfterRender} method, where we call our Javascript function, which finds all already rendered forms and assigns them an event handler for submitting.
Javascript interoperability is used to evaluate them on the client side.
It starts in \texttt{AfterRender} method, where it calls our Javascript function, which finds all already rendered forms and assigns them an event handler for submitting.
When submit occurs, the handler collects all data from the form, does ordinary navigation to the page defined in \texttt{action} attribute, and prevents default behavior, which is sending the form to the server.
When the navigation is handled by \texttt{PhpScriptProvider}, it gets all collected data and assigns the context superglobals by them.
Afterward, the script is executed, and it can access the superglobals.
\par
In the previous paragraph, we did not explain the file management due to its complexity.
The previous paragraph did not explain the file management due to its complexity.
We describe it now.
When a user loads files by form, Javascript obtains only the list of files.
When we want to read the content, we have to use a reading operation, which is done asynchronously by \texttt{Promise} mentioned in the Javascript section.
Thus, when we get the data during navigation, we have to wait until the content is read.
When a programmer wants to read the content, he or she has to use a reading operation, which is done asynchronously by \texttt{Promise} mentioned in the Javascript section.
Thus, when we get the data during navigation, the page rendering has to wait until the content is read.
This operation could take a long time, so the page shows old content.
For this reason, we provide an additional parameter for defining the content, which is shown during navigation.
An alternative is initializing reading by a PHP script when it is executed.

Просмотреть файл

@ -4,13 +4,13 @@ This chapter demonstrates the usage of our solution by four examples, which are
We describe example structures, show important blocks of code, which have to be added to projects.
Source code and binaries can be found in the attachments with build and run instructions.
The library offers debugging logs, which can be helpful to get a better insight into the architecture mechanisms.
We will show how to turn the logs on in the second example.
Instructions on how to turn the logs on are shown in the second example.
\section{WebGame}
The example aims at the third use case.
It contains a game where we have a rocket, which has to destroy falling asteroids with bullets, as we can see in Figure \ref{img28:game}.
We can also see the current \ac{FPS} in the left corner of the screenshot.
It contains a game where a rocket has to destroy falling asteroids with bullets, as we can see in Figure \ref{img28:game}.
The current \ac{FPS} is displayed in the left corner of the screenshot.
The rocket can be control by buttons in the bottom, or we can use a keyboard, where arrows determine the rocket movement and the \texttt{F} key fires a bullet.
We will discuss the rendering time in the benchmark section.
\par
@ -25,16 +25,16 @@ The example is implemented as a .NET solution consisting of three projects.
\texttt{BlazorApp.Client} and \texttt{BlazorApp.Server} are pregenerated projects by the Blazor App template.
The game is implemented in the Peachpie \texttt{PHPScripts} project.
These projects reference the \texttt{Peachpie.Blazor} library as a NuGet package containing all the necessary helper classes.
We describe steps, which were necessary for making the game working.
The following paragraph consists of steps, which were necessary for making the game working.
\par
We can find the game implementation in three PHP scripts and a CSS file defining game styles.
The game implementation is divided into three PHP scripts and a CSS file defining game styles.
The \textit{settings.php} script comprises default values of delay between game refreshing, an asteroids frequency, and additional settings.
The \textit{asteroids.php} script defines game entities like the rocket or an asteroid.
These entities utilize the \texttt{Peachpie.Blazor} library, which provides helper classes representing HTML elements.
At the bottom of the script is the \texttt{Application} class connecting all parts together.
The class uses HTML element events for interacting with a user due to the \texttt{PhpTreeBuilder} class providing an API targeting PHP usage.
The last script is \textit{main.php}, which contains the \texttt{AsteroidsComponent} class.
We can navigate this class by \texttt{/Asteroids} path.
A user can navigate this class by \texttt{/Asteroids} path.
It initializes the game and uses \texttt{Timer} provided by \texttt{Peachpie.Blazor}, which enables to fire tick events updating the game and the screen.
Because the \texttt{Application} class inherits the helper class \texttt{Tag}, \texttt{AsteroidsComponent} uses the \texttt{BlazorWritable} interface to format and render the game into HTML instead of formating and rendering the game by exposing the \texttt{Application} structure.
\par
@ -77,7 +77,7 @@ The website contains images, which are downloaded from the server when they are
\par
The whole application is implemented as .NET solution consisting of three projects.
\texttt{BlazorApp.Client} represents the client application containing \texttt{Program.cs}, which sets \texttt{WebAssemblyBuilder} and a root component, \texttt{PhpScriptProvider}, as we can see in Figure \ref{img20:program}.
We can turn debug logs by setting the minimum level of logging to Debug.
Debug logs can be turned on by setting the minimum level of logging to Debug.
\texttt{Blazor.Server} has the same role as in the previous example.
\par
\begin{figure}
@ -121,13 +121,14 @@ We can see the \textit{force.php} script containing empty \texttt{force} class,
An interesting page is \textit{developers.php}, which displays information about developers working in the company.
We can see the script in Figure \ref{img25:developer}
It uses script inclusion to add the head section.
Then, we make a Javascript call by using our predefined API, which causes the alert with the message when the page loads.
Then, there is a Javascript call using our predefined API, which causes the alert with the message when the page loads.
The whole page uses HTML interleaving.
We can see using \texttt{\$\_GET} superglobal in the script, where we decide to show its content based on the URL query.
The \texttt{\$\_GET} superglobal is used to make a decision on which content to display based on the URL query.
The default mode for the context is \texttt{OnNavigationChanged}.
When we refresh the page after navigation to a developer, we can see the anchors to developers.
When a user refreshes the page after navigation to a developer, he or she can see the anchors to developers.
It is caused by creating a new context between navigation, so the variables are disposed.
If we want to change the mode to \texttt{Persistant}, we just set the component parameter,\texttt{ContextLifetime}, to \texttt{Persistant}, which we show in the next example.
If we want to change the mode to \texttt{Persistant}, we just set the component parameter,\texttt{ContextLifetime}, to \texttt{Persistant}.
It is shown in the next example.
This page is transparently rendered by our \texttt{PhpScriptProvider}, which evaluates the whole script and adds the output as a markup text to the builder.
\par
\begin{figure}
@ -158,9 +159,9 @@ if (isset($_GET["developer"])) {
\section{OneScript}
In this example, we aim at the second use case.
This example aims at the second use case.
The website contains several pages which demonstrates an insertion of page fragments, written in PHP, to the Blazor website.
When we navigate the page, we can see a button, which utilizes interoperability between PHP and Javascript provided by our solution.
When we navigate the page, there is a button, which utilizes interoperability between PHP and Javascript provided by our solution.
When we click on it, the javascript code calls PHP code, which writes a message to a browser console.
Next examples referred as \textit{Example 1}, \textit{Example 2}, \textit{Example 3} show working with forms.
The first example uses a simple form with the \texttt{GET} method.
@ -170,7 +171,7 @@ We can also try to load a file to the form in the last example.
After the submit, the page displays its file contect encoded into \textit{base64} encoding.
\textit{Example 4} uses previously mentioned features to enable displaying user defined graphs.
We can upload a file containing the graph, or the application will generate it.
Then the graph is displayed, and we can download the points defining it, as we can see in Figure \ref{img27:graph}.
Then the graph is displayed, and the points defining it can downloaded, as we can see in Figure \ref{img27:graph}.
\par
\begin{figure}[b!]
\centering
@ -187,12 +188,12 @@ The website contains three Razor pages: \textit{Index.razor}, \textit{PhpGateway
The first page uses \texttt{PhpScriptProvider} to navigate \texttt{index.php}.
Using the provider is straightforward.
\par
We want to show the call of PHP function from Javascript in Figure \ref{img26:index}.
Figure \ref{img26:index} shows the call of PHP function from Javascript.
As we can see, it is effortless to call it.
The \texttt{callPHP} function accepts the function name and object to serialize as a function parameter.
When the script is rendered, the context contains defined \texttt{CallPHP} function.
We click on the button, which invokes \texttt{Call} method on the context, which invokes the desired function.
Then, we deserialize the parameter.
Then, the parameter is deserialized.
There is an interesting thing about using \texttt{echo}, \texttt{print}, etc. when the script is not rendered.
The context provides the second writer, which uses \texttt{Console} as the output.
It causes printing the message into the web browser console.
@ -248,10 +249,10 @@ Afterward, we can see a graph, which contains a score generated by the game.
\par
The .NET solution contains three projects \texttt{BlazorApp.Client}, \texttt{BlazorApp.Server}, and \texttt{PHPScripts}.
\texttt{PHPScripts} consists of \textit{Game}, \textit{Graph}, \textit{Web}, and \textit{wwwroot} folders.
We already know the implementation of these parts.
An interesting collaboration is between the game and the graph, where we save a global variable containing the graph in \texttt{AsteroidsComponent} and uses it later in \textit{main.php}, which provides the graph visualization.
The implementation of these parts is explained in previous examples.
An interesting collaboration is between the game and the graph, where a global variable containing the graph is saved in \texttt{AsteroidsComponent} and it is used later in \textit{main.php} providing the graph visualization.
It works due to \texttt{PhpScriptProvider}, where we navigate either \textit{main.php} or \texttt{AsteroidsComponent}.
Because the context can be persistent, we share global variables between these parts, and we can communicate through them.
Because the context can be persistent, global variables are shared between these parts, and they can communicate through them.
We choose between navigated parts by submitting a form containing one button, which navigates the game, and an anchor containing a reference to \textit{main.php}.
Because default \texttt{Router} can navigate \texttt{AsteroidsComponent}, we don't add the \texttt{PHPScripts} assembly to the router additional assemblies in order to let the provider navigate the component.
The navigation, maintained by the provider, shares the provider content with the game component, which is a reason for keeping the provider alive and hiding the game component before the default router.

Просмотреть файл

@ -1,9 +1,9 @@
\chapter{Benchmarks}
In this chapter, we show the difference between using \texttt{PhpTreeBuilder} properly and only the \texttt{AddMarkupContent} method.
Then, we test the speed of three PHP library functions in the Blazor and desktop environments.
This chapter shows the difference between using \texttt{PhpTreeBuilder} properly and only the \texttt{AddMarkupContent} method.
Then, it tests the speed of three PHP library functions in the Blazor and desktop environments.
These benchmarks are available as .NET solutions in the attachment.
We introduce the background of the benchmarks, execute them and then evaluate the results.
The following sections introduce the background of the benchmarks, execute them and then evaluate the results.
\par
The tests were executed on a HP Spectre x360 Convertible laptop with Intel(R) Core(TM) i7-8550U CPU, 8GB RAM, and NVIDIA GeForce MX150.
They used Google Chrome (version: 90.0.4430.93) browser and Apache server.
@ -11,11 +11,11 @@ They used Google Chrome (version: 90.0.4430.93) browser and Apache server.
\section{Rendering}
This benchmark observes the refreshing speed of a page using two ways for rendering a page content.
We modify the \texttt{Asteroids} game, mentioned earlier, to explore FPS during rendering.
The \texttt{Asteroids} game, mentioned earlier, is modified to explore FPS during rendering.
The modified application generates asteroids, represented by \texttt{<div>} element with CSS styles, and lets them fall until they reach the bottom, as we can see in Figure \ref{img33:benchmark}.
Then, they are removed.
We log the current FPS, count of elements generated by the application, and time from starting the measurement every second.
Then, we evaluate the results.
The current FPS, count of elements generated by the application, and time from starting the measurement are logged every second.
Then, there are result evaluations.
\par
\begin{figure}[t]\centering
\includegraphics[scale=0.7]{./img/BenchmarkRendering}
@ -27,8 +27,8 @@ The .NET solution comprises three projects: \texttt{BlazorApp.Client}, \texttt{B
The setting of BlazorApp is similar to the previous examples.
\texttt{PHPScripts} contains the modified game together with additional scripts providing the interactive setting for the benchmark in a browser.
When we start the server and navigate the website, we can set various properties of measurement like an upper bound of FPS, a frequency of asteroids, or dimensions of background.
We will explain only the \textit{Rendering} property because the rest of the properties are self-explanatory.
We have two options for the property.
We explain only the \textit{Rendering} property because the rest of the properties are self-explanatory.
There are two options for the property.
We call the first one \texttt{String} rendering because it uses \texttt{AddMarkup} method for updating the page content.
This method accumulates the generated HTML entities into a single string and adds it into \texttt{PhpTreeBuilder}.
We call the second one \texttt{Diff} rendering because it utilizes specialized builder interface for adding HTML entities, which includes \texttt{AddAttribute} for example.

Двоичные данные
docs/thesis/thesis.pdf

Двоичный файл не отображается.

Двоичные данные
docs/thesis/thesis.synctex.gz

Двоичный файл не отображается.

Просмотреть файл

@ -194,30 +194,31 @@ The attachments contain a user manual that helps to get familiar with the librar
The library, examples, and benchmarks are .NET solutions, which can be opened by \ac{VS} 2019.
The \texttt{bin} folder consists of compiled examples with supports for various OS and architectures like Windows (x86, x64), Unix, OSX, or Linux (x86, x64, arm).
We need only a .NET 5.0 runtime, which is available from \url{https://dotnet.microsoft.com/download/dotnet/5.0}, to run binaries.
After the installation, we launch the particular example by moving to the \texttt{bin/NameOfExample} directory and run the command line below:
The .NET 5.0 runtime, which is available from \url{https://dotnet.microsoft.com/download/dotnet/5.0}, is required to run binaries.
After the installation, the particular example can be run by moving to the \texttt{bin/NameOfExample} directory and run the command line below:
\par
\begin{code}[frame=none]
dotnet BlazorApp.Server.dll
\end{code}
\par
Then, we can navigate \url{https://localhost:5001}, or \url{http://localhost:5000} to reach the website.
Then, the website can be accesed by navigation to \url{https://localhost:5001}, or \url{http://localhost:5000}.
\par
We need .NET 5.0 SDK, which is available from the same website as the runtime, to build solutions.
After the installation, we compile and pack the \texttt{Peachpie.Blazor} library by moving to the \texttt{src/Peachpie.Blazor/Peachpie.Blazor} directory and run the commands below:
The .NET 5.0 SDK, which is available from the same website as the runtime, is required to build solutions.
After the installation, the \texttt{Peachpie.Blazor} library has to be compiled and packed.
This is done by moving to the \texttt{src/Peachpie.Blazor/Peachpie.Blazor} directory and run the commands below:
\par
\begin{code}[frame=none]
dotnet build --configuration Release
dotnet pack --configuration Release
\end{code}
\par
Then, we compile an example by moving to its directory containing the \texttt{BlazorApp.Server} project and run the command below using the NuGet generated by the previous step:
Then, an example can be compiled by moving to its directory containing the \texttt{BlazorApp.Server} project and run the command below using the NuGet generated by the previous step:
\par
\begin{code}[frame=none]
dotnet build --configuration Release --source PathToTheLibraryNuGet
\end{code}
\par
After the compilation, we can launch the server by the instructions mentioned at the beginning of this section.
After the compilation, the server can be launched by the instructions mentioned at the beginning of this section.
\par
The template compilation can be done by running a PowerShell command \texttt{./build/build.ps1} in the template folder.
It results in a NuGet package, which can be added to VS template collection.