A Module Loader for the Web

Related tags

Loaders seajs
Overview

A Module Loader for the Web

Sea.js is a module loader for the web. It is designed to change the way that you organize JavaScript. With Sea.js, it is pleasure to build scalable web applications.

The official site: https://seajs.github.io/seajs/

Build Status

Questions?

If you have any questions, please feel free to ask through New Issue.

Reporting an Issue

Make sure the problem you're addressing is reproducible. Use http://jsbin.com/ or http://jsfiddle.net/ to provide a test page. Indicate what browsers the issue can be reproduced in. What version of Sea.js is the issue reproducible in. Is it reproducible after updating to the latest version?

License

Sea.js is available under the terms of the MIT License.

Comments
  • 解析依赖时,移除代码注释产生的问题(内有提取依赖的优化活动)

    解析依赖时,移除代码注释产生的问题(内有提取依赖的优化活动)

    seajs在解释依赖模块时,先移除模块代码里的所有注释,然后在移除过注释的代码里查找require方法调用,以得到该模块的依赖项。

    不过移除模块代码注释的时候,只用了一个replace方法,得到的结果代码有可能是不完整的:

    src/util-deps.js

    var COMMENT_RE = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg
    code = code.replace(COMMENT_RE, '')
    

    module code

    var str = "//In face, this is not a comment."; require("module A");
    require("module B");
    

    调用完 code.replace(COMMENT_RE, '')后, 代码变成

    var str = 
    require("module B");
    

    依赖项将缺少 "module A", 至少在chrome(23.0.1271.97 m)中的行为是这样的。

    具体的结果依赖于浏览器的Function.prototype.toString 方法: deps = util.parseDependencies(factory.toString())。 在FF中,似乎会把代码格式化,toString后的代码不存在多条语句在同一行的情况,绕过了这个问题。别的浏览器暂时没有测试。

    不知道这里是为了保持代码简单所以这样简单处理还是我忽略了某些历史原因?

    这条issues昨天被我错误地发到了 spm项目那边去了,得知用spm解析依赖的时候不会有这个问题。

    activity 
    opened by ethanzheng 108
  • 配置

    配置

    配置

    可以对 Sea.js 进行配置,让模块编写、开发调试更方便。


    seajs.config seajs.config(options)

    用来进行配置的方法。

    seajs.config({
    
      // 别名配置
      alias: {
        'es5-safe': 'gallery/es5-safe/0.9.3/es5-safe',
        'json': 'gallery/json/1.0.2/json',
        'jquery': 'jquery/jquery/1.10.1/jquery'
      },
    
      // 路径配置
      paths: {
        'gallery': 'https://a.alipayobjects.com/gallery'
      },
    
      // 变量配置
      vars: {
        'locale': 'zh-cn'
      },
    
      // 映射配置
      map: [
        ['http://example.com/js/app/', 'http://localhost/js/app/']
      ],
    
      // 预加载项
      preload: [
        Function.prototype.bind ? '' : 'es5-safe',
        this.JSON ? '' : 'json'
      ],
    
      // 调试模式
      debug: true,
    
      // Sea.js 的基础路径
      base: 'http://example.com/path/to/base/',
    
      // 文件编码
      charset: 'utf-8'
    });
    

    支持以下配置选项:

    alias Object

    当模块标识很长时,可以使用 alias 来简化。

    seajs.config({
      alias: {
        'jquery': 'jquery/jquery/1.10.1/jquery',
        'app/biz': 'http://path/to/app/biz.js',
      }
    });
    
    define(function(require, exports, module) {
    
       var $ = require('jquery');
         //=> 加载的是 http://path/to/base/jquery/jquery/1.10.1/jquery.js
    
       var biz = require('app/biz');
         //=> 加载的是 http://path/to/app/biz.js
    
    });
    

    使用 alias,可以让文件的真实路径与调用标识分开,有利于统一维护。

    paths Object

    当目录比较深,或需要跨目录调用模块时,可以使用 paths 来简化书写。

    seajs.config({
      paths: {
        'gallery': 'https://a.alipayobjects.com/gallery',
        'app': 'path/to/app',
      }
    });
    
    define(function(require, exports, module) {
    
       var underscore = require('gallery/underscore');
         //=> 加载的是 https://a.alipayobjects.com/gallery/underscore.js
    
       var biz = require('app/biz');
         //=> 加载的是 path/to/app/biz.js
    
    });
    

    paths 配置可以结合 alias 配置一起使用,让模块引用非常方便。

    vars Object

    有些场景下,模块路径在运行时才能确定,这时可以使用 vars 变量来配置。

    seajs.config({
      vars: {
        'locale': 'zh-cn'
      }
    });
    
    define(function(require, exports, module) {
    
      var lang = require('./i18n/{locale}.js');
         //=> 加载的是 path/to/i18n/zh-cn.js
    
    });
    

    vars 配置的是模块标识中的变量值,在模块标识中用 {key} 来表示变量。

    map Array

    该配置可对模块路径进行映射修改,可用于路径转换、在线调试等。

    seajs.config({
      map: [
        [ '.js', '-debug.js' ]
      ]
    });
    
    define(function(require, exports, module) {
    
      var a = require('./a');
         //=> 加载的是 path/to/a-debug.js
    
    });
    

    更多用法可参考:调试实践

    preload Array

    使用 preload 配置项,可以在普通模块加载前,提前加载并初始化好指定模块。

    // 在老浏览器中,提前加载好 ES5 和 json 模块
    seajs.config({
      preload: [
        Function.prototype.bind ? '' : 'es5-safe',
        this.JSON ? '' : 'json'
      ]
    });
    

    preload 中的空字符串会被忽略掉。

    注意preload 中的配置,需要等到 use 时才加载。比如:

    seajs.config({
      preload: 'a'
    });
    
    // 在加载 b 之前,会确保模块 a 已经加载并执行好
    seajs.use('./b');
    

    preload 配置不能放在模块文件里面:

    seajs.config({
      preload: 'a'
    });
    
    define(function(require, exports) {
      // 此处执行时,不能保证模块 a 已经加载并执行好
    });
    

    debug Boolean

    值为 true 时,加载器不会删除动态插入的 script 标签。插件也可以根据 debug 配置,来决策 log 等信息的输出。

    base String

    Sea.js 在解析顶级标识时,会相对 base 路径来解析。详情请参阅 模块标识

    [email protected] 之前,Sea.js 会根据 sea.js 的路径去猜测 base 路径,一般为路径上含有 seajs 字符串的上一级路径。在 [email protected] 后,去掉了这个模糊的猜测。我们推荐始终手动设置一个准确的 base 路径

    charset String | Function

    获取模块文件时,<script><link> 标签的 charset 属性。 默认是 utf-8

    charset 还可以是一个函数:

    seajs.config({
      charset: function(url) {
    
        // xxx 目录下的文件用 gbk 编码加载
        if (url.indexOf('http://example.com/js/xxx') === 0) {
          return 'gbk';
        }
    
        // 其他文件用 utf-8 编码
        return 'utf-8';
    
      }
    });
    

    提示

    多次配置自动合并

    seajs.config 可以多次运行,每次运行时,会对配置项进行合并操作:

    seajs.config({
      alias: {
        'jquery': 'path/to/jquery.js',
        'a': 'path/to/a.js'
      },
      preload: ['seajs-text']
    });
    
    seajs.config({
      alias: {
        'underscore': 'path/to/underscore.js',
        'a': 'path/to/biz/a.js'
      },
      preload: ['seajs-combo']
    });
    

    上面两处 config 运行的结果是:

     alias = {
       'jquery': 'path/to/jquery.js',
       'underscore': 'path/to/underscore.js',
       'a': 'path/to/biz/a.js'
     };
    
     preload = ['seajs-text', 'seajs-combo'];
    

    即:config 会自动合并不存在的项,对存在的项则进行覆盖。

    插件的配置

    插件可以给 Sea.js 添加配置项,请查看具体插件了解相关配置。

    配置文件

    配置可以直接写在 html 页面上,也可以独立出来成为一个文件。

    config.js

    seajs.config({
      ...
    });
    

    独立成一个文件时,一般通过 script 标签在页面中同步引入。


    常用的配置项是 aliaspathsbase,其他配置项有需要时,来查查文档就会用了。

    documentation 
    opened by lifesinger 102
  • 构建工具

    构建工具

    标准构建

    spm3 已经发布,建议使用最新的构建工具。http://spmjs.io/documentation/develop-a-package#build


    如果项目遵循推荐的标准目录结构:

    foo-module/
      |-- dist                    存放构建好的文件
      |-- src                     存放 js、css 等源码
      |     |-- foo.js
      |     `-- style.css
      `-- package.json      模块信息   
    

    那么构建很简单。首先安装 spm 工具(spm2):

    $ npm install [email protected] -g
    $ npm install [email protected] -g
    

    然后运行构建命令:

    $ cd foo-module
    $ spm build
    

    这样,就会根据 package.json 中的信息,将文件自动构建到 dist 目录下。构建后,还需要将 dist 目录下的文件部署到 sea-modules 目录中,比如 examples 中的 make deploy 命令:Makefile

    详细可参考 http://docs.spmjs.org/

    推荐将 seajs/examples clone 到本地,实际操作一下就清楚。

    自定义构建

    如果标准构建无法满足需求,可以直接使用 Grunt 来完成。Grunt 是一个非常优秀的构建工具,详见:http://gruntjs.com/

    利用 Grunt 来构建 CMD 模块需要使用到以下 Grunt Tasks:

    这一块真的很简单,只要你熟悉 Grunt,因此先阅读 Grunt 的文档吧,然后有任何问题,欢迎回复。

    推荐几篇社区贡献的文章:

    非常欢迎大家的使用经验总结。


    有任何问题,欢迎留言交流。 注意:已解决的问题,会在整理后删除掉。

    documentation 
    opened by lifesinger 99
  • API 快速参考

    API 快速参考

    API 快速参考

    该页面列举了 Sea.js 的常用 API。只要掌握这些用法,就可以娴熟地进行模块化开发。


    seajs.config

    用来对 Sea.js 进行配置。

    seajs.config({
    
      // 设置路径,方便跨目录调用
      paths: {
        'arale': 'https://a.alipayobjects.com/arale',
        'jquery': 'https://a.alipayobjects.com/jquery'
      },
    
      // 设置别名,方便调用
      alias: {
        'class': 'arale/class/1.0.0/class',
        'jquery': 'jquery/jquery/1.10.1/jquery'
      }
    
    });
    

    更多配置项请参考:#262

    seajs.use

    用来在页面中加载一个或多个模块。

    // 加载一个模块
    seajs.use('./a');
    
    // 加载一个模块,在加载完成时,执行回调
    seajs.use('./a', function(a) {
      a.doSomething();
    });
    
    // 加载多个模块,在加载完成时,执行回调
    seajs.use(['./a', './b'], function(a, b) {
      a.doSomething();
      b.doSomething();
    });
    

    更多用法请参考:#260

    define

    用来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:

    define(function(require, exports, module) {
    
      // 模块代码
    
    });
    

    也可以手动指定模块 id 和依赖,详情请参考:#242 require, exportsmodule 三个参数可酌情省略,具体用法如下。

    require

    require 用来获取指定模块的接口。

    define(function(require) {
    
      // 获取模块 a 的接口
      var a = require('./a');
    
      // 调用模块 a 的方法
      a.doSomething();
    });
    

    注意,require 只接受字符串直接量作为参数,详细约定请阅读:#259

    require.async

    用来在模块内部异步加载一个或多个模块。

    define(function(require) {
    
      // 异步加载一个模块,在加载完成时,执行回调
      require.async('./b', function(b) {
        b.doSomething();
      });
    
      // 异步加载多个模块,在加载完成时,执行回调
      require.async(['./c', './d'], function(c, d) {
        c.doSomething();
        d.doSomething();
      });
    
    });
    

    详细说明请参考:#242

    exports

    用来在模块内部对外提供接口。

    define(function(require, exports) {
    
      // 对外提供 foo 属性
      exports.foo = 'bar';
    
      // 对外提供 doSomething 方法
      exports.doSomething = function() {};
    
    });
    

    详细说明请参考:#242

    module.exports

    exports 类似,用来在模块内部对外提供接口。

    define(function(require, exports, module) {
    
      // 对外提供接口
      module.exports = {
        name: 'a',
        doSomething: function() {};
      };
    
    });
    

    module.exportsexports 的区别,以及详细说明请参考:#242


    以上 7 个接口是最常用的,要牢记于心。

    这里提供一个不错的社区贡献的 API 文档:http://yslove.net/seajs/

    documentation 
    opened by lifesinger 83
  • 发布 Sea.js 2.3.0

    发布 Sea.js 2.3.0

    对当前页面的模块和模块关系感到混乱?模块依赖图插件轻松一点让你一目了然!

    preview

    只需在chrome上安装一个插件,就可以绘制出有向图,模块根路径、列表、名称、依赖关系尽收眼底。

    相对于上个版本,Sea.js的体积又有进一步缩减,这一切归功于将css功能部分提取出作为一个插件存在。

    • Sea.js 2.2

      sea-debug.js 20,671 bytes sea.js 6,769 bytes gzip 3.0 KB LOC 947

    • Sea.js 2.3

      sea-debug.js 18,177 bytes sea.js 6,064 bytes gzip 2.8 KB LOC 846

    测试用例增加到了505个!这一切都保障了Sea.js拥有十分强大的健壮性。

    下载更新

    推荐使用 spm

    spm install seajs
    npm install seajs
    

    BUG 修复

    • IE9下本地url document.URL与之前版本使用的location.href输出不一致导致模块id不能正确resolve #1154
    • Android中的webview当location.href为空时报错 #1225
    • realpath method in util-path.js:https://github.com/seajs/seajs/pull/1193

    移除特性

    • 去掉css支持,推荐link标签同步引入。如果实在要用,可以用seajs-css插件来完成。
    • preload移除,推荐script标签同步引入。如果实在要用,可以用seajs-preload插件来完成。
    • 去掉根据 sea.js 路径自动猜测 base 路径的功能。交给用户自己配置。
    • CommonJS规范书写,这其实是spm3的功能:https://github.com/spmjs/spm/issues/819

    http://spmjs.io

    改进增强

    • seajs-css插件:https://github.com/seajs/seajs-css
    • seajs-preload插件:https://github.com/seajs/seajs-preload
    • seajs-circular插件,支持循环依赖:https://github.com/seajs/seajs-circular
    • seamap插件,模块依赖图,绘制出当前页面上的模块和依赖关系图:https://github.com/seajs/seamap

    插件目前分为2种:1是seajs插件,以seajs-xxx形式命名;2是开发者工具,以seaxxx命名。

    其它调整

    • 模块保存时增加了save事件
    • 细微的性能改进
    • CommonJS/AMD/CMD/Other脚本之间的互相转换:https://github.com/army8735/ranma
    • pass-entry分支中尝试启用新算法,在体积不变的情况原生支持循环依赖。由于取消了回溯,初始化性能也提升了一倍
    • 构建工具seatools更新部分bug:https://github.com/seajs/seatools
    • 增加了英文文档:http://seajs.org/docs/en.html
    • 同步发布spm3:https://github.com/spmjs/spm/issues/819

    有任何问题,欢迎反馈。

    documentation 
    opened by army8735 80
  • 如何改造现有文件为 CMD 模块

    如何改造现有文件为 CMD 模块

    如何改造现有文件为 CMD 模块

    经过一段考察,我们终于要在项目中引入模块机制和 Sea.js 了,那么如何将现有的文件改造成 CMD 模块就成了重要的问题。下面针对一些典型场景来说明包装的方式。

    首先还是请大家详细了解下 CMD 模块定义规范,只要洞悉事物的定义和本质,一切问题可迎刃而解。

    改造主流模块

    这里指的是 jQuery、Moment、Backbone、underscore 等业界主流模块,这些模块一般都有对 AMD 和 CommonJS 的支持代码,例如 jQuery 源文件的最后几行:

    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
        module.exports = jQuery;
    } else {
        window.jQuery = window.$ = jQuery;
    
        if ( typeof define === "function" && define.amd ) {
            define( "jquery", [], function () { return jQuery; } );
        }
    }
    

    还有 Backbone 里:

    var Backbone;
    if (typeof exports !== 'undefined') {
      Backbone = exports;
    } else {
      Backbone = root.Backbone = {};
    }
    

    对于有这些兼容代码的,只需要去掉 define.amd 的支持,或是直接包装上 define 就可以了。

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

    如果没有模块化的兼容代码,有时候需要手动引入依赖,以及暴露对应的接口。

    define(function(require, exports, module) {
      var $ = require('$');
      // code here ...
      module.exports = Placeholders;
    });
    

    可以参考 cmdjs/gallery 里的 Gruntfile 对这些主流模块的代码替换方式。

    现有的 JS 文件

    对于一些现有的普通 JS 文件,相对简单的多,参考 CMD 的书写规范,把那些暴露到全局命名空间的接口用 CMD 的方式进行改造就可以了。

    比如现有文件 util.js

    window.util = window.util || {};
    util.addClass = function() {
      window.css();
    };
    util.queryString = function() {};
    

    改为:

    define(function(require, exports, module) {
      // 引入依赖
      var css = require('css');
    
      util.addClass = function() {
        css();
      };
      util.queryString = function() {};
    
      // 暴露对应接口
      module.exports = util;
    });
    

    这里不啰嗦,就是基本的 CMD 书写规范。实际的改造过程中,情况可以比上面的例子要复杂一些,具体情况具体解决就行。

    改造 jQuery 插件

    这也是一个经常遇到的问题,我们推荐以下的包装方式:

    // jquery-plugin-abc
    define(function(require, exports, module) {
      var $ = require('$');
      // 插件的代码
      $.fn.abc = function() {};
    });
    

    这样的改造方式实际上是强化了原有的 $ 对象(而不是重新包装出一个新的 $),在实际调用时,可以用下面的方式:

    seajs.use(['$', 'jquery-plugin-abc'], function($) {
      // $ 有了 jquery-plugin-abc 所提供的插件功能
      $.abc();
    });
    

    更多 jQuery 插件的包装,可以参考 cmdjs/jquery 里的做法。

    工具

    除了手动的方式修改代码外,我们推荐使用 Grunt 来进行统一的改造,官方也通过 Grunt 改造了很多主流模块和 jQuery 插件,具体的操作手册见 引入 CMD 模块指南 。你可以在 cmdjs/gallerycmdjs/jquery 中找到具体的 Gruntfile ,从而借鉴到您的项目中去。所有打包好的模块可以在 spmjs.org 中找到。

    小结

    上面提供的是原有代码包装为 CMD 书写规范 的方法,在具体上线前,可能还需要打包为具名模块(包含 ID 的模块)。关于构建方面的进一步知识可以参考 构建工具

    这里提到的包装方式都比较典型和简单,具体的实践可能千差万别。您在项目中有什么探索、实践和问题,欢迎来这里分享和提问。

    documentation 
    opened by afc163 75
  • Sea.js 2.1 发布计划

    Sea.js 2.1 发布计划

    目前代码已可用,获取方式:

    1. 下载 https://github.com/seajs/seajs/archive/master.zip
    2. 从 dist 目录中拿构建好的代码

    修改记录:https://github.com/seajs/seajs/issues?milestone=11&page=1&state=closed 尚未完成:https://github.com/seajs/seajs/issues?milestone=11&state=open

    正式发布前,还需要做:

    • [x] 仔细检查下所有 public api
    • [x] 仔细检查下所有 plugins
    • [x] examples 更新
    • [x] 文档系统化梳理
    • [x] test in all browsers
    • [x] 确定性能测试通过
    • [x] tag
    • [x] publish to npm & spm

    预计 6.18 日正式发布。

    milestone 
    opened by lifesinger 72
  • Sea.js 3.0 想法探讨

    Sea.js 3.0 想法探讨

    Sea.js 拟推出 3.0 版本,新增原则:

    Mobile First

    具体调整:

    1. 开发时只支持 Chrome / Firefox 等现代浏览器,不支持 IE6-8. 需要在 Old IE 下运行的话,需要先构建,生成 id 和 deps 后才能在 IE 下正常运行。
    2. 去掉 preload 功能?需要 preload 的组件,建议直接用 script 同步引入。preload 的初衷,是希望通过异步并行下载提高性能,但在非 IE 下,这种异步带来的性能优化已不明显。在移动端更意义不大。
    3. 细节调整:去掉根据 sea.js 路径自动猜测 base 路径的功能。交给用户自己配置。

    期待你的建议。

    discuss 
    opened by lifesinger 66
  • 前端模块化开发的价值

    前端模块化开发的价值

    本文发表在《程序员》杂志 2013 年 3 月刊,推荐购买。


    前端模块化开发的价值

    随着互联网的飞速发展,前端开发越来越复杂。本文将从实际项目中遇到的问题出发,讲述模块化能解决哪些问题,以及如何使用 Sea.js 进行前端的模块化开发。

    恼人的命名冲突

    我们从一个简单的习惯出发。我做项目时,常常会将一些通用的、底层的功能抽象出来,独立成一个个函数,比如

    function each(arr) {
      // 实现代码
    }
    
    function log(str) {
      // 实现代码
    }
    

    并像模像样地把这些函数统一放在 util.js 里。需要用到时,引入该文件就行。这一切工作得很好,同事也很感激我提供了这么便利的工具包。

    直到团队越来越大,开始有人抱怨。

    小杨:我想定义一个 each 方法遍历对象,但页头的 util.js 里已经定义了一个,我的只能叫 eachObject 了,好无奈。

    小高:我自定义了一个 log 方法,为什么小明写的代码就出问题了呢?谁来帮帮我。

    抱怨越来越多。团队经过一番激烈的讨论,决定参照 Java 的方式,引入命名空间来解决。于是 util.js 里的代码变成了

    var org = {};
    org.CoolSite = {};
    org.CoolSite.Utils = {};
    
    org.CoolSite.Utils.each = function (arr) {
      // 实现代码
    };
    
    org.CoolSite.Utils.log = function (str) {
      // 实现代码
    };
    

    不要认为上面的代码是为了写这篇文章而故意捏造的。将命名空间的概念在前端中发扬光大,首推 Yahoo! 的 YUI2 项目。下面是一段真实代码,来自 Yahoo! 的一个开源项目。

    if (org.cometd.Utils.isString(response)) {
      return org.cometd.JSON.fromJSON(response);
    }
    if (org.cometd.Utils.isArray(response)) {
      return response;
    }
    

    通过命名空间,的确能极大缓解冲突。但每每看到上面的代码,都忍不住充满同情。为了调用一个简单的方法,需要记住如此长的命名空间,这增加了记忆负担,同时剥夺了不少编码的乐趣。

    作为前端业界的标杆,YUI 团队下定决心解决这一问题。在 YUI3 项目中,引入了一种新的命名空间机制。

    YUI().use('node', function (Y) {
      // Node 模块已加载好
      // 下面可以通过 Y 来调用
      var foo = Y.one('#foo');
    });
    

    YUI3 通过沙箱机制,很好的解决了命名空间过长的问题。然而,也带来了新问题。

    YUI().use('a', 'b', function (Y) {
      Y.foo();
      // foo 方法究竟是模块 a 还是 b 提供的?
      // 如果模块 a 和 b 都提供 foo 方法,如何避免冲突?
    });
    

    看似简单的命名冲突,实际解决起来并不简单。如何更优雅地解决?我们按下暂且不表,先来看另一个常见问题。

    烦琐的文件依赖

    继续上面的故事。基于 util.js,我开始开发 UI 层通用组件,这样项目组同事就不用重复造轮子了。

    其中有一个最被大家喜欢的组件是 dialog.js,使用方式很简单。

    <script src="util.js"></script>
    <script src="dialog.js"></script>
    <script>
      org.CoolSite.Dialog.init({ /* 传入配置 */ });
    </script>
    

    可是无论我怎么写文档,以及多么郑重地发邮件宣告,时不时总会有同事来询问为什么 dialog.js 有问题。通过一番排查,发现导致错误的原因经常是

    <script src="dialog.js"></script>
    <script>
      org.CoolSite.Dialog.init({ /* 传入配置 */ });
    </script>
    

    在 dialog.js 前没有引入 util.js,因此 dialog.js 无法正常工作。同样不要以为我上面的故事是虚构的,在我待过的公司里,至今依旧有类似的脚本报错,特别是在各种快速制作的营销页面中。

    上面的文件依赖还在可控范围内。当项目越来越复杂,众多文件之间的依赖经常会让人抓狂。下面这些问题,我相信每天都在真实地发生着。

    1. 通用组更新了前端基础类库,却很难推动全站升级。
    2. 业务组想用某个新的通用组件,但发现无法简单通过几行代码搞定。
    3. 一个老产品要上新功能,最后评估只能基于老的类库继续开发。
    4. 公司整合业务,某两个产品线要合并。结果发现前端代码冲突。
    5. ……

    以上很多问题都是因为文件依赖没有很好的管理起来。在前端页面里,大部分脚本的依赖目前依旧是通过人肉的方式保证。当团队比较小时,这不会有什么问题。当团队越来越大,公司业务越来越复杂后,依赖问题如果不解决,就会成为大问题。

    文件的依赖,目前在绝大部分类库框架里,比如国外的 YUI3 框架、国内的 KISSY 等类库,目前是通过配置的方式来解决。

    YUI.add('my-module', function (Y) {
      // ...
    }, '0.0.1', {
        requires: ['node', 'event']
    });
    

    上面的代码,通过 requires 等方式来指定当前模块的依赖。这很大程度上可以解决依赖问题,但不够优雅。当模块很多,依赖很复杂时,烦琐的配置会带来不少隐患。

    命名冲突和文件依赖,是前端开发过程中的两个经典问题。下来我们看如何通过模块化开发来解决。为了方便描述,我们使用 Sea.js 来作为模块化开发框架。

    使用 Sea.js 来解决

    Sea.js 是一个成熟的开源项目,核心目标是给前端开发提供简单、极致的模块化开发体验。这里不多做介绍,有兴趣的可以访问 seajs.org 查看官方文档。

    使用 Sea.js,在书写文件时,需要遵守 CMD (Common Module Definition)模块定义规范。一个文件就是一个模块。前面例子中的 util.js 变成

    define(function(require, exports) {
      exports.each = function (arr) {
        // 实现代码
      };
    
      exports.log = function (str) {
        // 实现代码
      };
    });
    

    通过 exports 就可以向外提供接口。这样,dialog.js 的代码变成

    define(function(require, exports) {
      var util = require('./util.js');
    
      exports.init = function() {
        // 实现代码
      };
    });
    

    关键部分到了!我们通过 require('./util.js') 就可以拿到 util.js 中通过 exports 暴露的接口。这里的 require 可以认为是 Sea.js 给 JavaScript 语言增加的一个 语法关键字,通过 require 可以获取其他模块提供的接口。

    这其实一点也不神奇。作为前端工程师,对 CSS 代码一定也不陌生。

    @import url("base.css");
    
    #id { ... }
    .class { ... }
    

    Sea.js 增加的 require 语法关键字,就如 CSS 文件中的 @import 一样,给我们的源码赋予了依赖引入功能。

    如果你是后端开发工程师,更不会陌生。Java、Python、C# 等等语言,都有 includeimport 等功能。JavaScript 语言本身也有类似功能,但目前还处于草案阶段,需要等到 ES6 标准得到主流浏览器支持后才能使用。

    这样,在页面中使用 dialog.js 将变得非常简单。

    <script src="sea.js"></script>
    <script>
    seajs.use('dialog', function(Dialog) {
      Dialog.init(/* 传入配置 */);
    });
    </script>
    

    首先要在页面中引入 sea.js 文件,这一般通过页头全局把控,也方便更新维护。想在页面中使用某个组件时,只要通过 seajs.use 方法调用。

    好好琢磨以上代码,我相信你已经看到了 Sea.js 带来的两大好处:

    1. 通过 exports 暴露接口。这意味着不需要命名空间了,更不需要全局变量。这是一种彻底的命名冲突解决方案。
    2. 通过 require 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖,其他事情 Sea.js 都会自动处理好。对模块开发者来说,这是一种很好的 关注度分离,能让程序员更多地享受编码的乐趣。

    小结

    除了解决命名冲突和依赖管理,使用 Sea.js 进行模块化开发还可以带来很多好处:

    1. 模块的版本管理。通过别名等配置,配合构建工具,可以比较轻松地实现模块的版本管理。
    2. 提高可维护性。模块化可以让每个文件的职责单一,非常有利于代码的维护。Sea.js 还提供了 nocache、debug 等插件,拥有在线调试等功能,能比较明显地提升效率。
    3. 前端性能优化。Sea.js 通过异步加载模块,这对页面性能非常有益。Sea.js 还提供了 combo、flush 等插件,配合服务端,可以很好地对页面性能进行调优。
    4. 跨环境共享模块。CMD 模块定义规范与 Node.js 的模块规范非常相近。通过 Sea.js 的 Node.js 版本,可以很方便实现模块的跨服务器和浏览器共享。

    模块化开发并不是新鲜事物,但在 Web 领域,前端开发是新生岗位,一直处于比较原始的刀耕火种时代。直到最近两三年,随着 Dojo、YUI3、Node.js 等社区的推广和流行,前端的模块化开发理念才逐步深入人心。

    前端的模块化构建可分为两大类。一类是以 Dojo、YUI3、国内的 KISSY 等类库为代表的大教堂模式。在大教堂模式下,所有组件都是颗粒化、模块化的,各组件之间层层分级、环环相扣。另一类是以 jQuery、RequireJS、国内的 Sea.js、OzJS 等类库为基础的集市模式。在集市模式下,所有组件彼此独立、职责单一,各组件通过组合松耦合在一起,协同完成开发。

    这两类模块化构建方式各有应用场景。从长远来看,小而美更具备宽容性和竞争力,更能形成有活力的生态圈。

    总之,模块化能给前端开发带来很多好处。如果你还没有尝试,不妨从试用 Sea.js 开始。

    (完) 特别感谢这篇文章: http://chaoskeh.com/blog/why-seajs.html 参考了部分内容。


    2013-04-23

    补充一篇很不错的入门文档:一步步学会使用 Sea.js 2.0

    documentation 
    opened by lifesinger 66
  • CMD 模块定义规范

    CMD 模块定义规范

    CMD 模块定义规范

    在 Sea.js 中,所有 JavaScript 模块都遵循 CMD(Common Module Definition) 模块定义规范。该规范明确了模块的基本书写格式和基本交互规则。

    在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:

    define(factory);
    

    define Function

    define 是一个全局函数,用来定义模块。

    define define(factory)

    define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。

    factory 为对象、字符串时,表示模块的接口就是该对象、字符串。比如可以如下定义一个 JSON 数据模块:

    define({ "foo": "bar" });
    

    也可以通过字符串定义模板模块:

    define('I am a template. My name is {{name}}.');
    

    factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:requireexportsmodule

    define(function(require, exports, module) {
    
      // 模块代码
    
    });
    

    define define(id?, deps?, factory)

    define 也可以接受两个以上参数。字符串 id 表示模块标识,数组 deps 是模块依赖。比如:

    define('hello', ['jquery'], function(require, exports, module) {
    
      // 模块代码
    
    });
    

    iddeps 参数可以省略。省略时,可以通过构建工具自动生成。

    注意:带 iddeps 参数的 define 用法不属于 CMD 规范,而属于 Modules/Transport 规范。

    define.cmd Object

    一个空对象,可用来判定当前页面是否有 CMD 模块加载器:

    if (typeof define === "function" && define.cmd) {
      // 有 Sea.js 等 CMD 模块加载器存在
    }
    

    require Function

    requirefactory 函数的第一个参数。

    require require(id)

    require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口。

    define(function(require, exports) {
    
      // 获取模块 a 的接口
      var a = require('./a');
    
      // 调用模块 a 的方法
      a.doSomething();
    
    });
    

    注意:在开发时,require 的书写需要遵循一些 简单约定

    require.async require.async(id, callback?)

    require.async 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。

    define(function(require, exports, module) {
    
      // 异步加载一个模块,在加载完成时,执行回调
      require.async('./b', function(b) {
        b.doSomething();
      });
    
      // 异步加载多个模块,在加载完成时,执行回调
      require.async(['./c', './d'], function(c, d) {
        c.doSomething();
        d.doSomething();
      });
    
    });
    

    注意require 是同步往下执行,require.async 则是异步回调执行。require.async 一般用来加载可延迟异步加载的模块。

    require.resolve require.resolve(id)

    使用模块系统内部的路径解析机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的绝对路径。

    define(function(require, exports) {
    
      console.log(require.resolve('./b'));
      // ==> http://example.com/path/to/b.js
    
    });
    

    这可以用来获取模块路径,一般用在插件环境或需动态拼接模块路径的场景下。

    exports Object

    exports 是一个对象,用来向外提供模块接口。

    define(function(require, exports) {
    
      // 对外提供 foo 属性
      exports.foo = 'bar';
    
      // 对外提供 doSomething 方法
      exports.doSomething = function() {};
    
    });
    

    除了给 exports 对象增加成员,还可以使用 return 直接向外提供接口。

    define(function(require) {
    
      // 通过 return 直接提供接口
      return {
        foo: 'bar',
        doSomething: function() {}
      };
    
    });
    

    如果 return 语句是模块中的唯一代码,还可简化为:

    define({
      foo: 'bar',
      doSomething: function() {}
    });
    

    上面这种格式特别适合定义 JSONP 模块。

    特别注意:下面这种写法是错误的!

    define(function(require, exports) {
    
      // 错误用法!!!
      exports = {
        foo: 'bar',
        doSomething: function() {}
      };
    
    });
    

    正确的写法是用 return 或者给 module.exports 赋值:

    define(function(require, exports, module) {
    
      // 正确写法
      module.exports = {
        foo: 'bar',
        doSomething: function() {}
      };
    
    });
    

    提示exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口。

    module Object

    module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。

    module.id String

    模块的唯一标识。

    define('id', [], function(require, exports, module) {
    
      // 模块代码
    
    });
    

    上面代码中,define 的第一个参数就是模块标识。

    module.uri String

    根据模块系统的路径解析规则得到的模块绝对路径。

    define(function(require, exports, module) {
    
      console.log(module.uri); 
      // ==> http://example.com/path/to/this/file.js
    
    });
    

    一般情况下(没有在 define 中手写 id 参数时),module.id 的值就是 module.uri,两者完全相同。

    module.dependencies Array

    dependencies 是一个数组,表示当前模块的依赖。

    module.exports Object

    当前模块对外提供的接口。

    传给 factory 构造方法的 exports 参数是 module.exports 对象的一个引用。只通过 exports 参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports 来实现:

    define(function(require, exports, module) {
    
      // exports 是 module.exports 的一个引用
      console.log(module.exports === exports); // true
    
      // 重新给 module.exports 赋值
      module.exports = new SomeClass();
    
      // exports 不再等于 module.exports
      console.log(module.exports === exports); // false
    
    });
    

    注意:对 module.exports 的赋值需要同步执行,不能放在回调函数里。下面这样是不行的:

    // x.js
    define(function(require, exports, module) {
    
      // 错误用法
      setTimeout(function() {
        module.exports = { a: "hello" };
      }, 0);
    
    });
    

    在 y.js 里有调用到上面的 x.js:

    // y.js
    define(function(require, exports, module) {
    
      var x = require('./x');
    
      // 无法立刻得到模块 x 的属性 a
      console.log(x.a); // undefined
    
    });
    

    小结

    这就是 CMD 模块定义规范的所有内容。经常使用的 API 只有 define, require, require.async, exports, module.exports 这五个。其他 API 有个印象就好,在需要时再来查文档,不用刻意去记。

    与 RequireJS 的 AMD 规范相比,CMD 规范尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。通过 CMD 规范书写的模块,可以很容易在 Node.js 中运行,后续会介绍。

    祝使用愉快,有任何想法建议,欢迎反馈留言。

    documentation 
    opened by lifesinger 64
  • 前端模块化开发那点历史

    前端模块化开发那点历史

    最近不断有人问及,想起前些天跟 @dexteryy 等人的讨论:https://github.com/dexteryy/OzJS/issues/10 当时有过简单总结,重新梳理如下。

    写在前面

    1. 不谈什么:传统的模块化开发方式,比如文件拆分、全局变量、命名空间,以及 YUI3 式的模块化开发方式。有兴趣的可阅读:#547
    2. 谈什么: 关于 CommonJS、AMD、Node.js、CMD 等相关的故事与未来趋势,很有意思。
    3. 不一定精准:本文是基于史实的扯淡,因此部分文字特别是时间都是模糊记忆,不一定精准。关于流派、趋势则是个人在社区的感受,不代表客观看法。(看法都是主观的,呵呵)

    CommonJS 社区

    大概 09 年 - 10 年期间,CommonJS 社区大牛云集。CommonJS 原来叫 ServerJS,推出 Modules/1.0 规范后,在 Node.js 等环境下取得了很不错的实践。

    09年下半年这帮充满干劲的小伙子们想把 ServerJS 的成功经验进一步推广到浏览器端,于是将社区改名叫 CommonJS,同时激烈争论 Modules 的下一版规范。分歧和冲突由此诞生,逐步形成了三大流派:

    1. Modules/1.x 流派。这个观点觉得 1.x 规范已经够用,只要移植到浏览器端就好。要做的是新增 Modules/Transport 规范,即在浏览器上运行前,先通过转换工具将模块转换为符合 Transport 规范的代码。主流代表是服务端的开发人员。现在值得关注的有两个实现:越来越火的 component 和走在前沿的 es6 module transpiler
    2. Modules/Async 流派。这个观点觉得浏览器有自身的特征,不应该直接用 Modules/1.x 规范。这个观点下的典型代表是 AMD 规范及其实现 RequireJS。这个稍后再细说。
    3. Modules/2.0 流派。这个观点觉得浏览器有自身的特征,不应该直接用 Modules/1.x 规范,但应该尽可能与 Modules/1.x 规范保持一致。这个观点下的典型代表是 BravoJS 和 FlyScript 的作者。BravoJS 作者对 CommonJS 的社区的贡献很大,这份 Modules/2.0-draft 规范花了很多心思。FlyScript 的作者提出了 Modules/Wrappings 规范,这规范是 CMD 规范的前身。可惜的是 BravoJS 太学院派,FlyScript 后来做了自我阉割,将整个网站(flyscript.org)下线了。这个故事有点悲壮,下文细说。

    AMD 与 RequireJS

    再来说 AMD 规范。真正的 AMD 规范在这里:Modules/AsynchronousDefinition。AMD 规范一直没有被 CommonJS 社区认同,核心争议点如下:

    执行时机有异议

    看代码

    Modules/1.0:

    var a = require("./a") // 执行到此处时,a.js 才同步下载并执行
    

    AMD:

    define(["require"], function(require) {
      // 在这里,模块 a 已经下载并执行好
      // ...
      var a = require("./a") // 此处仅仅是取模块 a 的 exports
    
    })
    

    AMD 里提前下载 a.js 是浏览器的限制,没办法做到同步下载,这个社区都认可。

    但执行,AMD 里是 Early Executing,Modules/1.0 里是第一次 require 时才执行。这个差异很多人不能接受,包括持 Modules/2.0 观点的也不能接受。

    这个差异,也导致实质上 Node 的模块与 AMD 模块是无法共享的,存在潜在冲突。

    模块书写风格有争议

    AMD 风格下,通过参数传入依赖模块,破坏了 就近声明 原则。比如:

    define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
    
        // 等于在最前面申明并初始化了要用到的所有模块
    
       if (false) {
           // 即便压根儿没用到某个模块 b,但 b 还是提前执行了
           b.foo()
       }
    
    })
    

    还有就是 AMD 下 require 的用法,以及增加了全局变量 define 等细节,当时在社区被很多人不认可。

    最后,AMD 从 CommonJS 社区独立了出去,单独成为了 AMD 社区。有阵子,CommonJS 社区还要求 RequireJS 的文档里,不能再打 CommonJS 的旗帜(这个 CommonJS 社区做得有点小气)。

    脱离了 CommonJS 社区的 AMD 规范,实质上演化成了 RequireJS 的附属品。比如

    1. AMD 规范里增加了对 Simplified CommonJS Wrapper 格式的支持。这个背后是因为 RequireJS 社区有很多人反馈想用 require 的方式,最后 RequireJS 作者妥协,才有了这个半残的 CJS 格式支持。(注意这个是伪支持,背后依旧是 AMD 的运行逻辑,比如提前执行。)
    2. AMD 规范的演进,离不开 RequireJS。这有点像 IE…… 可能是我的偏见。

    AMD 的流行,很大程度上取决于 RequireJS 作者的推广,这有点像 less 因 Bootstrap 而火起来一样。但火起来的东西未必好,比如个人觉得 stylus 就比 less 更优雅好用。

    关于 AMD 和 RequireJS,暂且按下不表。来看另一条暗流:Modules/2.0 流派。

    Modules/2.0

    BravoJS 的作者 Wes Garland 有很深厚的程序功底,在 CommonJS 社区也非常受人尊敬。但 BravoJS 本身非常学院派,是为了论证 Modules/2.0-draft 规范而写的一个项目。学院派的 BravoJS 在实用派的 RequireJS 面前不堪一击,现在基本上只留存了一些美好的回忆。

    这时,Modules/2.0 阵营也有一个实战派:FlyScript。FlyScript 抛去了 Modules/2.0 中的学究气,提出了非常简洁的 Modules/Wrappings 规范:

    module.declare(function(require, exports, module)
    {
       var a = require("a"); 
       exports.foo = a.name; 
    });
    

    这个简洁的规范考虑了浏览器的特殊性,同时也尽可能兼容了 Modules/1.0 规范。悲催的是,FlyScript 在推出正式版和官网之后,RequireJS 当时正直红火。期间 FlyScript 作者 khs4473 和 RequireJS 作者 James Burke 有过一些争论。再后来,FlyScript 作者做了自我阉割,将 GitHub 上的项目和官网都清空了,官网上当时留了一句话,模糊中记得是

    我会回来的,带着更好的东西。
    

    这中间究竟发生了什么,不得而知。后来我有发邮件给 @khs4473 询问,khs 给了两点挺让我尊重的理由,大意是

    1. 我并非前端出身,RequireJS 的作者 James Burke 比我更懂浏览器。
    2. 我们应该协同起来推动一个社区的发展,即便它不是你喜欢的。

    这两句话对我影响很大。也是那之后,开始仔细研究 RequireJS,并通过邮件等方式给 RequireJS 提出过不少建议。

    再后来,在实际使用 RequireJS 的过程中,遇到了很多坑。那时 RequireJS 虽然很火,但真不够完善。期间也在寻思着 FlyScript 离开时的那句话:“我会回来的,带着更好的东西”

    我没 FlyScript 的作者那么伟大,在不断给 RequireJS 提建议,但不断不被采纳后,开始萌生了自己写一个 loader 的念头。

    这就是 Sea.js。

    Sea.js 借鉴了 RequireJS 的不少东西,比如将 FlyScript 中的 module.declare 改名为 define 等。Sea.js 更多地来自 Modules/2.0 的观点,但尽可能去掉了学院派的东西,加入了不少实战派的理念。

    最后

    写着写着,有点沧桑感,不想写了。

    历史不是过去,历史正在上演。随着 W3C 等规范、以及浏览器的飞速发展,前端的模块化开发会逐步成为基础设施。一切终究都会成为历史,未来会更好。

    documentation 
    opened by lifesinger 63
  • PullToRefresh中endReachedRefresh上拉加载后界面不会自动收回

    PullToRefresh中endReachedRefresh上拉加载后界面不会自动收回

    PullToRefresh中endReachedRefresh上拉加载后界面不会自动收回,有遇到过吗? ![image](https://user-images.githubusercontent.com/38171942/92340527-4db75f80-f0ed-11ea-8f82-bcbe5c4da1ec.png 底部是完成刷新一直存在。

    opened by NOKSAS 0
  • Fix simple typo: themeselves -> themselves

    Fix simple typo: themeselves -> themselves

    Issue Type

    [x] Bug (Typo)

    Steps to Replicate

    1. Examine tests/specs/util/events.js.
    2. Search for themeselves.

    Expected Behaviour

    1. Should read themselves.
    opened by timgates42 0
Releases(2.2.3)
curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.

curl (cujoJS resource loader) All development for curl.js and cram.js has stopped. For the foreseeable future, we will continue to respond to issues o

The Javascript Architectural Toolkit 1.9k Dec 30, 2022
Dynamic ES module loader

SystemJS SystemJS is a hookable, standards-based module loader. It provides a workflow where code written for production workflows of native ES module

null 12.4k Dec 29, 2022
:skull: An ancient tiny JS and CSS loader from the days before everyone had written one. Unmaintained.

LazyLoad Note: LazyLoad is no longer being maintained. I'm not responding to issues or pull requests, since I don't use this project anymore and don't

Ryan Grove 1.4k Jan 3, 2023
Asyncronous JavaScript loader and dependency manager

$script.js - Async JavaScript loader & dependency manager $script.js is an asynchronous JavaScript loader and dependency manager with an astonishingly

Dustin Diaz 2.9k Jan 3, 2023
enterprise standard loader

ESL (Enterprise Standard Loader) ESL是一个浏览器端、符合AMD的标准加载器,适合用于现代Web浏览器端应用的入口与模块管理。 ESL is a browser-only, amd-compliant module loader. In modern web app

Baidu EFE team 833 Dec 16, 2022
Lightweight JavaScript module system.

modulejs Lightweight JavaScript module system. License The MIT License (MIT) Copyright (c) 2020 Lars Jung (https://larsjung.de) Permission is hereby g

Lars Jung 124 Dec 21, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
A Module Loader for the Web

A Module Loader for the Web Sea.js is a module loader for the web. It is designed to change the way that you organize JavaScript. With Sea.js, it is p

seajs 8.3k Jan 3, 2023
An npm package for demonstration purposes using TypeScript to build for both the ECMAScript Module format (i.e. ESM or ES Module) and CommonJS Module format. It can be used in Node.js and browser applications.

An npm package for demonstration purposes using TypeScript to build for both the ECMAScript Module format (i.e. ESM or ES Module) and CommonJS Module format. It can be used in Node.js and browser applications.

Snyk Labs 57 Dec 28, 2022
A file and module loader for JavaScript

RequireJS RequireJS loads plain JavaScript files as well as more defined modules. It is optimized for in-browser use, including in a Web Worker, but i

null 12.9k Dec 27, 2022
curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.

curl (cujoJS resource loader) All development for curl.js and cram.js has stopped. For the foreseeable future, we will continue to respond to issues o

The Javascript Architectural Toolkit 1.9k Dec 30, 2022
Dynamic ES module loader

SystemJS SystemJS is a hookable, standards-based module loader. It provides a workflow where code written for production workflows of native ES module

null 12.4k Dec 29, 2022
Fintoc.js ES Module - Use the Fintoc widget as an ES module

Fintoc.js ES Module Use the Fintoc widget as an ES module. Installation Install using npm! (or your favourite package manager) # Using npm npm install

Fintoc 6 May 13, 2022
Template Repository for making your own budder Module. CORE is not included, this is just for the module.

A quick copy of the "How to make your own module" section Check out the official budderAPI repository Template Repository for making your own budder M

Logic 2 Apr 3, 2022
Userland module that implements the module path mapping that Node.js does with "exports" in package.json

exports-map Userland module that implements the module path mapping that Node.js does with "exports" in package.json npm install exports-map Usage co

Mathias Buus 9 May 31, 2022
A module federation SDK which is unrelated to tool chain for module consumer.

hel-micro, 模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 Demo hel-loadash codesandbox hel-loadash git Why hel-micro 如何使用远程模块 仅需要一句npm命令即可载入远程模块,查看下面例子线上示例 1 安装hel-micr

腾讯TNTWeb前端团队 319 Jan 3, 2023