【问题标题】:Building Javascript Modules构建 Javascript 模块
【发布时间】:2016-10-25 13:16:17
【问题描述】:

我有用于客户端路由和模板加载的小型库。 它由几个较小的模块构建而成,例如 Tpl、Router..

每个模块检查是否定义了库命名空间,然后将自己应用到它。

这里是代码:https://github.com/sgoran/micro

例如 Tpl 组件将自身绑定到 Micro 库(主库)

if(typeof Micro === "function" && Micro.prototype.isMicro){
      Micro['Tpl'] = Tpl;

然后我用构造函数调用库

var micro = new Micro(properties);

问题是如果我想创建另一个实例...依赖关系会在内部发生冲突

var micro2 = new Micro(properties);

对于构建,我使用 gulp 并将模块连接到一个文件..

谁能提出一种将多个模块合二为一的好方法,比如沙盒? 或者一些不使用 webpack、requireJs 等的最佳实践和模式。

【问题讨论】:

  • 如果您的业务逻辑是模块化的,并且模块之间有很多依赖关系,我建议您使用CommonJs 架构。它是 NodeJs 使用的架构。你熟悉 NodeJs 吗?
  • 是的,我熟悉 NodeJs 和 CommonJS 方法。它使用 export 和 require.. 但我需要使用 RequireJS 或类似的.. 我更喜欢一些自定义解决方案

标签: javascript design-patterns dependency-injection


【解决方案1】:

按原样使用module pattern

// Module1.js
var Module1 = (function(exports) {
   exports.Micro = function() {};
   exports.Micro.prototype = {
       // Properties...
   };
})(Module1 || {});

// Module2.js
var Module2 (function(exports, Module1) {
    var micro = new Module1.Micro();
})(exports, Module1); 

// Module3.js
var Module3 (function(exports, Module1) {
    // No collission here because Module3 creates an isolated scope
    // like Module2 already does too!
    var micro = new Module1.Micro();
})(exports, Module1); 

如果不想污染全局范围...

...您可以实现子模块。您将无法完全避免全局范围污染,但您将限制它以声明顶级模块:

// Module1.js
var Module1 = (function(Module1) {
    exports.Micro = function() {};
    exports.Micro.prototype = {
         // Properties...
    };
})(Module1 || {});

// Module2.js
(function(Module1) {
    Module1.Module2 = Module1.Module2 || {};

    exports.Other = function() {

    };

    exports.a = 11;
})(Module1 || {});

顺便说一句,使用SystemJS 之类的解决方案来配置您的模块并避免依赖地狱(否则,您需要手动添加脚本文件并以特定顺序让您的依赖模块可以使用...)。

【讨论】:

  • 命名空间也可以是函数本身,就像OP的设计一样,没关系。这没有回答问题。
  • @plalx OP 可能不应该使用命名空间之类的函数。建议是 OP 应该利用 module pattern。这是我对 OP 的问题/担忧的回答。我不确定我的回答是否解决了这个问题。如果我要回答 OP 如何期望解决方案的问题,那就太有限了……那么,为什么要在 StackOverflow 中提问呢? :D
  • 我目前不想使用 SystemJS、Browsify 或任何其他工具,即使我知道这样可以轻松完成。当前的目标是也学习一些东西并包括我的大脑,而不是立即依赖大量工具。我喜欢使用 grunt 来实现自动化。我可能应该在每个 Micro 创建时创建新的依赖对象,并且事情应该可以工作..
  • @sgora si 我已经为您提供了一个普通的解决方案.. System JS 只是一个建议
  • 我说这不能回答 OP 的问题,因为您没有解释为什么他不能拥有多个 Micro 实例,这是主要问题。您提出的方法与 OP 已经在做的相同或非常接近,但并不能解决该问题。这完全取决于内部如何实现Micro 构造函数。
【解决方案2】:

您只需在 Micro 构造函数本身中删除 all 共享状态。例如,对于me.events = Micro.Pubsub;,所有实例将共享相同的Pubsub 实例,这是有问题的,但您可以通过为每个Micro 实例实例化一个新的Pubsub 来解决这个问题。可能有更多共享状态(例如document.querySelectorAll('[hub-link]')),但我还没有深入挖掘。

一旦你摆脱了Micro 构造函数中的共享状态,仍然存在问题的是让多个Micro 实例使用不同的子模块(例如Tpl、Routes)。那是因为您没有使用任何形式的依赖反转来从 Micro 构造函数中解析这些子模块。

这可能不是问题,因为我怀疑单个应用程序是否会同时使用不同的子模块实现。不过,您可能希望明确依赖并允许将子模块依赖注入Micro 构造函数。

【讨论】:

    【解决方案3】:

    在不使用任何额外代码(通过 CommonJS 或 AMD 工具)的情况下分割应用程序的一种很好的方法是在每个子模块的末尾检查是否存在主模块..

    如果它不存在,我们可以全局暴露模块并单独使用它,测试它或类似的。

    ;(function (window, document){
    
        function Tpl(props){
    
        }
    
        Tpl.prototye = {
          // some methods
        }
    
    
        if(typeof Micro === "function" && Micro.prototype.isMicro){
          Micro['Tpl'] = Tpl;
        }
        else if ( typeof module != 'undefined' && module.exports ){
            module.exports = Tpl;
        }else if( typeof define == 'function' && define.amd ){
            define( function () { return Tpl; }); 
        }
        else{
            window.Tpl = Tpl;
        }
    
    
    
    }(window, document));
    

    **在主模块内声明**

    me.tpl = new Micro.Tpl(props);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-27
      • 1970-01-01
      • 2015-01-23
      相关资源
      最近更新 更多