In version 1.12 we changed the structure of the SDK, removing the idea of “packages” and relocating all the SDK’s modules under the “lib” directory. This changed, and greatly simplified, the
require() syntax used to import modules.
This change would break backwards compatibility, so we implemented a shim to ensure that most common usages of
require() would be unaffected by the change. Even so, it’s important to update to the new form when you can, and to use the new form for new code.
With the SDK, you import objects from other modules using the
require() statement. This is how you use modules supplied by the SDK itself, like page-mod and panel, and how you use modules supplied by the wider community, like
toolbarbuttons. You can also structure your own code into separate modules, then use
require() to import objects from these local modules.
require() statement takes a single argument, which tells the SDK which module you need. In version 1.12, we changed the way the SDK interprets this argument.
require() work before?
Before version 1.12 of the SDK, the algorithm used to find modules was based on the idea of “packages”. A package is a collection of modules. Most of the modules in the SDK belonged to either the
addon-kit or the
api-utils packages. An add-on was itself a package, and community-developed modules like
menuitems were delivered in packages of their own. A package declares a dependency on another packages, if it wants to use modules from that package.
The module search algorithm was pretty complicated, but in its most basic form: the SDK would build a list of packages, always starting with the package that contained the module doing the
require() and followed by the dependencies of that package. The SDK would treat the argument to
require() as a path to a module file, and would search all packages in its list for a matching file, starting at the package’s “lib” directory.
So if an add-on called “my-addon” declares one additional dependency, on the “menuitems” package, it would have four packages in its search list:
["my-addon", "addon-kit", "api-utils", "menuitems"]
If a module in “my-addon” contains a require statement like:
The SDK will search the following paths in order:
my-addon/lib/some-module.js addon-kit/lib/some-module.js api-utils/lib/some-module.js menuitems/lib/some-module.js
This means that add-ons can import modules from all four packages using only the module name as an argument:
require("my-local-module"); // load from my-addon require("panel"); // load from addon-kit require("match-pattern"); // load from api-utils require("menuitems"); // load from menuitems
This seems like a nice feature, but it’s tricky, because you can’t tell just from looking at a
require() statement which module will be imported. If module names clash, unexpected modules might be imported.
require() work now?
In version 1.12 of the SDK we removed the concept of “packages”. All SDK modules were relocated under a new “lib” directory directly under the SDK root. Along with this, a much simpler algorithm for importing from modules was implemented:
- to import objects from SDK modules, specify the full path to the module starting from, but not including, the “lib” directory:
- to import objects from modules in your add-on, specify a path relative to the importing module:
Obviously, this change would break every SDK add-on in existence. To prevent this we added a file, “mapping.json”, which maps old-style
require() statements to their new counterparts. For example:
With this in place, most users of the SDK are unaffected by the change.
Although “mapping.json” means existing add-ons will still work without needing an update, it’s important to update your code to the new style when you can, and to use the new style in future. For one thing, any new modules we add, like IndexedDB, won’t be added to “mappings.json”, so you’ll have to use the new style if you want to use these modules.
Eventually, you’ll be able to import objects from modules outside the SDK by passing a URL to
require(), but we don’t support that, yet. In the meantime there are two alternative approaches:
- you can still use third-party packages, copying them into the “packages” directory under the SDK root and declaring your dependency on them, as the SDK tutorial outlines.
- you can copy the modules you need to use (and any additional modules that these modules
require()) into your add-on, and treat them as local modules, using relative paths in
require(). But if you do this you may need to rewrite any
require()statements inside these modules to be in line with the new form.