SeaJS tutorial series using SeaJS (ii)

  • 2020-03-30 02:11:06
  • OfStack

Download and install

To use SeaJS in your project, all you need to do is download sea-js and drop it somewhere in your project.
SeaJS project is hosted in the making, home page for https://github.com/seajs/seajs/. You can download sea-js (compressed) or sea-debug.js (uncompressed) from the build directory of its git library.
When the download is complete, place it in the appropriate location of the project, and then on the page. Script> When the tag is introduced, you can use SeaJS.

Basic SeaJS development principles

Before discussing the specific use of SeaJS, let's introduce the modularity concept and development principles of SeaJS.
The basic principle of developing JavaScript with SeaJS is that everything is a module. With the introduction of SeaJS, writing JavaScript code becomes writing module after module, and the concept of a module in SeaJS is somewhat similar to that of an object-oriented class -- a module can own data and methods, which can be defined as public or private, and which can be invoked by other modules.
In addition, each module should be defined in a separate js file, one for each module.
The writing and invocation of the module are described below.

Module definition and preparation

Module definition function define
SeaJS defines a module using the "define" function. Since there is no complete reference to define in the SeaJS documentation, I read the SeaJS source code and found that define can receive three parameters:


fn.define = function(id, deps, factory) {
    //code of function ... 
}

Above is an excerpt from the SeaJS source code, define can accept the parameters are module ID, dependent module array and factory function. After reading the source code, I found that the analytical rules of define for the number of different parameters are as follows:
If there is only one argument, assign the value to factory.
If there are two arguments, the second is assigned to the factory; The first one is assigned to deps if array, otherwise to id.
If there are three parameters, they are assigned to id, deps, and factory, respectively.
However, almost everywhere that defines is passed a factory function, including the official SeaJS example, similar to the following code:


define(function(require, exports, module) {
    //code of the module...
});

My personal suggestion is to follow the standard of the SeaJS official example and define the module with a parameter define. So what happens to id and deps?
Id is the identity string of a module, and when define has only one parameter, id is assigned by default to the absolute path of this js file. If the define module is used in the a.js file under example.com, the ID of this module will be assigned to http://example.com/a.js. It is not recommended to pass in the ID without special necessity. Deps generally does not need to pass in, the need to use the module requires loading.

Factory function factory resolution

The factory function is the body and focus of the module. When only one parameter is passed to define (recommended writing method), this parameter is the factory function, and the three parameters of the factory function are:
1. Require -- module loading function used to record dependent modules.
2. Exports -- an interface point on which data or methods are defined and exposed to external calls.
3. Module -- the metadata of a module.
These three parameters can be selected as to whether the display specification is required or not.
Let's talk about modules. Module is an object that stores the meta information of the module as follows:
1. Module. id -- the id of the module.
2. Module. dependencies -- an array that stores a list of the ids of all the modules on which the module depends.
3. Module. Exports -- exports refer to the same object.

Three patterns for writing modules

The first pattern to define a module is based on exports:


define(function(require, exports, module) {
    var a = require('a'); //Introduce module a
    var b = require('b'); //Introduce b module

    var data1 = 1; //Private data

    var func1 = function() { //Private methods
        return a.run(data1);
    }

    exports.data2 = 2; //Public data

    exports.func2 = function() { //Public methods
        return 'hello';
    }
});

Above is a more "authentic" module definition pattern. In addition to attaching public data and methods to exports, you can also directly return an object representation module with the same functionality as the following code:

define(function(require) {
    var a = require('a'); //Introduce module a
    var b = require('b'); //Introduce b module

    var data1 = 1; //Private data

    var func1 = function() { //Private methods
        return a.run(data1);
    }

    return {
        data2: 2,
        func2: function() {
            return 'hello';
        }
    };
});

If the module definition has no other code and returns only one object, it can also be written in the following simplified way:

define({
    data: 1,
    func: function() {
        return 'hello';
    }
});

The third approach is ideal for modules that define pure JSON data.

Module load and reference

Such as:

require("http://example/js/a");

That means loading http://example/js/a.js.
Relative address - find the module with relative calls to the relative address of the js file where the loading function is located.
For example, load in http://example/js/b.js
require("./c");

Load http://example/js/c.js.
Base address - if the loaded string identifies neither an absolute path nor begins with "./ ", address the "base" in the SeaJS global configuration, as discussed later.
Note that you don't have to pass the suffix ".js "when the module is loaded above. SeaJS adds".js "automatically. But it is not added in the following three cases:
When loading CSS, for example:
require("./module1-style.css");

The path contains "?" , such as:
require(<a href="http://example/js/a.json?cb=func">http://example/js/a.json?cb=func</a>);

When the path ends in "#", as in:
require("http://example/js/a.json#");

Depending on the application scenario, SeaJS provides three apis for loading modules: seajs.use, require, and require.async, which are described below.

Seajs. Use

Seajs. use is primarily used to load entry modules. The entry module is equivalent to the main function of the C program and is also the root of the entire module dependency tree. In the TinyApp example above, init is the entry module. Seajs. use is used as follows:


//A single mode
seajs.use('./a');

//The callback mode
seajs.use('./a', function(a) {
  a.run();
});

//Multi-module mode
seajs.use(['./a', './b'], function(a, b) {
  a.run();
  b.run();
});

Generally, seajs.use is only used in the page loading entry module, and seajs will resolve all dependent modules along the entry module and load them. If there is only one entry module, you can also omit seajs.use by adding the "data-main" attribute to the script tag that introduces sea-js. For example, the index.html of TinyApp above can also be written as follows:

<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>TinyApp</title>
</head>
<body>
    <p class="content"></p>
    <script src="./sea.js" data-main="./init"></script>
</body>
</html>

This will make the HTML more concise.

The require

Require is the main module loading method of SeaJS. It is commonly used when other modules are needed in a module:

var m = require('/path/to/module/file');

Here is a brief introduction to the automatic SeaJS loading mechanism. As mentioned above, the HTML with SeaJS only needs to contain sea-js, so how do other js files load in? SeaJS will first download the entry module, then follow the entry module to use regular expressions to match all the require in the code, and then download the corresponding js file according to the file path identification in require, and then iterate over the downloaded js file. The whole process is similar to the traversal operation of a graph (the entire dependent data structure is a graph rather than a tree because of possible cross-loop dependencies).
With this in mind, the following rules are easy to understand:
The path id to require must be a literal string, not an expression, as the following method using require is wrong:
require('module' + '1');
require('Module'.toLowerCase());

All of this causes SeaJS to fail to perform the correct regular matching to download the corresponding js file.

The require. Async

As mentioned above, SeaJS will record all the required js files at once through static analysis when the HTML page opens. If you want a js file to be downloaded when it is used, you can use require. Async:

require.async('/path/to/module/file', function(m) {
    //code of callback...
});

In this way, only when the module is used, the corresponding js file will be downloaded, and the JavaScript code will be loaded on demand.

Global configuration for SeaJS
SeaJS provides a seajs.config method to set the global configuration to receive a configuration object representing the global configuration. The specific use method is as follows:

seajs.config({
    base: 'path/to/jslib/',
    alias: {
      'app': 'path/to/app/'
    },
    charset: 'utf-8',
    timeout: 20000,
    debug: false
});

Where, base represents the base address path when the base address is addressed. For example, if the base is set to http://example.com/js/3-party/, then:
var $ = require('jquery');

http://example.com/js/3-party/jquery.js is loaded.
Alias can set abbreviations for longer commonly used paths.
Charset represents the charset property of a script tag when downloading js.
Timeout represents the maximum time in milliseconds to download a file.
Debug indicates whether to work in debug mode.

How does SeaJS work with existing JS libraries

To use existing JS libraries such as jQuery with SeaJS, you only need to encapsulate the existing libraries according to the module definition rules of SeaJS. For example, here's how to encapsulate jQuery:

define(function() {

//{{{jQuery original code starts
/*!  
 * jQuery JavaScript Library v1.6.1
 * http://jquery.com/
 *
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2011, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: Thu May 12 15:04:36 2011 -0400
 */
//...
//}}}jQuery original code ends

return $.noConflict();
});


Package deployment of the SeaJS project

SeaJS was originally integrated with a packaged deployment tool, SPM, but later the authors took the SPM out of SeaJS and made it a separate project for a KISS. The core idea of SPM is to merge and compress the code of all modules into the entry module. Due to the nature of SeaJS itself, HTML can be easily switched between development and production environments without any changes. But, due to the SPM didn't release the official version, so this article is not going to detail, interested friends can see its making project homepage at https://github.com/seajs/spm/.
In fact, since each project USES different JS merge and compression tools, SPM may not be perfect for each project. Once you understand the principles of SeaJS, you can write your own merge package script that matches your project's characteristics.


 


Related articles: