Skip to content
This repository was archived by the owner on Mar 22, 2019. It is now read-only.

motivation

JiamingLinn edited this page Dec 17, 2015 · 39 revisions

如今的网站正在向wepapp快速发展:

  • 网页中出现了越来越多的javascript.
  • 在现代的浏览器你可以往里面塞进更多的代码.
  • 整页的刷新变少了 ,更多的代码被留在同一页面执行.

其结果就是在你的客户端有了一堆的代码!!!

一个庞大的代码库需要被管理,而模块系统提供了将你的代码库归类到模块中去的机会。

模块系统风格

这里有多种如何定义依赖和输出(exports)的标准:

  • <script>-标签风格 (非模块系统)
  • CommonJs
  • AMD以及其中的一些方言
  • ES6模块
  • 还有其他的...

<script>-标签风格

如果你并没有使用模块化系统,这个将是你用来处理模块化的代码库的方式

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>

每个模块暴露向全局对象暴露出一个接口,例如window对象。其他模块可以通过全局对象过去其依赖的模块

Common problems

  • Conflicts in the global object.
  • Order of loading is important.
  • Developers have to resolve dependencies of modules/libraries.
  • In big projects the list can get really long and difficult to manage.

CommonJs: synchronous require

This style uses a synchronous require method to load a dependency and return an exported interface. A module can specify exports by adding properties to the exports object or setting the value of module.exports.

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

It's used on server-side by node.js.

Pros

  • Server-side modules can be reused
  • There are already many modules in this style (npm)
  • very simple and easy to use.

Cons

  • blocking calls do not apply well on networks. Network requests are asynchronous.
  • No parallel require of multiple modules

Implementations

AMD: asynchronous require

Asynchronous Module Definition

Other module systems (for the browser) had problems with the synchronous require (CommonJs) and introduced an asynchronous version (and a way to define modules and exporting values):

require(["module", "../file"], function(module, file) { /* ... */ });
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});

Pros

  • Fits to the asynchronous request style in networks.
  • Parallel loading of multiple modules.

Cons

  • Coding overhead. More difficult to read and write.
  • Seems to be some kind of workaround.

Implementations

Read more about CommonJs and AMD.

ES6 modules

EcmaScript6 adds some language constructs to JavaScript, which form another module system.

import "jquery";
export function doStuff() {}
module "localModule" {}

Pros

  • Static analysis is easy
  • Future-proof as ES standard

Cons

  • Native browser support will take time
  • Very few modules in this style

Unbiased solution

Give the developer the choice of the module style. Allow existing code to work. Make it easy to add custom module styles.


Transferring

Modules should be executed on the client, so they must be transferred from the server to the browser.

There are two extremes on how to transfer modules:

  • 1 request per module
  • all modules in one request

Both are used in the wild, but both are suboptimal:

  • 1 request per module
    • Pro: only required modules are transferred
    • Con: many requests means much overhead
    • Con: slow application startup, because of request latency
  • all modules in one request
    • Pro: less request overhead, less latency
    • Con: not (yet) required modules are transferred too

Chunked transferring

A more flexible transferring would be better. A compromise between the extremes is better in most cases.

→ While compiling all modules: Split the set of modules into multiple smaller batches (chunks).

We get multiple smaller requests. Chunks with modules that are not required initially are only requested on demand. The initial request doesn't contain your complete code base and is smaller.

The "split points" are up to the developer and optional.

→ A big code base is possible!

Note: The idea is from Google's GWT.

Read more about Code Splitting.


Why only JavaScript?

Why should a module system only help the developer with JavaScript? There are many other static resources that need to be handled:

  • stylesheets
  • images
  • webfonts
  • html for templating
  • etc.

And also:

  • coffeescript → javascript
  • elm → javascript
  • less stylesheets → css stylesheets
  • jade templates → javascript which generates html
  • i18n files → something
  • etc.

This should be as easy as:

require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");

Read more about Using loaders and Loaders.


Static analysis

When compiling all the modules a static analysis tries to find dependencies.

Traditionally this could only find simple stuff without expression, but i.e. require("./template/" + templateName + ".jade") is a common construct.

Many libraries are written in different styles. Some of them are very weird...

Strategy

A clever parser would allow most existing code to run. If the developer does something weird it would try to find the most compatible solution.

Clone this wiki locally