-
Notifications
You must be signed in to change notification settings - Fork 5
Wrapping
When you look at a Spaghetti module's generated JavaScript code, especially when it's already packaged into an application, it can look rather convoluted. This page explains the purpose and functioning of the multiple layers of wrapping around the compiled JavaScript code. Check the workflow page on how the steps follow each other.
When your Haxe or TypeScript code is compiled, the resulting JavaScript code is to be understood as the function body of a function returning the module implementation:
// lots of JavaScript stuff
var module = ...;
// lots more of JavaScript stuff
return module;
When you are writing code in Haxe or TypeScript, this is already taken care of by Spaghetti. But when you are writing a vanilla JS module, your final code should look like this, i.e. it must have a return
statement yielding the module implementation.
The module bundle's purpose is to put everything required to use your module in a single ZIP file. The JavaScript code defining the raw module is now wrapped in a function call such that we get this:
module(function(Spaghetti) {
// lots of JavaScript stuff
var module = ...;
// lots more of JavaScript stuff
return module;
})
Packaging is the operation that makes an executable JavaScript application out of your modules.
The Spaghetti
parameter of the anonymous function passed to the bundled JavaScript is the way for the module code to interact with the outside world. It contains metadata about the module (name, version), the Spaghetti version used to build it, references to dependent modules, and some utility functions to access resources.
You can access the metadata and the resource-handling functions via a Spaghetti
class (in the root namespace) both in Haxe (Spaghetti.hx) and TypeScript (Spaghetti.ts). You should not need to access dependent module information from this object directly, as Spaghetti will generate proxy classes in your chosen language to access other modules.
{
getSpaghettiVersion: function() {
return "2.0";
},
getName: function(){
return "com.example.test";
},
getVersion: function() {
return "1.0";
},
getResourceUrl: function(resource) {
return baseUrl + resource;
},
"dependencies": {
// ...
}
}
Spaghetti wraps your module's returned object into a module data object that also contains the module version, and the Spaghetti version used to generate it:
{
"module": module(function (Spaghetti) {
// lots of JavaScript stuff
var module = ...;
// lots more of JavaScript stuff
return module;
}),
"version": "1.0",
"spaghettiVersion": "2.0"
}
In order to keep Spaghetti small, we rely on existing tools to load modules in an application. As there is no standard JavaScript module format yet, we have to support both AMD and CommonJS modules. Spaghetti modules need to be wrapped to be used by either of these systems.
For AMD the module gets wrapped into something like this:
define(["require", "com.example.alma", "com.example.bela"], function() {
var dependencies = arguments;
var Spaghetti = {
"modules": {
"com.example.alma":dependencies[1],
"com.example.bela":dependencies[2]
},
// ...
};
// ...
return {
"module": module(function (Spaghetti) {
// lots of JavaScript stuff
var module = ...;
// lots more of JavaScript stuff
return module;
}),
"version": "1.0",
"spaghettiVersion": "2.0"
};
});
For CommonJS it looks something similar to this:
var Spaghetti = {
"modules": {
"com.example.alma":require("com.example.alma"),
"com.example.bela":require("com.example.bela")
},
// ...
};
// ...
module.exports = {
"module": module(function (Spaghetti) {
// lots of JavaScript stuff
var module = ...;
// lots more of JavaScript stuff
return module;
}),
"version": "1.0",
"spaghettiVersion": "2.0"
};