Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

JEP Packageless

Gozala edited this page Apr 30, 2012 · 5 revisions

This page describes how module system will work in the future versions of add-on sdk.

Rationale

  • Packages seem to be too heavy weight.
  • Packages require tools like package managers to be useful.
  • Packages require central repositories for publishing.
  • Package identifiers / names may conflict and there for require implementing a conflict resolutions.
  • Modules are light & encourage minimalism.
  • Modules don't necessary require tools to be useful. ES.next uses URLs to code as an identifiers.
  • Modules don't need additional central repository, simple registries may be build to ease discovery of popular module URLs.
  • Modules are similar to script tags and that's what we have on the web today and what we'll have in a future

Add-on

Add-on is just a directory with a package descriptor and an entry point module. In a common case it has a following layout:

${ADDON}/package.json
       ./main.js
       ./icon.png
       ./test/all.js

Dependencies

Module may declare dependencies on other modules via require statements. Add-on sdk recognizes several types of dependencies:

Local

Idiomatic add-on code is authored in multiple modules that do one thing at a time. Some of these modules may be located near each other. Modules that can be referenced via relative path are considered local. All local module requirements IDs start with character .

require('./toolbar')
require('./toolbar/view')
require('../../outside/of/addon')

External

Code that is generic enough, to be useful outside of specific add-on, is better be shared with others. Such modules (typically third party libraries) may be placed in a specific location to be requireable. These modules can be required by a non relative require form.

require('fs')
require('streamer')
require('backbone/model')

Following requirement usually translates to:

require('./@modules/fs')
require('./@modules/fs')
require('./@modules/backbone/model')

If requirements are not discovered under appropriate paths they will be searched one level up:

require('../@modules/fs')
require('../@modules/fs')
require('../@modules/backbone/model')

Goin upwards until add-on root is reached.
Note: special @modules folder is exact equivalent of nodejs's node_modules and we may decide to go with a different name instead.

System

Modules that have external require form and are not discovered are considered system. Such modules are found either in the lib directory of the add-on sdk or are shipped with a platform itself. These modules have following forms:

require('panel')
require('tabs')
require('sdk/window/events')
require('devtools/scratchpad')

Single term system modules (ones that do not contain / character) are just high level SDK modules and represent just a convenience shortcuts for multi-term equivalents:

require('sdk/panel')        // panel -> sdk/panel
require('sdk/tabs')         // tabs  -> sdk/tabs
require('sdk/window/events')
require('devtools/scratchpad')

Also system module require form represents just a convenience form for loading modules relative to loader's baseURI. For add-on sdk add-ons it's equivalent of:

require('resource:///modules/sdk/panel.js')
require('resource:///modules/sdk/tabs.js')
require('resource:///modules/sdk/window/events.js')
require('resource:///modules/devtools/scratchpad.js')

Note: Unlike in nodejs, remote modules take precedence over system ones. This is intentional as new system add-ons may be added after add-on is installed, shadowing modules that add-on had dependency upon, would break it when users update application.

Special forms

Different tools may be build / used to help users organize dependencies. SDK will come with a built-in tool to make dependency management transparent for users. SDK will recognize distinct external require flavors to achieve that:

URLs

External dependencies that have form of http / https URLs (excluding http:// and https://) will be recognized and installed at build time to make them available at run-time:

 require('git.io/streamer')
require('raw.github.com/gist/1733262/d98dd3f854eed5deb129122e2459de10a5e609a0/recovery')

Note: Modules from associated URLs will be downloaded and to @modules directory at build time, so no fetch from remote servers will happen at run-time. This is somewhat equivalent of JS files in HTML app-cache manifest with a difference that SDK will download and update app-cache automatically for users.

Assets

Remote modules written for third party consumption may also depend on assets different from modules. Such dependencies may be declared via special require form that SDK will also be recognized by SDK and will be bundled with an add-on.

var iconURI = require('asset!./icon.png')

Note: Each asset will have to be declared as SDK won't parse html or alike to figure out non declared dependencies.

Backwards compatibility

Most of this changes are backwards compatible. While it may break some exotic require forms (like require('utils') meaning require('./utils')) it's still pretty trivial to fix those and we may even build tools to help migration.

Tools

While add-on sdk will come with a built-in tool that we believe will be a best match for most add-ons, we recognize it may not match all cases. There for we build infrastructure first that would allow users to write / choose alternative tools (npm comes in mind).