如何强制TypeScript模块内容在运行时执行?
问题描述
我有多个仅包含TypeScript类的模块,每个类都带有类装饰器,作用是把类信息添加到一个Map中。这些类从来不会通过名称直接实例化,而是由应用的其他部分通过访问这个Map获取类信息来创建对象。
现在的问题是:因为这些模块里的内容从未被显式引用,运行时模块不会被评估,导致类装饰器没被执行,Map里也没任何内容。
我试过两种临时解决办法,但都属于hack手段:
- 在其他模块里对每个模块的某个类执行无意义的
new操作(只要一个就能强制模块评估); - 在每个TS模块里加一个空函数,初始化时从其他模块调用这个函数。
想知道有没有其他方法,可以强制那些未被应用其他部分显式引用的模块在运行时被评估?仅导入模块无法实现这个效果。
解决方案
1. 动态导入模块
在应用初始化的入口文件中,批量动态导入目标模块,无需引用任何导出内容,仅触发导入操作即可强制模块评估:
// 入口文件 async function init() { // 列出所有需要加载的类模块路径 const modulePaths = [ './classA.ts', './classB.ts', './classC.ts' ]; // 并行导入所有模块 await Promise.all(modulePaths.map(path => import(path))); // 此时装饰器已执行,Map中已包含类信息 } init();
如果是Node.js环境,也可以直接用require加载:
// Node.js环境 const modulePaths = [ './classA', './classB' ]; modulePaths.forEach(path => require(path));
2. 配置构建工具保留副作用模块
如果使用Webpack、Vite这类构建工具,默认的tree-shaking会剔除未被引用的模块。可以通过配置标记这些模块为有副作用(装饰器执行属于副作用),避免被剔除:
- Webpack:在
webpack.config.js中对目标模块设置sideEffects: true:
const path = require('path'); module.exports = { module: { rules: [ { test: /\.ts$/, include: path.resolve(__dirname, './classes'), // 类模块所在目录 sideEffects: true } ] } };
之后在入口文件中静态导入模块即可:
import './classA.ts'; import './classB.ts';
- Vite:在
package.json中添加sideEffects字段指定目标模块:
{ "sideEffects": [ "./src/classes/*.ts" ] }
同样在入口文件静态导入模块,Vite会保留并评估这些模块。
3. 创建模块索引统一导入
在类模块所在目录创建index.ts,统一导出所有模块:
// ./classes/index.ts export * from './classA.ts'; export * from './classB.ts'; export * from './classC.ts';
然后在入口文件导入该索引模块(无需使用导出内容):
import './classes/index.ts';
结合构建工具的sideEffects配置,索引模块会被评估,进而触发所有子模块的装饰器执行。
内容的提问来源于stack exchange,提问作者Tom Hoffman
相关产品推荐
相关产品推荐

