v2 Migration Guide
In advance of the release of version 2, we are releasing this guide in order to give third-party developers a chance to bring their plugins and themes up-to-date. In the successive sections below, we will outline the breaking change or new best-practice, and the steps to migrate, along with a live example.
This blog post is the third in a series of posts related to the release of NodeBB v2
We tried to plan out this release in such a way that any breaking changes would be minimized. There is a chance that your theme or plugin will just work out-of-the-box, or with minimal changes.
We've tried to list any gotchas and necessary changes in this article, but please do let us know if you encounter one we haven't seen yet.
Migrate AMD modules from scripts
and acpScripts
to modules
(breaking change 🚨)
Standard practice in v1.x was to write a page-specific client-side script or admin script as an AMD module, and bundle them with the minified files served to the browser. We now recommend that the files be defined in the modules
property in package.json
so that they can be bundled as necessary, or dynamically loaded otherwise.
Note:These scripts can continue to be written in AMD-style, as it is supported by Webpack.
Live example (nodebb-theme-persona)
The persona theme contains two page-specific scripts, one loaded on the user settings page, and another loaded in the ACP settings page.
- The scripts are removed from the
scripts
andacpScripts
sections, and added tomodules
- Note that the key for these modules matches the template name, and that it is prepended with
../
— this is necessary because they are not added to the modules folder - Modules can continue to be written in AMD-style, this is handled transparently by Webpack.
Migrate third-party modules to use npm dependencies, if available (best practice)
Any third-party modules are no longer recommended to be used in the modules
section of plugin.json
. Instead, install them directly from npm if available, and just import them into your client-side code.
There are some savings to be had by no longer appending third-party code into the main bundle. Webpack can choose to either bundle it in, or dynamically load it as-needed.
Additionally, having a dependency maintained in your package.json
allows for better version control and updates, without needing to modify copy-pasted code directly in your repository.
Live example (nodebb-plugin-markdown)
The markdown plugin relies on highlightjs
as a dependency in order to highlight code written in code blocks.
- The plugin is now installed directly from npm, instead of the CDN variant, and
- Instead of
require
-ing them as an AMD module, they are now imported in by Webpack
Live example (nodebb-plugin-2factor)
The 2factor plugin relies on @github/webauthn-json to properly encode and verify key registrations and challenges.
- The script is removed from scripts configuration (in this case, the package was already installed as a dependency)
- The dependency is imported directly by Webpack
Require.js dependency removed (breaking change 🚨)
While modules and client-side scripts can continue to be written in AMD-style (with define
and require
calls), you will no longer be able to use the AMD-style require
in widgets or the browser console to get modules. By and large, this will not affect most installations/plugins.
A helper method app.require
is added to require modules dynamically. app.require
can be used in widgets or custom javascript tab in the ACP to require modules.
Before
require(['alerts'], function (alerts) {}); // single module
require(['alerts', 'translator'], function (alerts, translator) {}); // multiple modules
After
const alerts = await app.require('alerts'); // single module
const [alerts, translator] = await app.require(['alerts', 'translator']); // multiple modules
Update try_files
directive in nginx config (best practice)
Power users may opt to have a reverse proxy serve the built assets directly, instead of going through NodeBB.
Several paths are included in this configuration, but you no longer need to have your reverse proxy handle the /plugins
path prefix.
Remove this block
location /plugins/ {
root /path/to/nodebb/build/public/;
try_files $uri @nodebb;
}
Update nbbpm.compatibility
in third-party themes and plugins (best practice)
In order to ensure that plugins and themes updated for NodeBB v2.x are not accidentally installed in v1.x installations, you should update the nbbpm.compatibility
string in your package.json
to at least ^2.0.0
.
Keep in mind that after updating your plugin, it might still actually be compatible with NodeBB v1.x. Whether your plugin continues to be backwards compatible does not depend on whether you needed to apply the breaking changes in this guide. A breaking change just means that change is needed to be forwards compatible.
Change
{ ... "nbbpm": { - "compatibility": "^1.17.4" + "compatibility": "^2.0.0" } ... }
translator
, utils
, and helpers
library restrictions (breaking change 🚨)
The following three libraries were used on both the server and client side:
utils
(basic utility functions)translator
(localisation methods)helpers
(NodeBB’s set of built-in Benchpress helpers)
In NodeBB v1.x, you were able to require()
them from the server-side, even though they were contained in the client-side directories.
As of NodeBB v2.x, you will need to require()
from the server-side src/
directory instead:
src/utils.js
src/translator.js
src/helpers.js
Change
- const utils = require.main.require('./public/src/utils'); + const utils = require.main.require('./src/utils');
- const translator = require.main.require('./public/src/modules/translator'); + const translator = require.main.require('./src/translator');
- const helpers = require.main.require('./public/src/modules/helpers'); + const helpers = require.main.require('./src/helpers');
ACP Privileges table template change (breaking change 🚨)
If you maintain a theme that modifies one of the following files:
admin/partials/privileges/global.tpl
admin/partials/privileges/category.tpl
The format of the privilege labels has changed from an array of objects to a simpler array of language keys (strings).
Apply the changeset to the right.
Change
- {privileges.labels.users.name} + {@value}
Live Example
Core maintains templates for the ACP privilege page, the diff for this particular changeset can be found here.
Sorted Lists client-side hook renamed
A client-side hook used in the sorted-lists module has been renamed from action:settings.sorted-list.loaded
to action:settings.sorted-list.itemLoaded
.
A new action hook by the same name is still called, but only once at the very end, when all sorted list items have been parsed and inserted into the DOM.
Change
hook.on('action:settings.sorted-list.loadedItemLoaded', ...
Top and bottom padding removed from body element (breaking change 🚨)
In v1.19.x and earlier, the body element had a 70px top padding, which was missing on mobile. This discrepancy meant that styles for mobile needed to account for a missing 70px in their positioning.
The padding is now removed, and the #panel element now contains a top padding corresponding to the dynamically generated height of the header bar(s).
Live Example
The Persona theme contains the logic for calculating the panel-offset. As part of this change, some of the styles depending on the old 70px offset needed to be adjusted. Some additional styles needed to be removed as they were no longer required as a single common style for both desktop and mobile was applicable.
utils.params()
refactored
The common utility method .params()
has been refactored in order to use browser and node built-ins, instead of executing its own logic.
- The
skipToType
anddisableToType
options have now been removed - A new option —
full
— has been added, which will cause the method to return anURLSearchParams
object instead of a plain Object
No Example Available
There are no pre-existing usages of the .params()
method — that we know of — that use either of the deprecated options.
This commit shows how to use the new full
option to return something other than a plain Object.
Notes
- Cover Photo by Dan-Cristian Pădureț on Unsplash