配置具有公共依赖项的TypeScript项目以构建多个纯JavaScript输出文件


10

我目前正在为Bot Land编写一些脚本。Bot Land是一种实时策略游戏,您无需使用鼠标和键盘来控制自己的单位,而是可以编写代码来通过API控制机器人,然后让机器人与其他机器人进行对抗。如果您熟悉SC2中的单位,则可以创建类似于眨眼潜行者,攻城坦克,医护人员和超能力的机器人。(对于软件工程师来说,这是一个非常有趣的游戏,但这超出了此问题的范围。)

机器人土地

Bot控件的复杂度从三个级别提高:默认的AI,类似于Scratch的编程语言以及减少的JavaScript集合,称为BotLandScript。尽管BotLandScript的内置编辑器是合理的,但是您必须将所有代码作为一个文件上载,并在各处使用全局顶级功能。自然,如果您的代码开始变长并且不同的机器人共享相同的功能,那么一段时间后,这将变得很痛苦。

编程环境

为了方便为多个机器人编写代码,减少使用裸露的JS编码时发生意外错误的机会,并增加击败其他玩家的机会,我设置了上述TypeScript项目,以提供一个公共库以及每个机器人的代码。当前目录结构大致类似于以下内容:

lib/ 
  bot.land.d.ts
  common.ts
BlinkStalker/
  BlinkStalker.ts
  tsconfig.json
Artillery/
  Artillery.ts
  tsconfig.json
SmartMelee/
  SmartMelee.ts
  tsconfig.json

lib是bot之间共享的通用代码,并提供(非TS)Bot Land API的TypeScript定义。然后,每个机器人都有自己的文件夹,其中一个文件包含机器人代码,另一个文件包含样板tsconfig.json

{
  "compilerOptions": {
    "target": "es3",
    "module": "none",
    "sourceMap": false,
    "outFile": "bot.js"
  },
  "files": [
    "MissileKite.ts"
  ],
  "include": [
    "../lib/**/*"
  ]
}

tsconfig.json构建bot.js完每个文件后,它会创建一个对应文件,其中包含来自bot本身的转译代码以及中的所有代码common.js。此设置由于以下几个原因而欠佳:需要大量重复的样板,使其很难添加新的bot,为每个bot包含很多不必要的代码,并且要求分别构建每个bot。

但是,根据我到目前为止的研究,似乎没有一种简单的方法可以完成我想要的事情。特别是,使用new tsc -b选项和引用不起作用,因为这需要对代码进行模块化,而Bot Land需要一个文件,且所有功能都在顶层定义。

达成以下尽可能多的最佳方法是什么?

  • 不需要新的样板即可添加新的机器人(例如,tsconfig.json每个机器人不需要)
  • 使用import了常用的功能,以避免输出无用的代码,但随后...
  • 仍以Bot Land的特定格式将所有功能输出为一个文件
  • 一个生成多个输出文件的构建步骤,每个机器人一个
  • 奖励:将构建过程与VS Code集成在一起。当前有一个tasks.json用于构建每个子项目的样板。

我含糊地推测答案可能除了之外还涉及Grunt之类的东西tsc,但是我对此一无所知。


所有漫游器都必须有单独的文件夹吗?还是每个机器人在单个文件的根目录下就足够了?(例如<root>/MissileKite.ts
a1300

1
是否所有已转译的bot文件都必须命名bot.js
a1300

最好在单个文件中扎根;由于存在,它们位于单独的文件夹中tsconfig.json。可以将已翻译的bot文件命名为任何名称,最好是原始文件的.js版本。我现在在回购输出到中以这种方式设置它build/MissileKite.js
安德鲁·毛

1
@ andrew-mao您可以看一下我的GAS项目模板,该模板可以满足您的大多数要求(但针对不同的环境)。如果适合您,下周某个时候我可能会为您进行调整。github.com/PopGoesTheWza/ts-gas-project-starter
PopGoesTheWza

tsconfig-gas.json看有相关的事情?
安德鲁·毛

Answers:


2

这是我试图回答您的要求。

值得注意的文件:

  • src/tsconfig-botland.json保存任何bot.land脚本的设置(包括您移至的自定义声明types/bot-land/index.d.ts)。您可能会更改strict我使用的设置。
  • src/tsconfig.json保存对所有机器人的引用。每当您要添加另一个机器人脚本时,这就是要编辑的文件

Bot脚本至少包含两个文件:最低要求tsconfig.json和一个或多个.ts脚本文件。

例如src/AggroMiner/tsconfig.json

{
    "extends": "../tsconfig-botland",
    "compilerOptions": {
        "outFile": "../../build/AggroMiner.js"
    },
    "files": ["index.ts"],
    "include": ["**/*.ts", "../lib/**/*.ts"]
}

在大多数情况下,要启动新的机器人脚本,您应该:

  1. 将任何Bot文件夹(即src/AggroMiner)复制到下的新文件夹src
  2. 编辑,使用您的漫游器名称src/<newBotFolder>/tsconfig.json进行编辑outFile
  3. 编辑src/tsconfig.json并添加参考src/<newBotFolder>

设置了以下npm/ yarn脚本:

  • build 建造所有机器人
  • build-cleanbuild在运行之前清除文件夹build
  • format.ts在下的所有文件上运行Prettiersrc
  • lint 对所有机器人脚本运行tslint检查

现在满足您的要求:

  • 不需要新的样板即可添加新的机器人(例如,每个机器人无需tsconfig.json)

为此,需要创建一些脚本来枚举您的bots文件夹/脚本...并为每个bot设置相关脚本tsconfig.json并运行tsc。除非绝对必要,否则最少的设置(如上所述)可能就足够了。

  • 对常见功能使用import以避免输出未使用的代码,但是...

首先,请注意,如果您开始使用任何模块export/ import语句,则需要附加的第三方来打包/树状握手,以实现单个文件输出。据我所知,Bot.land的脚本正在服务器上运行。除非死代码对您的机器人性能有影响,否则我真的不会打扰。

  • 仍以Bot Land的特定格式将所有功能输出为一个文件

做完了

  • 一个生成多个输出文件的构建步骤,每个机器人一个

做完了

  • 奖励:将构建过程与VS Code集成在一起。当前有一个用于创建每个子项目的样板任务task.json。

这些npm脚本应该出现在vsc的任务列表中(至少在我的任务列表中如此),因此变得tasks.json不必要。


对于您在此处所做的所有其他操作,Deadcode是一个很好的折衷方案。您能否让我知道为什么使用types/bot-land定义以及为什么选择strict设置?
安德鲁·毛

Types / bot-land / index.d.ts实际上是来自lib的原始.d.ts,已重命名并以不同的方式放置。Î假设它描述了所有脚本的常规bot.land执行上下文,因此,我确保它在每个bot脚本中始终可用。“严格”设置仅在这里,因为我懒惰地复制了我喜欢的设置(与更漂亮的设置相同)。这些应该适应用户(您)的偏好。
PopGoesTheWza

我只是想知道是否有惯常的理由将其放入,types或者这仅仅是您选择的一种特定的组织方式。
毛泽东

唯一的原因是假设它是bot.land上下文。可以将其想像为在nodejs脚本中已经有@ types / node类型可用
-PopGoesTheWza

1
/ types文件夹是放置外部类型声明的常规位置之一(即特定的执行上下文,例如botland引擎或未类型化的JavaScript模块/包,此处未使用)
PopGoesTheWza

3

您实际上可以使用项目引用。请按照以下步骤操作,以获取与原始文件相同的结果,并将所有功能放在一个文件中。但是,我找不到在机器人中仅导入所需功能的解决方案。也就是说,不使用进出口。

在根目录的tsconfig.json中

{
    "files": [],
    "references": [
        { "path": "./lib" }
        { "path": "./AggroMiner" }
        { "path": "./ArtilleryMicro" }
        { "path": "./MissileKite" }
        { "path": "./SmartMelee" }
        { "path": "./ZapKite" }
    ]
}

接下来,在您的lib文件夹中,添加tsconfig.json,如下所示

{
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "composite": true,
    "rootDir": ".",
    "outFile": "../build/lib.js",
    "target": "es3",
    "removeComments": true,
    "sourceMap": false,
  },
  "files": [
    "data.ts",
    "movement.ts",
    "utils.ts"
  ]
}

我们需要对data.ts,movement.ts和utils.ts进行一些调整,以使ts不会因编译错误而困扰我们。

数据

/// <reference path="./bot.land.d.ts"/>

(...)

运动


/// <reference path="./data.ts"/>
/// <reference path="./utils.ts"/>
(...)

实用程序

/// <reference path="./bot.land.d.ts"/>
(...)

接下来,我们在根目录添加base.json(自动程序的tsconfig.json将对其进行扩展)。

base.json

{
  "compilerOptions": {
    "declaration": true,
    "composite": true,
    "rootDir": ".",
    "target": "es3",
    "removeComments": true,
    "sourceMap": false,
  }
}

和机器人的tsconfig.json(根据机器人进行调整)

{
  "extends": "../base",
  "compilerOptions": {
    "outFile": "../build/AggroMiner.js",
  },
  "files": [
    "AggroMiner.ts"
  ],
  "references": [
      { "path": "../lib", "prepend": true } //note the prepend: true
  ]
}

而已。现在运行

tsc -b

所以我想到了这样的东西,但是它不起作用的原因是因为在分支上输出的文件的顶部有很多这样的东西,游戏需要一个包含所有功能的文件。因此,我不得不手动将所有编译后的输出拼凑在一起,以创建要上传的文件,而不仅仅是复制粘贴该文件。`“使用严格”;Exports .__ esModule = true; var data_1 = require(“ ../ lib / data”); var Movement_1 = require(“ ../ lib / movement”); var utils_1 = require(“ ../ lib / utils”); `
安德鲁·毛

但是它可以工作,因为lib也可以在build文件夹中输出(build)(由于引用)。
jperl

我正在编辑评论-见上文。或查看build/MissileKite.js构建原始存储库时输出的。
安德鲁·毛

@AndrewMao对不起,直到现在我才明白您的意思“,因为这需要对代码进行模块化,而Bot Land则需要在顶层定义所有功能的单个文件。” 我考虑过使用“ prepend:true”,但是这要求使用outFile和ts不允许我们编译lib中的文件,因为某些文件依赖于其他文件。
jperl

@AndrewMao我已经添加了Webpack支持。我编辑了帖子,并将更改推送到了仓库中。让我知道是否更好。
jperl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.