jQuip is a lightweight script loading library.
You have following options to get the library:
- Download the latest release
- Clone the repo,
git clone git://github.com/zebzhao/jQuip.git
. - Install with Bower:
bower install jQuip
- Defining modules
- Loading modules
- Partial module definition
- Initializing modules
- Defining Module Methods
- Special Properties
- Standard modules
- Jasmine Testing Support
Start by including the file in your main HTML file.
For debugging
<script src="jquip.debug.js" type="text/javascript"></script>
For production
<script src="jquip.min.js" type="text/javascript"></script>
Modules and can contain definitions of functions and variables, also provides entry point after module dependencies are loaded.
$Q.module('mymodule')
.import('https://example.com/random.css')
.import('path/to/file/random.js')
.require('dependency')
To access the module one can use a function call, or access it through a variable:
$Q.module('myModule')
// which is the same as:
$Q.modules.myModule
Modules can be loaded and then initialized. A module can be loaded from by using:
$Q.import(url).then(callback);
This will append either a <script>
or <link>
tag depending on if a '.js' file is included.
When a module is defined, its __new__
method is automatically immediately called.
Note that self
refers to the module (same as $Q.module.mymodule
in the case below).
$Q.module('myModule')
.__new__(function(self) {
// Do stuff immediately.
// ...
});
Note that multiple __new__
callback functions can be defined, and they will be called in the defined order:
$Q.module('myModule')
.__new__(function(self) {
console.log('I am first')
})
.__new__(function(self) {
console.log('I am second')
});
// A module defined again will refer to the original defined module.
// This allows module definitions to be split between many files.
$Q.module('mymodule')
.__new__(function(self) {
console.log('I am third');
});
After a module is loaded, it needs to be initialized. Initializing will load all dependencies. The initialization process has 2 steps:
- Import all files defined by
.import
. - After imports are successful, initialize required modules defined by
.require
.
To initialize a module manually:
$Q.module('myModule');
// This can be called anywhere after the module definition.
$Q.initialize('myModule');
To initialize a module as a requirement by another module initialization process:
$Q.module('child')
.import('path/to/modules/mother.js')
.require('mother');
When a module is initialized, its __init__
method is automatically called.
The __init__
method(s) are called after dependencies are loaded.
$Q.module('mymodule')
.__init__(function(self) {
console.log('I am initialized')
});
Similarly to __new__
, when defining multiple __init__
callbacks, they are called in the order of definition.
$Q.module('mymodule')
.__init__(function(self) {
self.a = 5;
})
.__init__(function(self) {
self.a++;
console.log(self.a); // Outputs 6
});
When a module is initialized, its dependencies will be loaded.
$Q.module('mymodule')
.import('jquery.min.js')
.import('angular.min.js')
.import('https://example.com/script.js');
// Dependencies will be loaded asynchronously (all at the same time).
$Q.initialize('mymodule');
An example on requiring modules. In the scenario below that you have 1 module that relies on another module:
// Inside mother.module.js
$Q.module('mother')
.__init__(function(self) {
console.log('I will be initialized and loaded FIRST!')
});
// Inside child.module.js
$Q.module('child')
.import('mother.module.js')
.require('mother')
.__init__(function(self) {
console.log('I am initialized AFTER mother.')
});
In the case that your submodule has very large dependencies and needs to be loaded in a future point in time:
// Inside bigmodule.module.js
$Q.module('bigModule')
.import('very-large-file.js')
.__init__(function(self) {
// do stuff
});
// Inside mymodule.module.js
$Q.module('myModule')
.import('bigmodule.module.js')
.__init__(function(self) {
// Load big module dependencies after 1s
setTimeout(function() {
$Q.initialize('bigModule');
}, 1000);
});
Methods can be defined in a module in the following way:
$Q.module('myModule')
.def({
testMethod1: function(self, string) {
}),
callsMethod1: function(self, string) {
self.testMethod1(string);
});
});
$Q.modules['mymodule'].callsMethod1('Awesome');
Note that the methods are defined on the module instance and injected with a self
argument.
The self
argument is a reference to the module singleton instance.
Additional properties that are defined on top of module instances.
__name__
- name of module defined bymodule(name)
__state__
-'loading'
or'loaded'
orundefined
__initialized__
- true only when the module has finished initializing
jQuip officially supports Jasmine 2.0 Testing.
Sometimes you want to use CDNs, but this introduces problems when testing locally on a headless browser. jQuip solves this issue by letting dynamic replacement of external dependencies with local ones during testing.
Here's an example of how this works:
jQuip.prefix = '/home/user/project'; // Tells the headless browser to local path
jQuip.prefix = 'C://path/to/project/folder'; // For Windows
describe('mymodule', function () {
beforeEach(function(done) {
var self = this;
// This will replace any scripts loading www.example.com/external.js with /home/user/project/lib/external.js
$Q.mockDependencies({
"www.example.com/external.js": "lib/external.js"
});
// Wait till module has loaded asynchronously
$Q.initialize('myModule').then(function(myModule) {
self.myModule = myModule;
done();
});
});
First of all, install Node. We use Gulp to build jQuip. If you haven't used Gulp before, you need to install the gulp
package as a global install.
npm install --global gulp
If you haven't done so already, clone the jQuip git repo.
git clone git://github.com/zebzhao/jQuip.git
Install the Node dependencies.
npm install
Run gulp
to build and minify the release.
gulp
gulp build
gulp build-debug
The built version will be put in the same folder as jquip.min.js
and jquip.debug.js
.
All tests are contained in the tests
folder. Tests can be run using npm test
.
This library aims for test 80%+ coverage. Since some functions cannot be tested such as Ajax methods, 100% coverage is not possible.
This project follows the GitFlow branching model. The master
branch always reflects a production-ready state while the latest development is taking place in the develop
branch.
Each time you want to work on a fix or a new feature, create a new branch based on the develop
branch: git checkout -b BRANCH_NAME develop
. Only pull requests to the develop
branch will be merged.
In some browsers, when a script HTTP request fails, no error will be thrown. You can tell if a script failed to load by checking for missing loaded messages in the browser console.