@seanox/aspect-js
Version:
full stack JavaScript framework for SPAs incl. reactivity rendering, mvc / mvvm, models, expression language, datasource, virtual paths, unit test and some more
236 lines (174 loc) • 7.44 kB
Markdown
[Markup](markup.md) | [Inhalt](README.md#scripting) | [DataSource](datasource.md)
- - -
# Scripting
Seanox aspect-js nutzt Composite-JavaScript. Ein Dialekt, basierend auf dem
JavaScript des Browsers, das um Makros -- einer einfachen Meta-Syntax,
angereichert wurde.
Composite-JavaScript, was auch die Module einschliesst, wird nicht als Element
eingefügt, sondern direkt mit der eval-Methode ausgeführt. Da hierzu
ein isolierter und nicht der globale Gültigkeitsbereich (Scope) verwendet
wird, sind Variablen, Konstanten und Methoden nicht direkt global oder
übergreifend nutzbar, weshalb u.a. das Composite-JavaScript mit [Makros](
#makros) angereichert wurde, welche u.a. solche Aufgaben übernehmen.
## Inhalt
* [Eingebettetes Composite-JavaScript](#eingebettetes-composite-javascript)
* [Module](#module)
* [Makros](#makros)
* [#export](#export)
* [#import](#import)
* [#module](#module)
* [#use](#use)
* [(?...) tolerate](#-tolerate)
* [Debugging](#debugging)
## Eingebettetes Composite-JavaScript
Eingebettetes Scripting bringt einige Besonderheiten mit sich. Das
Standard-Scripting wird vom Browser automatisch und unabhängig vom
Rendering ausgeführt. Daher wurde das Markup für das Rendering um den
zusätzlichen Skript-Typ `composite/javascript` erweitert, der das normale
JavaScript verwendet, im Vergleich zum Typ `text/javascript` vom Browser aber
nicht erkannt und somit nicht direkt ausgeführt wird. Der Renderer hingegen
erkennt den JavaScript-Code und führt diesen mit jedem relevanten
Renderzyklus aus. Auf diese Weise kann das SCRIPT-Element mit anderen
Composite-Attributen kombiniert und die Ausführung damit gesteuert werden.
```html
<script type="composite/javascript">
...
</script>
```
## Module
Module sind ein fester Bestandteil des Composite-Konzepts. Bei diesem Konzept
wird davon ausgegangen, dass die Ressourcen für ein Composite (JS, CSS,
HTML) in das Modul-Verzeichnis ausgelagert sind und erst zur Laufzeit geladen
werden. Was u.a. die Startzeit verkürzen und das Linken bzw. Binden der
Module zu einer Anwendungsdatei vermeiden soll, was sich an der Idee für
Micro-Frontend orientiert, so dass sich Plattform und Module unabhängig
bereitstellen lassen.
Auch ohne Composites lassen sich Module im JavaScript nutzen. Dazu wird die
Logik ebenfalls in einzelnen Dateien im Modul-Verzeichnis und wenn erforderlich
in weiteren Unterverzeichnissen abgelegt.
```
+ modules
+ example
- moduleE.js
- moduleF.js
- ...
- moduleA.js
- moduleB.js
- ...
- index.html
```
Die Module werden dann programmatisch mit `Compoiste.include(...)`,
`Compoiste.load(...)` oder bevorzugt mit dem Makro [#import](#import) geladen.
__Beim Aufruf von Modulen wird auf die Dateiendung verzichtet.__
```javascript
#import moduleA moduleB
#import example/moduleE example/moduleF
```
## Makros
Makros sind eine einfache Meta-Syntax, die sich in die bestehende
JavaScript-Syntax einfügt. Im Kern sind es verkürzte Schreibweisen
oder Umschreibungen für gängige JavaScript-Anweisungen.
### #export
Composite-JavaScript, was auch die Module einschliesst, wird nicht als Element
eingefügt, sondern direkt mit der eval-Methode ausgeführt. Da hierzu
ein isolierter und nicht der globale Gültigkeitsbereich (Scope) verwendet
wird, sind Variablen, Konstanten und Methoden nicht direkt global oder
übergreifend nutzbar.
Hier lassen sich Variablen, Konstanten und Methoden mit dem Makro `#export`
global nutzbar machen. Nach dem Namen des Makros werden bis zum Zeilenende oder
bis zum nächsten Semikolon eine durch Leerzeichen getrennte Liste mit den
Namen der Elemente erwartet, die öffentlich zugänglich gemacht werden
sollen.
```javascript
const connector = {
...
};
const utilities = {
...
};
#export connector utilities;
```
Die Namen der Elemente können für den Export um Namensräume
erweitert werden, damit diese explizit dort hinzugefügt werden.
```javascript
const connector = {
...
};
const utilities = {
...
};
#export connector@io.example utilities@io.example
```
### #import
Das Makro lädt ein oder durch Leerzeichen getrennt mehrere
(Composite)-JavaScript-Module aus dem Modul-Verzeichnis, wobei JavaScript-Module
nur einmalig geladen werden, egal ob direkt über [#import](#import) oder
indirekt als Ressource zu einem Composite.
__Beim Aufruf von Modulen wird auf die Dateiendung verzichtet.__
```javascript
#import moduleA
#import moduleA moduleB moduleC
```
Zu beachten ist, dass das Makro bei einem Server-Status abweichend 200 zu einem
Fehler führt. Da sich das Makro in die allgemeine JavaScript-Syntax
einfügt, kann der Fehler wie gewohnt mit try-catch gefangen werden.
```javascript
try {#import moduleA;
} catch (error) {
...
}
```
Im Modul-Verzeichnis werden auch Unterverzeichnisse unterstützt, was in den
Modulnamen durch das Slash repräsentiert wird.
```javascript
#import example/io/connector;
```
### #module
Dieses Makro ist als Hilfe für das Debugging implementiert worden. Es
erwartet Text bis zum Zeilenende oder bis zum nächsten Semikolon, der in
der Browser-Konsole im Debug-Level ausgegeben wird.
```javascript
#module some text;
```
Als Besonderheit wird auch die Syntax der String-Expression von JavaScript
unterstützt, was die Verwendung von Variablen ermöglicht.
```javascript
const value = "Hallo Welt!";
#module some more complex text: ${value} ... ${1 + 2};
```
### #use
Das Marko erwartet einen oder mehrere durch Leerzeichen getrennte
Namensräume, die auf Objektebene erstellt werden, wenn diese noch nicht
existieren.
```javascript
#use a
#use a b c
#use a.b.c d.e.f g.h.i
```
### (?...) tolerate
Ein ganz besonderes Makro ist die tolerierende Anweisung `(?...)`. So wird die
in den Klammern eingeschlossene Logik im Fall eines Fehlers nicht zum Fehler
führen und es wird keine Ausgabe in der Browserkonsole geben. Stattdessen
wird die Klammer den Wert `false` repräsentieren. Von diesem tolerierenden
Verhalten ausgenommen sind Syntaxfehler.
```javascript
const value = (?object.that.does.not.exist());
```
## Debugging
Da Ressourcen und Module, was JavaScript einschliesst, erst zur Laufzeit geladen
werden, kennt der Browser die Quellen nicht und so werden die Module in den
Entwicklerwerkzeugen der Browser nicht angezeigt, was u.a. für die
Verwendung von Break-Points wichtig ist. Daher muss hier der Einstiegspunkt ins
JavaScript über die Browser-Konsole genutzt werden, welche neben der
Text-Ausgabe auch einen Link zur Quelle der Ausgabe enthält. Und über
diesen Link lässt sich auch der Quelltext der Module im Debugger
öffnen und gewohnt mit Break-Points nutzen.
Daher sollten Module zum Debugging eine entsprechende Konsolen-Ausgabe erzeugen.
Das kann manuell über das `console` Objekt oder alternativ mit dem Makro
[#module](#module) möglich ist.
```javascript
#module example;
...
```
- - -
[Markup](markup.md) | [Inhalt](README.md#scripting) | [DataSource](datasource.md)