-
Notifications
You must be signed in to change notification settings - Fork 96
Module API
This document is a work-in-progress proposal and has not been implemented yet.
Place 2.0 is great because it's open, but everyone has different needs and uses for it. A lot of configuration can be done in the config.js
file, but after that, it's hard to keep up with custom code changes and more. That's why we created the module API.
Modules are loaded when the Place 2.0 server starts up. They can do things such as adding extra HTML to the templates, adding more routes, adding middleware to every request, creating new data models, and even extending existing data models with new methods and fields.
Modules are folders inside of the modules
directory of Place 2.0. Name it something so that they can be easily identified.
Every module must have a module.json
file in its root directory. This instructs Place 2.0 on how to load your module. The most basic example of a module.json
looks like this:
{
"identifier": "co.dynastic.place.module.test",
"main": "main.js",
"name": "Test Module"
}
-
identifier
: This identifier is unique to your module and is how Place 2.0 refers to it internally. Make sure no other modules have this identifier. (required) -
main
: The main file for your module. It should also be in the root directory of your module. We'll get into this more in the next section. (required) -
name
: A user-friendly name for your module that we can show the user if ever needed. (required) -
priority
: A number stating the priority in the loading order of all modules. A module with a higher priority gets loaded before a module with a lower priority. (default: 1) -
route
: A list of any routes that need to be processed by Place. (default: none) API Reference Example
The main module file contains your module's main class. This is responsible for loading any other code you might need and initializing your module. It should be in your module's root directory and have the same name you specified in your module.json
.
Use this boilerplate template of a main module file to get started:
class Module {
constructor(app) {
this.app = app;
this.meta = require('./module');
}
// any other code you might need
}
module.exports = Module;
The main Place app object is passed in the constructor of your module, and it is created while Place loads (just before the server starts listening). You can do anything in there you need to initialize your module and modify the main Place app object.
To make it easier to add HTML to integral places, we have added insertion points in our module files. It's easy to add onto a template using insertion points. The following insertion points are available for creating your extensions:
-
head
: Inside the<head>
attribute of every page. (note: there's a better way to add CSS and JS, in your main module file) -
nav_left
: Inside the navigation bar, to the left of all of the built-in links. -
nav_inside
: Inside the navigation bar, right after the Home link. -
nav_right
: Inside the navigation bar, to the right of all of the built-in links (rules, admin). -
nav_user_left
: Inside the navigation bar, to the left of the user menu. -
nav_user_right
: Inside the navigation bar, to the right of the user menu. -
main
: In the<body>
of the main Place page. -
body
: In the<body>
of every page. -
place
: In the Place<div>
. -
footer
: Inside the footer, after the copyright information.
Adding your own HTML into these insertion points is really easy. To start, create a folder called view_extensions
in your module's root. For every insertion point you want to hook, create a file with the name of your insertion point with an HTML extension (e.g., nav_inside.html
). Add any HTML you want to your template file and Place 2.0 will automatically load it. No need to add any other code.
Pro tip: Template extensions follow the same loading order based on the priority specified in your
module.json
when choosing how to lay out. Modules with higher priorities will get inserted before modules with lower priorities.
Modules also have an easy way to add stylesheets and scripts to the website. Inside your main module file again, the methods getCSSResourceList
and getJSResourceList
are available. You simply have to return an array of the resources you would like to add to the page. In addition, the request is passed along as a parameter so you can add your own logic for adding files.
Here's an example how you would utilize one of these methods to add a stylesheet:
class Module {
// ...
getCSSResourceList(req) {
return ["/css/module.css"]
}
}
// ...
Easy, right? But we referenced a stylesheet, how can we actually make it available so that the browser can load it? We use the public
folder.
Heads up! Remember that each resource can significantly increase the load time of a page. Use the request object passed as a parameter to only load the resources required for each page and get rid of unnecessary resources where possible.
Serving static files with modules is as easy as making a folder and dropping files in it. No really, that's all you have to do.
Make a folder called public
in your module's root directory. From there, you can add any file and it will be served when requested by the browser. Try and keep a similar directory structure to Place itself (separate folders for each resource type, such as css
, js
, and img
).
You can easily create more routes in your module. Create a folder named routes
in your module's root to get started. Then, using the routes
property of your module.json
, you can tell Place how to process them.
Like other routes, you simply create an Express router and add your routes to it, then pass a function returning that router as an export. This function will be called again with the main Place app object for convenience, but it is also available as a parameter on each request (req.place
).
const express = require('express');
function MyRouter(app) {
let router = express.Router()
router.get('/test', function(req, res) {
return res.send("Hello, world!");
});
return router;
}
MyRouter.prototype = Object.create(MyRouter.prototype);
module.exports = MyRouter;
Once you've created the code for your route, you need to tell Place how to load it. In your module.json
file, add a routes array like so:
{ ... other stuff
"routes": [
{
"path": "/"
"file": "MyRouter.js"
}
]
}
-
path
: The prefix to all requests to this route. (for example, if this is set to/test
and you have a route going to/hello
, you can call/hello
by going to/test/hello
) (required) -
file
: The file containing the code for your custom route. (required)
More information about the module API will be available soon.
Place 2.0 is licensed under the APGL-3.0 license. Please see it for details.