GlueCodes Studio has been built to support you with standards. You won't see much magic here when it comes to coding. The structure is made with HTML extended with attribute directives and extended tags to achieve reactivity. Styles are CSS but smartly linked and powered by CSS Modules. Similarly the logic is written with JavaScript ES7+ with a few rules which allow to achieve the level of automation we aimed for:
imports
global e.g. imports.someLocalName
window
object and any [global variables] via global
variableIn GlueCodes Studio your business logic is spread across app actions which store their returned/resolved values in a single store. The data changes flow in one direction and UI reacts to changes of the store, updating the only affected parts. The DOM diffing happens in-compilation time and is powered by SolidJS.
There are two types of actions; the ones that supply data before rendering called Providers and those triggered by a user called Commands. Their both returned/resolved values are accessible by their names in UI and [widget input parameters]. In your UI, specifically in slots and reusable slots you get access to global variables actions
and actionResults
. The variable actions
is an object of Commands you can call to perform an action e.g. to return/resolve fetch
ed data.
Let's imagine calling actions.fetchUser
. When called (typically on a DOM event), it'll implicitly write to the store and the result will be accessible via actionResults.fetchUser
. In the same HTML piece (and also anywhere on the page) you can call a Command and display its result, however bear in mind that initially, before it's ever called the result of a command defaults to null
.
In order to fetch data prior to rendering you wouldn't call actions.fetchUser
Command. Instead you'd create a Provider and simply by using one of directives or accessing it via global actionResults
(e.g.actionResults.fetchUser
) in an extended tag, you'd tell the studio to call it before the UI is rendered. Providers also write to the store by returning/resolving and their results are accessible in slots and resuble slots via global variable actionResults
. Providers pass through a single argument which is a snapshot of the store, by convention named actionResults
. You can set their execution order and have multiple Providers which do a single task and pipe through data to compose the final result. You can also feed your app with incoming data, just see [live providers].
A typical scenario would be to use Commands combined with Providers. Let's imagine you want to add a record to a list so on the same page you have a form and data table. In this case you'd use a Provider e.g. getRecords
and Command addRecord
. On the form submission, you would call actions.addRecord
and then reload providers to give you fresh records. This can be simply done by awaiting actions.addRecord
and calling built-in . For more details see [built-in commands].
Note: if a Command or Provider doesn't exist and you reference it in directives or extended tags, the [implementation assistant] will notify you to create it.
It's a SolidJS state which keeps results of Commands and Providers by their names along with few built-in objects like: errors
, parseRootNodeDataset
and route
.
Command is an action triggered by a user typically via DOM event. It's a function exported as default and it can take any arguments. It can be async
and by returning it writes to a store. See the above section to understand its relation with the store. It's wrapped in a single [error handler] which catches whatever errors is thrown and errors are accessible in slots, reusable slots and [widget input parameters]. There are several built-in commands:
errorName
and marks error as cancelled meaning that the user has already dealt with it. Literally, it means setting isCancelled
property to true
so in UI you can use it in conditionals.url
to which hard-redirect is to be made.reload
. Typically you'd have an early-returning if statement which checks for actionResults.reload === ‘someReloadType’
to avoid unnecessary executions. So e.g. in getSomething
provider you'd return actionResults.getSomething
which would be a reference to earlier returned value.commandsToRun
which is an array of arrays looking like: [[‘command1’, arg1, arg2...], ...]
and runs each - command caching their results before writing them together to the store.error
object.Commands have access to the following global variables:
imports
- an object of imported functions via [dependencies]global
- a combine window
and [global variables] objectProvider is an action executed prior to UI rendering. It's a function exported as default and it passes through a snapshot of the store. You can access results of previously executed Providers by accessing its only argument, by convention named actionResults
. You can set the order of execution, [see how]. It can be async
and by returning it writes to a store. See the above section to understand its relation with the store. There are several built-in objects in the store:
isCancelled
property which tells if a user has already dealt with it e.g. removed an input field value which wasn't valid.window.location
Providers have access to the following global variables:
imports
- an object of imported functions via [dependencies]mediaFiles
- an object of media files e.g. mediaFiles['some-image'].png
global
- a combine window
and [global variables] objectThere are cases when you want to feed your UI with incoming data. E.g. data coming from a Web Socket or some non-DOM event. With GlueCodes Studio you're covered.
To put it into perspective let's compare this normal Provider:
async
or non-async.actionResults
.with this Live Provider:
actionResults
.async
or non-async.asyncResults
- an object of promises of other live providers so you can await
other Live Providers.hasBeenInitialized
- a flag which tells whether provider has been already executed. Useful to wrap any event registering code so it just happens once.provide
- a callback which needs to be called in order to resolve the provider data. Every time it's called with new data it'll write to the store which then affects the UI which accesses its result.In classical MVC apps you have a separation between Controller and Model. In GlueCodes architecture Commands and Providers play the role of Controllers. By the book fat Controllers and especially those with duplicated data access are a bad idea. If you need another layer to e.g. share data accessors among different Commands and Providers, then Reusable Functions might come handy. For now they are available only for enterprise members who can create their own repositories of widgets and shape the entire business domain with Commands, Providers and Reusable Functions.
Parameters for a widget are supplied by a function which returns an object. It passes destructured actions
and actionResults
which are Commands and a snapshot of the store respectively. The function can be understood as an adapter/connector between the app and widget. Widgets rely on SolidJS reactivity so quite often you'll see parameters whose names start with "get" or "is" and pass arrow functions. That's how reference to the store is kept so the widget can react to its changes. Widget input parameter functions have access to the following global variables:
mediaFiles
- an object of media files e.g. mediaFiles['some-image'].png
global
- a combine window
and [global variables] objectThere is a single error handler which catches any errors thrown by Commands. Whenever an error is thrown, it ends up in the store's errors
object by its name. You can access errors in slots, reusable slots, [widget input parameters] and [providers]. By convention you'd access e.g. SomeErrorName
error by actionResults.errors.SomeErrorName