将大型Typescript项目转换为ES6模块

时间:2018-10-03 17:41:00

标签: typescript es6-modules

我有一个相当大的应用程序(约650个文件),目前有混合实现ES6模块和旧版全局命名空间内部模块和类。

我想使用100%ES6模块。

迭代方法

要到达那里,我需要首先通过添加“ export”关键字将所有全局对象转换为ES6模块。

添加“ export”后,该全局对象将不再是全局对象,并且使用该对象的每个文件现在都出现了编译器错误“找不到对象”(即无法读取未定义的属性“ xxx”)。 / p>

要解决此问题,必须将“导入”添加到文件中,从而将其转换为ES6模块,该模块进而“取消全局”该文件中的所有对象,从而导致出现新的“找不到对象”错误。其他文件。

简而言之,这种迭代方法似乎效果不佳。

可能的“一举一动”解决方案:

  1. 遍历所有ts文件
    1. 以编程方式将export添加到所有顶级类,模块和变量。
    2. 将这些收集到列表中
  2. 生成桶(globalBarrel)文件,然后重新导出上一步中收集的所有出口。
  3. 再次遍历所有ts文件
    1. 对于每个ts文件,在每个文件中添加import {list, of, symbols, exported, by, the, barrel,file} from "./globalBarrel"
  4. 编译干净吗?
    1. 可能需要解决一些循环依赖问题。做到这一点。
  5. 在以后编辑每个文件时,请使用vsCode“组织导入”命令删除许多不必要的文件。

@ jfriend000说:

  

采用非模块化代码,并尝试以编程方式将其转换为   进入模块只会造成混乱。

但是一次性将所有内容都放入模块中将使 true 模块化过程更加容易。

问题

这是解决此问题的最佳方法吗?有什么建议吗?

2 个答案:

答案 0 :(得分:2)

  

这是解决此问题的最佳方法吗?有什么建议吗?

我怀疑这是个好方法,当然也不是最好的方法。

采用非模块化代码并尝试以编程方式将其转换为模块形式,只会造成混乱。我敢肯定它是可以做到的,但是它并没有真正获得任何好处。它使事情变得比原来可能更混乱。您将把一个非模块化的架构弄得一团糟,变成了许多非模块化,高度交叉依赖的模块。您的体系结构将不会得到改善,并且代码现在会变得更加复杂,而不是那么复杂。

更好的方法是将功能区域逐步重新设计为实际上是“模块化”的。为功能区域创建接口,将其打包在模块中,然后转换该功能的所有用户以导入该接口并使用它。从字面上看,可以一次完成一个功能区域。您不必一次将整个事情分解,然后再将它们放回去。

要摆脱共享的全局变量,需要重新考虑设计。仅将一堆共享的全局变量包装到一个模块中(您现在使每个人都可以导入它)并不能真正改善设计-实际上,这甚至可能使情况变得更糟。代码与以前一样交织在一起,相互依赖。

您可以一次一次地在代码的一个功能区域内逐步进行模块化的重新设计,而不必一口气就造成巨大的混乱,而这实际上并没有改善代码的体系结构。

如果要解决此问题,我可能会创建程序所有主要功能的顶层图表,并确保650个文件中的每个文件都显示在该图中。然后,我将开始逐步挑选最简单的模块进行模块化(具有最干净的界面和最少的意大利面条依赖性)。随着越来越多的事情进入模块,其余部分开始变得不那么复杂。如果确实可以访问遍历代码的全局变量,那么您将真的必须重新考虑该设计的各个部分,要么创建包含数据的对象并将其传递,要么将全局数据移至相关模块中,并为以下对象提供导出的访问器:该数据。

答案 1 :(得分:2)

  

要到达那里,我需要首先通过添加“ export”关键字将所有全局对象转换为ES6模块。

     

添加“ export”后,该全局对象将不再是全局对象,并且使用该对象的每个文件现在都出现了编译器错误“找不到对象”(即无法读取未定义的属性“ xxx”)。 / p>      

要解决此问题,必须将“导入”添加到文件中,从而将其转换为ES6模块,该模块进而“取消全局”该文件中的所有对象,从而导致出现新的“找不到对象”错误。其他文件。

对。避免这种恶性循环的诀窍是,每次将文件转换为模块时,还要将该模块分配给一个全局变量,您可以从其他非模块文件中引用该全局变量,而无需将它们转换为模块。这需要一些样板。 this open suggestion会稍微减少样板。

我假设您当前必须使用某种捆绑工具来确保所有非模块文件都已加载并有助于单个全局作用域,以便它们可以访问彼此的定义。首先使用以下代码创建文件,然后配置捆绑程序以确保其首先运行:

namespace Modules {
    // Force `Modules` to be created at runtime.
    (() => {})();
}

现在,如果您开始使用:

// a.ts
namespace A {
    export const a = 42;
}

// b.ts
namespace B {
    console.log(A.a);
}

您可以过渡到:

// a.ts
export const a = 42;

import * as A_ from "./a";
declare global {
    namespace Modules {
        export import A = A_;
    }
}
Modules.A = A_;

// b.ts
namespace B {
    console.log(Modules.A.a);
}

b.ts将能够使用完整类型信息访问Modules.A,而不必成为模块本身(捆绑程序的模数加载顺序问题)。