Modules

When we say an application is modular, we generally mean it’s composed of a set of highly decoupled, distinct pieces of functionality stored in modules.

模块可以明确地指定哪些变量、类或函数对外暴露。

  • 专一性」:每一个模块仅为一项任务或者功能负责,并且对外暴露的 API 应该是简洁、干净的。
  • 独立性:模块对其它模块的了解应该是越少越好。模块之间彼此不允许直接调用,它们之间的通信需要建立在中介之上。
  • 拆分性:即便与其它模块分离开,也不会影响该模块的测试和使用。
  • 重组性:模块之间能够以各种方式组合使用,利用这一特性可以构建出软件的不同版本,甚至是不同的应用。
  • 替换性:两个模块只要遵循实现了相同的接口,就能够相互替换使用,并且系统的其余部分将不会受到影响。

接口 : 接口是模块化设计的首要工具,它约定了模块在开发过程中需要实现的所有功能。

Scripts 模式

逐一排入标签,然后用全局命名或者 Sandbox 的模式来加载运行模块。

AMD & CommonJS 规范

AMD

AMD 是提前执行,推崇依赖前置。RequireJS 的思想。

The AMD module format itself is a proposal for defining modules where both the module and dependencies can be asynchronously loaded.

  1. define(
  2. module_id /*optional*/,
  3. [dependencies] /*optional*/,
  4. /*function for instantiating the module or object*/
  5. definition function );
  6. require(['foo', 'bar'], function ( foo, bar ) {
  7. // rest of your code here
  8. foo.doSomething();
  9. });

CMD

CMD 是延迟执行,推崇依赖就近。

CommonJS

The CommonJS module proposal specifies a simple API for declaring modules server-side and unlike AMD attempts to cover a broader set of concerns such as io, filesystem, promises and more.

  1. // package/lib is a dependency we require
  2. var lib = require('package/lib');
  3. // some behaviour for our module
  4. function foo(){
  5. lib.log('hello world!');
  6. }
  7. // export (expose) foo to other modules
  8. exports.foo = foo;

ES6 Module

Language-level support for modules for component definition. Codifies patterns from popular JavaScript module loaders (AMD, CommonJS). Runtime behavior defined by a host-defined default loader. Implicitly async model – no code executes until requested modules are available and processed.

  1. // lib/math.js
  2. export function sum(x, y) {
  3. return x + y;
  4. }
  5. export var pi = 3.141593;
  1. // app.js
  2. import { job as Job, key as Key } from 'util'
  3. import * as math from "lib/math";
  4. alert("2π = " + math.sum(math.pi, math.pi));
  1. // otherApp.js
  2. import { sum, pi } from "lib/math";
  3. alert("2π = " + sum(pi, pi));

Some additional features include export default and export *:

  1. // lib/mathplusplus.js
  2. export * from "lib/math";
  3. export var e = 2.71828182846;
  4. export default function(x) {
  5. return Math.log(x);
  6. }
  1. // app.js
  2. import ln, {pi, e} from "lib/mathplusplus";
  3. alert("2π = " + ln(e)*pi*2);

Module Loader

Module loaders support:

  • Dynamic loading
  • State isolation
  • Global namespace isolation
  • Compilation hooks
  • Nested virtualization

The default module loader can be configured, and new loaders can be constructed to evaluate and load code in isolated or constrained contexts.

  1. // Dynamic loading – ‘System’ is default loader
  2. System.import('lib/math').then(function(m) {
  3. alert("2π = " + m.sum(m.pi, m.pi));
  4. });
  5. // Create execution sandboxes – new Loaders
  6. var loader = new Loader({
  7. global: fixup(window) // replace ‘console.log’
  8. });
  9. loader.eval("console.log('hello world!');");
  10. // Directly manipulate module cache
  11. System.get('jquery');
  12. System.set('jquery', Module({$: $})); // WARNING: not yet finalized

Tools

  • SeaJS
  • RequireJS
  • WebPack / Browserify

Features:

  • WebPack supports AMD and CommonJs module styles. It performs clever static analysis on the AST of your code. It even has an evaluation engine to evaluate simple expressions. This allows you to support most existing libraries.
  • WebPack allows to split your codebase into chunks. Chunks are loaded on demand. This reduces initial loading time.

配合 Gulp 等自动化流程工具静态使用:

Gulp-Webpack

参考:webpack.md

Browserify