Skypager Runtime
This is the core Skypager Runtime, which is made up of:
- the base Runtime class
- the base Helper class
- the Feature Helper
In addition to these base framework classes, it provides a number of utilities used by the base framework:
- Event Emitter
- Entity
- String Inflection
- Middleware Pipelines
- Object Hashing
- Path Matcher
- Property Utils
- Array Query
- String Utils
Runtimes
A Runtime is a class which provides a global singleton instance that can be shared by all modules in a project.
This global singleton instance is an observable state machine, with an event emitter, a vm, and helper module registries.
As a developer, you should be building everything that your projects have in common into runtime bundle that can be cached long term, and ideally shared between many projects.
Helpers
Helpers are a core component of the skypager framework. They are used to define module types and categories, usually matching the plural names found in the the source code organization conventions.
For example, in one of your apps, you might have the following structure:
src
├── apps
│ ├── PublicApp.js
│ └── UserApp.js
├── components
│ ├── AddItem.js
│ ├── ItemList.js
│ ├── NavButton.js
├── features
│ ├── items.js
│ ├── permissions.js
│ ├── authentication.js
├── pages
│ ├── HomePage
│ │ └── index.js
│ ├── ItemPage
│ │ └── index.js
In this app, you might have the following Helper
subclasses
import { Helper } from '@skypager/runtime'
class App extends Helper { }
class Component extends Helper { }
class Feature extends Helper { }
class Page extends Helper { }
Which get used in the following way
// src/runtime.js
import runtime from '@skypager/runtime'
import App from 'helpers/App'
import Component from 'helpers/Component'
import Page from 'helpers/Page'
import PublicApp from 'apps/PublicApp'
import UserApp from 'apps/UserApp'
import HomePage from 'pages/HomePage'
import ItemPage from 'pages/ItemPage'
import ItemsFeature from 'features/items'
import PermissionsFeature from 'features/permissions'
import AuthenticationFeature from 'features/authentication'
runtime
.use(App)
.use(Component)
.use(Page)
runtime.apps.register('public-app', () => PublicApp)
runtime.apps.register('user-app', () => UserApp)
runtime.pages.register('HomePage', () => HomePage)
runtime.features.register('items', () => ItemsFeature)
runtime.features.register('permissions', () => PermissionsFeature)
runtime.features.register('authentication', () => AuthenticationFeature)
// Enable all of our features and export the runtime. The Module require.cache
// will ensure that we always have the same instance anywhere it is imported in the project
export default runtime
.use('permissions')
.use('authentication', {
provider: 'oauth2',
config: { token: "abc", callbackUrl: "/callback" }
})
.use('items')
The Helper
class provides you with a way for defining object models on top of the different types of modules in your project.
And once the runtime users a Helper
(e.g. runtime.use(App)
) you can register the available instances of these modules with module registries (such as runtime.apps
, runtime.features
and runtime.pages
in the example above.)
With these systems in place, it is hopefully clearer how you might define an App
as a collection of Pages
and a Page
as a collection of Components
which use different Features
.
Since an App
, Component
, Feature
, or Page
all have their own life cycles and configuration mechanisms, but common to each other, the Helper
gives you a place to define what all Features
Pages
and Apps
have in common in your project.
By modeling this logic in helper classes, you can better take advantage of declarative coding styles to compose all of the various pieces of your application together.
Take a look at the example below.
// the module we wrote above for example
import runtime from './runtime'
const MyWebsite = () => {
const UserApp = runtime
.app('UserApp', {
pages: {
"/" : "HomePage",
"/items": "ItemsPage",
"/items/:id": "ItemsPage"
}
})
}
let mySite
async function main() {
await runtime.start()
mySite = MyWebsite()
return mySite.render()
}
main()
In this application, we're building an app by describing which pages it has and which features it depends on.
The Helper
class is how we describe how these different types of pieces fit together.