Requirejs has been popular for a long time, and we also intend to use it in our projects. It provides the following features:
- Declaring dependencies between different JS files
- Can load JS Library on demand, in parallel, in time delay
- Allows our code to be organized in a modular way
It's not complicated at first.
Introduction of Requirejs in HTML
In HTML, add such a <script>
label:
<script src="/path/to/require.js" data-main="/path/to/app/config.js"></script>
Usually using Requirejs, we only need to import Requirejs, do not need to explicitly import the other JS library, because this work will be given to Requirejs to do.
data-main
the property tells Requirejs: When you're done downloading, load the real portal file right away. It is typically used to configure REQUIREJS and to load real program modules.
Configuring Requirejs in Config.js
config.js
are usually used to do two things:
- Configure Requirejs such as which modules are used in the project, and what the file path is
- Loading Program Main module
requirejs.config({ ‘/public/js‘, paths: { app: ‘app‘ }});requirejs([‘app‘], function(app) { app.hello();});
In paths
, we declare a app
module named, and its corresponding JS file address. In the most ideal case, app.js
the content should be defined using the Requirejs way to define the module:
function() { return { hello: function() { alert("hello, app~"); } }});
Here define
is the function provided by Requirejs. Requirejs provides a total of two global variables:
- Requirejs/require: Used to configure the Requirejs and load the Ingress module. If one of the names is used by another library, we can use the other
- Define: Defining a Module
It is also possible to take a require
dependent module and then invoke its method:
define(["require"], function(require) { var cssUrl = require.toUrl("./style.css");});
Rely on a library that does not use the Requirejs method
The preceding code is the ideal case, that is, the dependent JS file, which is used in define(...)
such a way to organize the code. If it doesn't work this way, what happens?
Like this hello.js
:
function hello() { alert("hello, world~");}
It defines a function in the most common way, can we use it in Requirejs?
First look at the following code that does not work correctly:
requirejs.config({ ‘/public/js‘, paths: { hello: ‘hello‘ }});requirejs([‘hello‘], function(hello) { hello();});
This code will error, prompt:
undefined is not a function
The reason is that hello()
this hello
is a last call undefined
. This shows that although we rely on a JS library (it will be loaded), Requirejs cannot get the object that represents it to be injected into our use.
In this case, we would use a shim
global variable in a dependency to be exposed to Requirejs as a reference to the module itself.
requirejs.config({ ‘/public/js‘, paths: { hello: ‘hello‘ }, shim: { hello: { exports: ‘hello‘ } }});requirejs([‘hello‘], function(hello) { hello();});
It's normal to run again.
exports: ‘hello‘
in the above code hello
, we hello.js
define the functions in the hello
. When we function hello() {}
define a function in the way we use it, it is globally available. If we choose export
to give it to Requirejs, then we can get a reference to the function when our code is dependent on hello
the module hello
.
So: exports
you can expose one of the global variables in a non-Requirejs way code as a reference to that module.
Exposing Multiple variables: init
But what if I want to expose multiple global variables at once? For example, hello.js
the definition is actually:
function hello() { alert("hello, world~");}function hello2() { alert("hello, world, again~");}
It defines two functions, and I want two of them.
This is no longer available exports
and must be replaced by a init
function:
requirejs.config({ ‘/public/js‘, paths: { hello: ‘hello‘ }, shim: { hello: { init: function() { return { hello: hello, hello2: hello2 } } } }});requirejs([‘hello‘], function(hello) { hello.hello1(); hello.hello2();});
exports
init
It is ignored when it is present with the same time exports
.
Non-master and master modules
I met a question that took me a long time: why should I use it jquery
to rely on jquery and not other names?
For example, the following code:
requirejs.config({ ‘/public/js‘, paths: { myjquery: ‘lib/jquery/jquery‘ }});requirejs([‘myjquery‘], function(jq) { alert(jq);});
It will prompt me:
is undefined
But I just changed my name:
requirejs.config({ ‘/public/js‘, paths: { jquery: ‘lib/jquery/jquery‘ }});requirejs([‘jquery‘], function(jq) { alert(jq);});
Everything is normal, can print out jq
the corresponding object.
Why? I still don't know where the problem is.
The module with the main
Often researched and found that the original has been defined in jquery:
define(‘jquery‘, [], function() { ... });
It here is define
different from what we saw earlier, it is the app.js
first parameter ‘jquery‘
, indicating that the current module has a name jquery
, it is already a master, can only belong jquery
to .
So when we use another name:
myjquery: ‘lib/jquery/jquery‘
To refer to this library, it will find that the jquery.js
module name in the declaration jquery
and I use the module name myjquery
can not be assigned to it myjquery
, so myjquery
the value is undefined
.
So when we use a third party, be sure to notice whether it declares a definite module name.
Non-master Module
If we don't specify the module name, it looks like this:
function() { ...});
Then it is a module with no master. We can requirejs.config
use any one of the module names to reference it in. In this case, let's make our name very free, most of the modules are non-master.
Why some have the Lord, some have no master
As you can see, the non-master module is very free to use, why do some libraries (jquery, underscore) declare themselves as having a master?
By some accounts, this is done for performance reasons. Because like jquery
underscore
this, the base library is often relied upon by other libraries. If declared as non-master, then other libraries are likely to have different module names, so that when we use them, we may load jquery/underscore multiple times.
Instead of declaring them as having a master, then all modules can only refer to them using the same name, so that the system will only load them once.
Dig a corner.
For the main module, we also have a way to dig a corner: not as a module that satisfies the REQUIREJS specification, but as a normal JS library, and then shim
export their defined global variables in.
requirejs.config({ ‘/public/js‘, paths: { myjquery: ‘lib/jquery/jquery‘ }, shim: { myjquery: { exports: ‘jQuery‘ } }});requirejs([‘myjquery‘], function(jq) { alert(jq);});
So by exposing jQuery
this global variable myjquery
, we can use it normally.
But we have absolutely no need to dig this corner, because for us it doesn't seem to do any good.
How to completely keep jquery from polluting the global $
In the previous ways of referencing jquery, although we can get a reference to the jquery module in a modular way, we can still use global variables and anywhere else jQuery
$
. Is there a way to make jquery completely non-polluting these two variables?
Calling Noconflict (invalid) in Init
First try one of the simplest but not working ways:
requirejs.config({ ‘/public/js‘, paths: { jquery: ‘lib/jquery/jquery‘ }, shim: { jquery: { init: function() { return jQuery.noConflict(true); } } }});requirejs([‘jquery‘], function(jq) { alert($);});
This is not working, or will pop up a non- undefined
value. The reason for this is that once Requirejs jquery
has found the module that belongs to the module name, it ignores the shim
corresponding content in. In other words, the following code is completely out of execution:
jquery: { init: function() { return jQuery.noConflict(true); }}
Use another name
If we use jquery in a corner-digging way, here's the following:
requirejs.config({ ‘/public/js‘, paths: { myjquery: ‘lib/jquery/jquery‘ }, shim: { myjquery: { init: function() { return jQuery.noConflict(true); } } }});requirejs([‘myjquery‘], function(jq) { alert($);});
This is really effective, then the one that comes out undefined
. But the problem with this is that if we refer to a third-party library or use it jquery
to refer to jquery, we will report the "Module not found" error.
We either have to manually modify the code of the third-party modules or provide them with a jquery
module. But with the latter, the global variables $
may be contaminated again.
Using map
If we have a way to keep jquery
This module name in the meantime, there is a chance to invoke jQuery.noConflict(true)
it.
We can define a module again just to execute this code:
Jquery-private.js
define([‘jquery‘], function(jq) { return jQuery.noConflict(true);});
Then call it at the entrance:
requirejs.config({ baseUrl: ‘/public/js‘, paths: { jquery: ‘lib/jquery/jquery‘, ‘jquery-private‘: ‘jquery-private‘ }});requirejs([‘jquery-private‘, ‘jquery‘], function() { alert($);});
This is true, but there is still a problem: we must be careful to ensure that we are jquery-private
always the first to be relied upon, so that it has the opportunity to call the jQuery.noConflict(true)
global variables and clear them as soon as possible $
jQuery
. This guarantee can only be relied on by people, very unreliable.
We can then introduce map
the configuration to solve this problem once and for all:
requirejs.config({ ‘/public/js‘, paths: { jquery: ‘lib/jquery/jquery‘, ‘jquery-private‘: ‘jquery-private‘ }, map: { ‘*‘: { ‘jquery‘: ‘jquery-private‘}, ‘jquery-private‘: { ‘jquery‘: ‘jquery‘} }});requirejs([‘jquery‘], function(jq) { alert($);});
This solves the previous problem: in any dependency other than Jquery-private, the module name can be used directly, and is jqurey
always replaced with a dependency on the pair jquery-private
, making it the first to be executed.
Http://www.tuicool.com/articles/jam2Anv
Quick Understanding Requirejs