Quick Understanding Requirejs

Source: Internet
Author: User

Requirejs has been popular for a long time, and we also intend to use it in our projects. It provides the following features:

    1. Declaring dependencies between different JS files
    2. Can load JS Library on demand, in parallel, in time delay
    3. 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-mainthe 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.jsare usually used to do two things:

    1. Configure Requirejs such as which modules are used in the project, and what the file path is
    2. 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:

    1. 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
    2. 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 to jquery .

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.

Quick Understanding Requirejs

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.