1. 语法对比
入口文件引入
requirejs 的引入和入口文件的引入是同一个 script 标签
//在引入 requirejs 的 script 标签的 data-main 属性引入入口文件
<script data-main="src/main.js" src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.min.js"></script>
systemjs 的引入和入口文件的引入是两个单独的 script 标签
//引入 systemjs
<script src="https://cdn.bootcdn.net/ajax/libs/systemjs/6.13.0/system.min.js"></script>
//script 标签指明 type,加载入口文件
<script type="systemjs-module" src="/src/main.js"></script>
模块定义方式
requirejs 使用 define() 方法定义模块,原生支持具名模块定义。
define(['./b.js'], function(b) {
return function() {
console.log('我是 a.js')
b.sayHi()
}
})
systemjs 使用 System.register() 方法定义模块,可通过插件 named-register.js
实现具名模块定义。
System.register(['/src/b.js'], (exports) => {
let b;
return {
setters: [(module) => {
b = module
}],
execute() {
exports({
default: () => {
console.log('我是 a.js')
b.sayHi()
}
})
}
}
})
PS:
具名模块定义在节省文件请求数量,进行多个模块合并在一个文件里的时候很有用。如果不进行模块合并,其实可以直接使用匿名模块,匿名模块的模块名字 id 是默认以其路径为唯一 id。
模块路径映射方式
require.config({
baseUrl: 'lib',
paths: {
'compute': 'compute/main'
}
});
<script type="systemjs-importmap">
{
"imports": {
"myquery": "/deps/myquery.js"
}
}
</script>
// Alternatively:
<script type="systemjs-importmap" src="path/to/map.json" crossorigin="anonymous"></script>
模块加载方式(动态导入)
require(['src/a.js', 'myquery'], function(a, myquery) {
console.log('I am main')
a()
console.log(myquery)
})
System.import()
加载其他模块定义方式的模块
requirejs 使用 shim
require.config({
shim: { // 支持iife全局模式的模块
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['underscore', 'jquery'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
},
packages: {} // 支持 commonjs 模式的模块
})
systemjs 使用 pluggable extras
加载其他模式的模块
循环依赖
requirejs 支持循环依赖
//"a" needs "b" and "b" needs "a"
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
// requirejs 中的循环依赖用 require 改写
systemjs 支持循环依赖
PS: 循环依赖本身是一种代码设计问题,代码编写过程中应该避免循环依赖的出现,但有时候循环依赖也是必须的,无法避免的。两种工具都有对循环依赖的处理。
live bindings
2. script loading
requirejs
requirejs 使用 head.appendChild(script)
的方式进行模块脚本加载。
systemjs
systemjs 使用 head.appendChild(script)
的方式进行模块脚本加载,同时在加载完成后又 head.removeChild
了脚本模块。
3. 浏览器支持
requirejs
systemjs
充分支持到 IE 11,若要支持 IE11 之前版本的浏览器,需要引入 polyfill ,有 promise / fetch 等等 polyfill。