【问题标题】:How to spread module across multiple AMD files?如何将模块分布在多个 AMD 文件中?
【发布时间】:2012-12-13 07:12:09
【问题描述】:

我不知道是否有可能将“导出模块”分布在多个文件中。

如果我有文件 Contact.ts:

// file Contact.ts
export module Contacts {
   export class Contact {
      ...
   }
}

和另一个 ContactView.ts

// file ContactView.ts
export module Contacts {
   export class ContactView {
      model: Contact;  // <---  is not recognized
   }
}

那么 TSC 无法识别 Contact 类。如您所见,Contact 和 ContactView 被声明为驻留在同一个模块中,并且根据规范它应该可以工作。

我正在构建一个使用 require.js 和 AMD 模式的复合应用程序,因此我必须使用“导出模块”声明。

我应该做一些“提前声明”还是一些棘手的“导入”?

感谢您的建议。

编辑:目前我通过导入分别加载每个模块,但是,如果您注意到,它会造成大量代码浪费和大量“导入”依赖项。 我的问题是,是否有办法使用相同的命名空间(即联系人)来告知我不想导入的 TS。 我正在研究正常的 // 命令,但它不起作用。到目前为止,我什至尝试了 *.d.ts 声明文件,但没有成功。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    该规范允许您跨多个文件定义 internal 模块(本质上,内部模块是指 javascript 模块模式)。 外部 模块,例如 AMD 或 CommonJS 模块,认为每个文件都是实际的“代码模块”,并且其中的命名空间/命名是无关紧要的,因为模块将被加载到它的无论如何都要拥有新对象。

    您可以编写以下代码来在 ContactView.ts 模块中加载 Contact.ts 模块:

    // file ContactView.ts    
    import mod = module("./Contact");
    
    export module Contacts {
       export class ContactView {
          model: mod.Contacts.Contact;  // <---  will be recognized
       }
    }
    

    这应该可以很好地工作,但是如果您想访问另一个区域中两个模块的内容(例如,自己创建一个新的联系人模型),您基本上必须同时导入它们:

    import c = module("./Contact");
    import cv = module("./ContactView");
    

    我认为这已经足够好了,因为您清楚地说明了您的依赖关系。缺点是它们不会共享一个共同的父对象,因此让它们都处于“联系人”模块模式可能没有多大用处。

    另一种选择是将“Contact”与“ContactView”一起导出,如下所示(当然,这段代码有点愚蠢,因为您已经通过 ContactView 的模型属性做到了这一点,但绝不会少......) :

    export module Contacts {
       export class ContactView {
           model: mod.Contacts.Contact;
           constructor() {
               this.model = new mod.Contacts.Contact();
           }
        }
    
        export var Contact = mod.Contacts.Contact;
    }
    

    所以你可以在加载 ContactView 后访问它。

    编辑:顺便说一句,您不仅可以通过“export module Name { ... }”导出模块,还可以导出任何内容,因为文件本身就是模块。所以你可以有一个只有“export function foo() { ... }”的文件,而没有任何模块模式代码包装它。

    EDIT2:看起来 AMD 可能具有加载多个依赖项并从中构建“模块”的功能,但我不知道这在 TS 中如何工作,这里有一个链接:http://www.adobe.com/devnet/html5/articles/javascript-architecture-requirejs-dependency-management.html(构造函数模块)。

    【讨论】:

    • 这正是我现在所做的——通过导入分别加载每个模块,但是,如果你注意到的话,它会浪费大量的代码和数百个依赖项。我的问题是,是否有办法使用相同的命名空间(即联系人)来告知我不想导入的 TS。我正在研究正常的 // 命令,但它不起作用。
    • 在这种情况下,不要导出模块联系人,只需在所有文件中将其定义为“模块联系人{ ... }”,使用 ///(这行得通对于内部模块)帮助 TS 找到它们,并为 AMD 模块创建一个新文件,该文件只有“export var contacts = Contacts;”在其中,您可以通过 AMD 加载整个内容。您必须确保您导出的 var 与模块的名称不同,否则发出的代码将不起作用。很遗憾,我目前无法为此编写代码演示,但如果需要,我可以稍后再编写。
    • 再想一想,您可能需要创建一个makefile,将每个模块输出到它自己的js文件中。
    • 您的演示对正确设置非常有帮助。非常感谢!
    【解决方案2】:

    我在同一个问题上挣扎了一段时间,只是想分享一下我在做什么,以防其他人在这个问题上徘徊。

    首先,我为自己定义了一个引用文件,它声明了我的模块中的所有文件:

    /// <reference path="_contacts.dependencies.ts" />
    /// <reference path="../contacts/Contact.ts" />
    /// <reference path="../contacts/ContactView.ts" />
    /// <reference path="../contacts/ContactModel.ts" />
    

    请注意,文件内指定的路径与参考文件本身 (_contacts.ts) 的位置相关,这与 .js 参考文件不同。我的目录结构如下:

    modules
        references // all of the reference files
            knockout 
            underscore
            // ... a subfolder for every 3rd party library used
        contacts
        commerce 
        // ... other modules at same level as contacts
    

    回到参考文件本身。第一行包含一个单独的参考文件,列出了模块使用的所有外部库,例如下划线、moment 或您拥有.d.ts 定义文件的任何其他现有库。其余行是组成模块的文件。

    在作为模块一部分的每个文件中,我引用了上述文件:

    /// <reference path="../references/_contacts.ts" />
    module Contacts {
        export class Contact { 
            public model: ContactModel;
            // ...
        }
    } 
    

    同样,您可以创建一个参考文件来列出所有模块:

    /// <reference path="_address.ts" />
    /// <reference path="_contacts.ts" />
    /// <reference path="_commerce.ts" />
    

    只需从您的源文件中指向它。

    不过,这并不能解决发出的代码位于单独文件中的问题。对于这个问题,我使用了一个 JavaScript 缩小工具,它能够将多个文件捆绑到一个源文件中。根据您的编译设置和用例需求,您可能需要在生成的代码周围应用一些包装器,以使其作为 AMD 模块工作(还不太熟悉该部分)。

    【讨论】:

    • 至于最后一部分,你也可以在 BeforeBuild 中使用它来编译成单个文件: 编译 _references.ts 文件本身可确保您放置的正确顺序出参考。我不认为 --module 标志只会让它作为一个 AMD 模块工作。我认为为此您需要生成这样的定义文件: tsc --declarations file1.ts file2.ts file3.ts ...
    • 其实,这里刚刚解决了一个与此方法相关的错误:typescript.codeplex.com/workitem/836
    • @Vazgen 感谢您的提醒。但是,我已切换到用于 TypeScript 开发的 JetBrains WebStorm IDE,它现在具有原生 TS 支持。它会根据需要自动编译文件并且通常工作得很好(并且它不会像 VS 那样污染你的源文件夹)。至于捆绑,当所有东西都捆绑在一起时,我找不到源代码,所以投降了,现在链接到各个 js 文件。一旦我接近工作产品,我希望添加一些捆绑的节点自动化。
    猜你喜欢
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 2017-01-02
    • 2011-12-09
    • 2020-01-19
    • 2018-07-13
    • 1970-01-01
    • 2015-01-11
    相关资源
    最近更新 更多