Spring cleaning: changes to require and self in the SDK

Irakli recently posted a ‘Spring Cleaning’ todo list ( https://github.com/mozilla/addon-sdk/wiki/Spring-cleaning-2012 ) of changes we are proposing to make to the SDK in the next few months. While most of these changes deal with how the SDK is implemented and will not affect the behaviour of the top-level APIs, there are two specific changes that will change how the SDK behaves in specific circumstances.

Changes to require()

In the first case, the behaviour of the SDK’s require statement will be greatly simplified to support 3 explicit use cases: loading local modules via relative paths, loading module names from the SDK’s high level APIs, or loading via a dependency’s explicit path. Not only does this greatly simplify the implementation of the module loader, it will also allow us to make 3rd party module development and sharing much simpler. A nice side effect is that require will work exactly how it does in node.js.

The proposal clarifies the three styles to be used when requiring a module:

  1. Relative path for modules included in the add-on’s lib directory
    require('./utils/something')
            require('../foo/bar')
  2. Single term for high level SDK dependencies:
    require('panel')
            require('tabs')
  3. Complete require form for external dependencies:
    require('api-utils/functional')
            require('io/fs')
            require('package-name/module/path')

Once this change is made, require will raise warning for any deprecated require usage. Eventually support for older usage patterns for require will be removed.

Why are we doing this? The main goal is to remove ambiguity in how the argument you supply to require is resolved. Currently these patterns are supported, but will be deprecated:

   require('functional')
   require('fs')
   require('module/path')

In particular, the first example ( require('functional') ) currently means too many things:

   require('addon-kit/functional')
   require('api-utils/functional')
   require('./functional')
   require('io/functional')
   require('package-name/functional')

Changing to this more explicit require form makes us more compatible with other commonjs platforms like nodejs and also makes it distinction between high and low level APIs more obvious. While we will make our best efforts to keep high level APIs (ones that do not have `/` in require: require(‘panel’) ) backwards compatible at all times, we may change low level APIs when it makes sense.

Changes to self.data

In the second case, we will be changing how the SDK’s self module resolves the location of the data directory, specifically in the case where a statement like self.data.load is called from inside a package that is loaded in as a dependency in an add-on.

With the current implementation this code would try to load files from the package’s own data directory. In the proposed change we would instead load files from the add-ons main data directory.

Now, as far as we can tell this use of files in a package’s data directory is not a wide-spread practice, in fact Irakli could not find a single module on Builder that uses this behaviour. This is a breaking change to the SDK’s apis, however, but we think this particular use case is obscure.

As always, we’d love to hear your feedback on these changes and how they might affect you. We want to make sure we have your input before making changes such as these, and to ensure as much as possible that we do not break your add-ons as we improve the SDK.
I’ve also posted this info to the google user gorup for Jetpack, and we would appreciate we centralize discussion in that thread.