Configura un proyecto de TypeScript con dependencias comunes para generar múltiples archivos de salida de JavaScript plano
Actualmente estoy escribiendo algunos scripts para Bot Land. Bot Land es un juego de estrategia en tiempo real donde en lugar de controlar tus unidades con un ratón y teclado, escribes código para controlar tus bots a través de una API, y luego tus bots van a luchar contra los bots de otros. Si estás familiarizado con las unidades de SC2, puedes crear bots similares a stalkers con blink, tanques de asedio, médicos y ultraliscos. (Es un juego bastante divertido para ingenieros de software, pero eso está fuera del alcance de esta pregunta.)
El control de bots tiene tres niveles de complejidad creciente: una IA predeterminada, un lenguaje de programación similar a Scratch y un conjunto reducido de JavaScript llamado BotLandScript. Aunque el editor integrado para BotLandScript es razonable, tienes que subir todo tu código como un solo archivo con funciones globales de nivel superior en todos lados. Naturalmente, esto comienza a volverse molesto después de un tiempo si tu código empieza a ser largo y diferentes bots comparten las mismas funciones.
Para facilitar la escritura de código para múltiples bots, reducir la posibilidad de errores involuntarios al programar en JS puro y aumentar mis posibilidades de vencer a otros jugadores, configuré el proyecto de TypeScript anterior para proporcionar una biblioteca común así como código para cada uno de mis bots. La estructura actual del directorio se ve aproximadamente así:
lib/
bot.land.d.ts
common.ts
BlinkStalker/
BlinkStalker.ts
tsconfig.json
Artillery/
Artillery.ts
tsconfig.json
SmartMelee/
SmartMelee.ts
tsconfig.json
lib es el código común que se comparte entre los bots y proporciona definiciones de TypeScript para la API de Bot Land (no TS). Cada bot luego obtiene su propia carpeta, con un archivo que contiene el código del bot y otro un tsconfig.json de plantilla:
{
"compilerOptions": {
"target": "es3",
"module": "none",
"sourceMap": false,
"outFile": "bot.js"
},
"files": [
"MissileKite.ts"
],
"include": [
"../lib/**/*"
]
}
Cuando se construye cada tsconfig.json, se crea un correspondiente bot.js que contiene el código transpiledo del propio bot así como todo el código en common.js. Esta configuración es subóptima por varias razones, entre otras: requiere mucho código repetitivo, dificulta agregar nuevos bots, incluye mucho código innecesario para cada bot y requiere que cada bot se construya por separado.
Sin embargo, según mi investigación hasta ahora, no parece que haya una manera fácil de hacer lo que quiero. En particular, usar la nueva opción tsc -b y referencias no funciona, porque eso requiere que el código esté modularizado y Bot Land requiere un solo archivo con todas las funciones definidas en el nivel superior.
¿Cuál es la mejor manera de lograr tantos de los siguientes como sea posible?
- No se requiere nueva plantilla para añadir un nuevo bot (por ejemplo, no se necesita
tsconfig.jsonpor bot) - Usa
importpara funciones comunes para evitar generar código no utilizado, pero luego... - Todavía genera todas las funciones como un solo archivo en el formato específico de Bot Land
- Un único paso de compilación que produce múltiples archivos de salida, uno por cada bot
- Bono: integración del proceso de compilación con VS Code. Actualmente hay un
tasks.jsonestándar correspondiente para compilar cada subproyecto.
Sospecho vagamente que la respuesta probablemente involucra algo como Grunt además de tsc, pero no sé lo suficiente sobre eso para estar seguro.
Respuesta #1
Aquí está mi intento de responder a sus requisitos.
Archivos notables:
src/tsconfig-botland.jsoncontiene configuraciones para cualquier script de bot.land (incluyendo tus declaraciones personalizadas que moví atypes/bot-land/index.d.ts). Puedes querer cambiar las configuraciones destrictque usé.src/tsconfig.jsoncontiene referencias a todos tus bots. Este es el archivo que debes editar cada vez que quieras agregar otro script de bot
Un script de bot consta al menos de dos archivos: un tsconfig.json minimalista y uno o más archivos de script .ts.
Por ejemplo src/AggroMiner/tsconfig.json:
{
"extends": "../tsconfig-botland",
"compilerOptions": {
"outFile": "../../build/AggroMiner.js"
},
"files": ["index.ts"],
"include": ["**/*.ts", "../lib/**/*.ts"]
}
En la mayoría de los casos, para iniciar un nuevo script de bot deberías:
- copia cualquier carpeta de bot (es decir,
src/AggroMiner) a una nueva carpeta dentro desrc - edita el
src/<newBotFolder>/tsconfig.jsonpara editar eloutFilecon el nombre de tu bot - edita
src/tsconfig.jsony añade una referencia asrc/<newBotFolder>
Se han establecido los siguientes scripts de npm/yarn:
buildpara construir todos los botsbuild-cleanque limpia la carpetabuildantes de ejecutar unbuildformatpara ejecutar Prettier en todos los archivos.tsbajosrclintpara ejecutar una verificación de tslint en todos los scripts del bot
Ahora revisando tus requisitos:
- No se requiere nuevo código estándar para agregar un nuevo bot (por ejemplo, no se necesita tsconfig.json por bot)
Lograr esto requeriría crear algún script que enumerara tu carpeta de bots/scripts... y configurara el tsconfig.json relevante por bot y ejecutara tsc. A menos que sea estrictamente necesario, una configuración mínima (descrita arriba) podría ser suficiente.
- Usa import para funciones comunes para evitar generar código no utilizado, pero luego...
Primero, tenga en cuenta que si comienza a usar cualquier módulo export/import, necesitará terceros adicionales para empaquetar/eliminar código no utilizado con el fin de lograr una salida en un solo archivo. Por lo que pude entender de Bot.land, sus scripts se ejecutan en el servidor. A menos que el código muerto tenga un impacto en el rendimiento de su bot, realmente no me preocuparía.
- Todavía genera todas las funciones como un solo archivo en el formato específico de Bot Land
Hecho.
- Un único paso de compilación que produce múltiples archivos de salida, uno por cada bot
Hecho.
- Bono: integrar el proceso de compilación con VS Code. Actualmente hay un archivo tasks.json de plantilla correspondiente para compilar cada subproyecto.
Los scripts de npm deberían aparecer en la lista de tareas de VSC (al menos aparecen en la mía), haciendo así innecesario el tasks.json.
Respuesta #2
De hecho, podrías usar referencias de proyecto. Sigue estos pasos para obtener los mismos resultados que obtenías con tus archivos originales, con todas las funciones en el nivel superior en un solo archivo. Sin embargo, no pude encontrar una solución para importar solo las funciones necesarias en los bots. Es decir, sin usar importaciones y exportaciones.
En tu tsconfig.json en la raíz
{
"files": [],
"references": [
{ "path": "./lib" }
{ "path": "./AggroMiner" }
{ "path": "./ArtilleryMicro" }
{ "path": "./MissileKite" }
{ "path": "./SmartMelee" }
{ "path": "./ZapKite" }
]
}
A continuación, en tu carpeta lib, añade un tsconfig.json de la siguiente manera
{
"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"
]
}
Necesitamos hacer algunos ajustes en data.ts, movement.ts y utils.ts para que ts no nos moleste con errores de compilación.
datos.ts
/// <reference path="./bot.land.d.ts"/>
(...)
movimiento.ts
/// <reference path="./data.ts"/>
/// <reference path="./utils.ts"/>
(...)
utils.ts
/// <reference path="./bot.land.d.ts"/>
(...)
A continuación, agregamos base.json en la raíz (el tsconfig.json de los bots lo extenderá).
base.json
{
"compilerOptions": {
"declaration": true,
"composite": true,
"rootDir": ".",
"target": "es3",
"removeComments": true,
"sourceMap": false,
}
}
y el tsconfig.json de los bots (adaptar según los bots)
{
"extends": "../base",
"compilerOptions": {
"outFile": "../build/AggroMiner.js",
},
"files": [
"AggroMiner.ts"
],
"references": [
{ "path": "../lib", "prepend": true } //note the prepend: true
]
}
Eso es todo. Ahora solo corre
tsc -b

