XPJS Components Proposal

Warning: The content of this article may be out of date. This is a proposal for a system that got implemented, but it may differ from the actual implementation. See the status document for more recent info on the status of this proposal.

Draft 1.0

What are XPJS Components?

XPJS Components is a (cheesy) name for a system to support xpcom components written in JavaScript. Now, you might ask: "Isn't that what XPConnect does?" And I would answer that XPConnect is necessary, but not sufficient to the task. XPConnect provides the mechanisms for communication between native and JS xpcom components, but it does not provide all of the infrastructure to register and instantiate JS components outside of the limitations of the browser window. XPJS will provide that infrastructure.

So what does this mean?

The XPJS Component system will support implementing xpcom services, factories, and components in JavaScript. It will support service and factory registration. These components will be independent of web content and browser windows. They will run from the user's disk just like native components.

How will it work?

The overriding principle is to make this work as much like native components as possible. XJS Components will 'live' in .js files. Just as with native component modules each of these .js files will be expected to have the functions:

  • <tt>NSRegisterSelf</tt>
  • <tt>NSGetFactory</tt>
  • <tt>NSUnregisterSelf (optional)</tt>
  • <tt>NSCanUnload (optional)</tt>

Each .js file might implement one or more components.

We will have one native module - called the XPJSManager - which holds this system together. The XPJSManager is in charge of loading these .js files, helping them register themselves, and acting as an intermediary between the xpcom component manager and the JS code.

XJS Components are not run in browser windows. Each .js file (let's call it a module) is started up and run in the context of a relatively 'raw' JS global object. The standard (non-DOM) JS classes will be available. The xpconnect Components object will be available. And some additional yet to be defined objects may be available. The xpconnect Components object allows access to the whole repository of native and JS xpcom components, so this is not as isolated an environment as it might at first sound.

A 'load' or 'import' function will also be provided to let the JS code import other .js files where libraries of code might be stored. This is akin to 'static' libraries. Accessing other components/services via xpcom/xpconnect is more akin to 'dynamic' libraries.

When a XPJS Component module is first installed - or at autoregistration time - the XPJSManager will load the .js file into a fresh JS environment, let its top level script run to do whatever initialization it wants to do, and then it will call the module's NSRegisterSelf function (passing the filespec of the .js file). At this point the module will use the (new) methods on the Components object to register itself with the component manager as a factory module for one or more classid or progid.

This registration function that the JS code calls (e.g. Components.RegisterComponentSpec) will be provided by the XPJSManager. The XPJSManager will receive this call from the JS code, store the mapping of clsid to .js filespec in the registry for its own use later, and then call the real component manager to do the registration. However, the XPJSManager will pass the component manager its *own* filespec.

So, at some future point some chunk of code will ask the component manager to create an object instance for some clsid (or progid). The component manager will load up the XPJSManager's module and call the native NSGetFactory it finds there. That native NSGetFactory function will check the information it stored in the registry to see that the JS factory for the given clsid is in a given .js file. It will load that .js file (if not already loaded) and call the NSGetFactory function.

Our friend XPConnect will convert the JS object returned from the JS module's NSGetFactory function into an xpcom object. The component manager (and anyone else with a reference to that factory) can then call the factory's CreateInstance method at will.

The JS module is free to implement factories and components and services that the factories construct on command. Any code anywhere and implemented in any language can get to these things via the component and service managers.

The XPJSManager is loosely in charge of the lifetime of each XPJS module. JavaScript is garbage collected and one can not force an object to be deleted or the compiled code to be unloaded [except by deleting the JSRuntime; i.e. erasing the entire JS universe]. In C if a module gets unloaded when there are still references to objects created by the module then a crash is likely to happen soon after. JS does not have this problem. If the XPJSManager is asked to trim itself back (by whatever means) it will call the NSCanUnload method (if present) on each module. It the module OKs it then the XPJSManager will release its root of the module's global object and release any hold over the objects in the module. Any subsequent requests from the component manager that would result in NSGetFactory calls into the module will force the XPJSManager to load up a new instance of the .js file and start over. So, these XPJS Component modules are safely unloadable, but have the power (like native modules) to veto any attempt.

So when will it be ready?

I was thinking that I'd get on this pretty soon. I think that it is all very straightforward.

Comments and suggestions welcome!

Original Document Information

Document Tags and Contributors

 Contributors to this page: teoli, Mgjbot, Pd, Jorend, Nickolay, George3
 Last updated by: Mgjbot,