JS Only Application Modules - NCIOCPL/cgov-digital-platform GitHub Wiki
JS-Only App Modules are used for any JavaScript (usually React-based) app modules that do not need any back-end Drupal support. Drupal will handle the loading of the page, displaying server-side 404s for unknown routes within the app, and providing some basic URL information. In addition app modules follow a specific config format for the JSON data. Until app modules have the ability to draw a UI for their options, OR at least some validation method exists, the following will have to do.
The simplest app module you can make is something like the following:
window.My_App_Module_Init = (config) => {
const appEl = document.getElementById('my-app-module');
appEl.innerText = 'Hello World';
}
For a react app, appEl.innerText = 'Hello World';
would end up being something like ReactDOM.render(<App />, appEl);
.
Your init function will be passed a configuration object with a combination of items from the App Module Configuration and information from Drupal about the page. This information contains, as a flat object, the following:
- All of the elements from the
frontEndConfig
section of the App Module Configuration. -
baseHost
- the value of the current baseHost. If you need to use an absolute URL back to your app or another page, you want to use this. -
basePath
- The url of this page. For -
canonicalHost
- The canonical host for the page. This can be different than thebaseHost
. You should use this host when creating a<link rel="canonical" />
element. (This is usually used for SEO purposes and MIGHT not be the same host as the app is running on.) -
language
- This should be the language of the page that is holding the app module. -
rootId
- TherootId
of thedrupalConfig
from the App Module Configuration. -
alternateLanguageUrls
- an object that is a collection of the various translations of the current page:- 2-language character code (e.g.,
en
for English) - The path of that version
- 2-language character code (e.g.,
- The entire application must be bundled into a single .js file and hosted on another web site.
- There is no way to upload the file to the Drupal server.
- As above you can see that .js must add an initialize function onto the Window object. The name must be UNIQUE as to not clash with any other variables that may already exist.
- This function name will be specified in the App Module Configuration and called upon load of your provided JS file.
- DON'T output the entire HTML for a web page. The application container (specified in the App Module Configuration) will be placed within the content area of the page.
- The CSS for the application should be bundled into a single .css file and hosted on another web site.
- There is no way to upload the file to the Drupal server.
- We recommend using a system like BEM for styling specific elements of your app
- The CSS should NOT interfere with other classes on the web site.
- The CSS SHOULD NOT define default element styles (e.g.
a { color: blue; }
)
{
"drupalConfig": {
"appName": "your-apps-name-here",
"rootId": "NCI-app-root",
"initFnName": "window.appModuleInit",
"appCssUri": "https://someserver/app-name/app-name.vX.Y.Z.css",
"appJsUri": "https://someserver/app-name/app-name.vX.Y.Z.js",
"removeHeadElements" : [
...
],
"validAppPaths": [
".*"
]
},
"frontEndConfig": {
...This will be passed into the initialize function...
}
}
The config has two parts:
- drupalConfig -- this is configuration for Drupal to know how to load the app.
- frontEndConfig -- this is configuration for the app itself. This will be passed into the initialize method. (It will be combined with some other Drupal path information.) You can make this whatever you want.
The drupalConfig is made up of the following:
- appName -- This is a unique ID for your app. (e.g. 'glossary-app-doct') try and make multiple instances of the app have a unique name please.
NOTE: This must be appropriate for being the key of an array.
- rootId -- this is the ID of the div tag for this instance, and what will get passed into the initialize function.
- initFnName -- The full name of the init function, we assume the app' init function will be attached to the window, but please include that too.
- pathToCss -- This is the full URL to the CSS file for the app. Make sure it has a version number, and never update that asset. (Or caching issues will occur)
- pathToJs -- This is the full URL to the JS file for the app. Make sure it has a version number, and never update that asset. (Or caching issues will occur)
- removeHeadElements -- The Drupal head elements your module will handle and should not be generated by Drupal lest Google get the wrong information. This list maps to keys in $attachments['#attached']['html_head'], except for 'alternate' which will remove any elements. A key for the <title> tag has been added, 'title_tag'. We had added react-helmet attributes to tags so the app would not generate dupes, but at this point, just remove them and then have your app generate everywhere.
- validAppPaths -- This is a list of regular expressions that will ensure that your app has a route for that path. '/' is always allowed, so this is for any URL OTHER than '/'. If the requested path does not match, then a 404 is retured. The path is RELATIVE TO YOUR APP. So if the url of your app is /foo/bar and the route is /chicken/:someID, then enter "\/chicken\/.*". (NOTE: You need to escape backslashes in JSON)