-
Notifications
You must be signed in to change notification settings - Fork 263
JEP Packageless
This page describes how package-less SDK and may look like & steps required to get there.
- Packages seem to be too heavy weight.
- Packages require tools like package managers.
- Packages require repositories for publishing them.
- Package identifiers / names may conflict with each other.
- Modules are light & encourage minimalism.
- Modules don't require much tools since they are just URLs to actual code.
- Modules don't need central repository, web is the a one.
- Modules are similar to script tags and that's [what we'll have on the web] (http://wiki.ecmascript.org/doku.php?id=harmony:modules)
Add-on is just a directory with a package descriptor and an entry point module in it. In a common case this will look as follows:
${pwd}/package.json
./main.js
./icon.png
./test/all.js
Module may express it's dependencies via require
statements. SDK will
recognize following types of dependencies:
System modules IDs have a special require form that starts with @
character.
require("@[${name}/]${path}[.js][;${version}]")
-
${name}
is a unique module group identifier. As firefox features will be implemented using SDK, such groups can be created for feature specific APIs. For convenience${name}/
can be omitted, in which case default group"sdk"
will be used. -
${path}
is a module file path with in a group. -
${version}
is a string like1.5
. Versions suffix is just a convention that SDK MAY recognize in order to allow smoother transition from deprecated APIs.
require('@tabs')
require('@sdk/window/events')
require('@devtools/scratchpad')
require('@panel;1.5')
System modules intentionally have a visually distinct form and independent namespace:
- To signify the fact that such module are provided by a runtime & may not even have associated JS file.
- Having distinct namespace avoids conflicts with other dependencies which would have introduced room for surprises. With shared namespace either system or non-system module would have win the conflict, which is not problem free in both cases. System wins approach used by nodejs is not well suited for SDK, since deployment platform (Firefox) is very different, it may changes and introduce conflicting modules in a future releases causing add-on breakage. Non-system wins approach is also problematic, since it may be confusing for people coming from nodejs, in addition nested dependencies may shadow system modules without users knowledge or a way to load system modules.
- SDK has no way of knowing what will be available in the deployment runtime, while for system modules assumption that module is shipped with runtime is not-comforting sharing same namespace with other types of modules will SDK unable to catch missing dependencies as they will automatically be assumed to be shipped with a runtime.
-
@
prefix intentionally replicates harmony's form:
module stdlib at '@std'; // => var stdlib = require('@std')
Addons code may be authored in multiple modules located near each other.
This type of modules, or more explicitly, modules that can be referenced
via relative path are considered as local. All local module requirements
IDs start with .
character ('./foo', '../bar'
):
require('./toolbar')
require('./toolbar/view')
require('../../outside/of/addon')
Modules are all about sharing reusable pieces of code. Most of the
reusable code does not needs to be in core for add-on's to use it.
Dependency on such third party developed modules / libraries are
considered as external (as it's not part of system or add-on code).
These modules are also visually distinct from other forms as they
don't start with @
or .
characters:
require('fs')
require('streamer')
require('backbone/model')
Multiple different tools may be used in order to organize external dependencies. SDK will come with have built-in tool to will make dependency management seamless for external dependencies that will have a distinct forms:
External dependencies that have form of http / https URLs (for
convenience http://
and https://
may be omitted) will be
recognized by an SDK and instilled at build time so that they
will be requireable at runtime:
require('http://git.io/streamer.js') // => require('git.io/streamer')
require('raw.github.com/gist/1733262/d98dd3f854eed5deb129122e2459de10a5e609a0/recovery')
Not that modules are not fetched from the URLs at runtime, those modules are bundled with add-on during build time and are somewhat equivalent of JS files in HTML app-cache manifest. Also this form intentionally resembles on from Harmony.
Remote modules written for third party consumption may depend on other assets. Such dependencies may be declared via special require form that SDK will recognize and bundle with an add-on.
var iconURI = require('asset!./icon.png')
Add-on may be build by running cfx xpi
command from an add-on directory.
When XPI is build all .js
files in ${pwd}
and it's nested directories
(except ${pwd}/test/
and ${pwd}/@modules/
) will be included into XPI
in exact same layout as presented on filesystem. In addition ${pwd}/data/
${pwd}/icon.png
and ${pwd}/index.html
will be included
System modules in a future will be shipped with a firefox and will directly map to an associated resource URIs (this URI mapping is hypothetical and may end up slightly different in practice):
@${name}/${path/to}[;${version}] => resource:///commonjs/${name}[;${version}]/${path/to}.js
require('@tabs') // require('resource:///commonjs/sdk/tabs.js')
require('@sdk/window/events') // require('resource:///commonjs/sdk/window/events.js')
require('@devtools/scratchpad') // require('resource:///commonjs/devtools/scratchpad.js')
require('@panel;1.5') // require('resource:///commonjs/sdk;1.5/panel.js')
Until then standard library modules will be included into XPI and will be available under special URIs:
require('@tabs') // require('resource://jid/@modules/@sdk/tabs.js')
require('@sdk/window/events') // require('resource://jid/@modules/@sdk/window/events.js')
Note: System modules are copied to a special @modules
folder along with
other dependencies. Also, they won't conflict with other dependencies since
they have distinct @
prefix.
All the local modules (any file with .js
extension in the add-on directory
and it's nested directories except ${pwd}/test/
and ${pwd}/@modules/
) are
included in a xpi with a same layout as presented in the source directory.
These files will be mapped to an associated resource URIs:
require('./foo') // => require('resource://${jid}/foo.js')
require('./foo/bar') // => require('resource://${jid}/foo/bar.js')
require('../../bla') // => require('resource://${jid}/@modules/__/__/bla.js')
Local modules that are out of the add-on folder will be copied into special
@modules
directory. And path will be transformed as shown in example
above.
External dependencies are also included into XPI as long as they are located
under the special @modules
folder:
require('fs') // => require('resource://${jid}/@modules/fs.js')
require('underscorejs.org/underscore') // => require('resource://${jid}/@modules/underscorejs.org/underscore.js')
External dependencies that have special forms supported by SDK will be
automatically downloaded and correctly organized in special @modules
folder:
// Special
require('http://underscorejs.org/underscore.js') // => require('underscorejs.org/underscore')
Alternatively users may choose to use npm like
package managers for more complicated cases to organizing dependencies
in a special @modules
directory.
- Move all SDK modules into
${SDK}/lib/
- Make all SDK library modules require-able as follows:
require("@${name}/${path}[.js][;${version}]")
require('@addon/panel;1.4')
require('@addon/system')
-
Make it possible to omit
@
in which case cfx will perform search:-
${SDK}/lib/
(normalizationpanel -> @panel
) - If require term starts with
addon-kit/
orapi-utils/
it will be stripped out and searched again in${SDK}/lib/
(normalizationapi-utils/system - @system
) - In
${PWD}
(normalizationfoo -> ./foo
) - In folders one level up to current one (to support case of packages folder ?)
-
If module is found print out deprecation warning explaining the normalization and encouraging use of new standard.
- Support third party module dependencies by locating it in a
@modules
folder. Requirement in form ofrequire(!host.com/module/path')
will have to be located under the following location:${ADDON}/@modules/!host.com/path/to/module.js
If requirement is not found it will be downloaded to:
${ADDON}/@modules/!host.com/path/to/module.js
from one of the following locations:
Note: That that if require term contains protocol scheme http!git.io/streamer
then
discovery will be limited to given protocol only.
- Support third party assets by locating them in a special
@modules
folder or by downloading them there in a same exact way as in case of modules.