Skip to content

Module API

betas edited this page Jun 24, 2017 · 37 revisions

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.

Module Structure

Modules are folders inside of the modules directory of Place 2.0. Name it something so that they can be easily identified.

The module.json file

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"
}

module.json API reference list

  • 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

Your main module file

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.

Adding more to the templates with extensions

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.

Adding extra JS and CSS to the site

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

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).

Registering more routes

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).

Example Router file

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:

Example Router module information

{ ... other stuff
    "routes": [
        {
            "path": "/"
            "file": "MyRouter.js"
        }
    ]
}

Route object API reference list

  • 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.

Clone this wiki locally