Configurare un progetto TypeScript con dipendenze comuni per creare più file di output JavaScript semplici


10

Attualmente sto scrivendo alcuni script per Bot Land . Bot Land è un gioco di strategia in tempo reale in cui invece di controllare le tue unità con un mouse e una tastiera, scrivi codice per controllare i tuoi robot tramite un'API, quindi i tuoi robot vanno a combattere i robot degli altri. Se hai familiarità con le unità in SC2, puoi creare robot simili a stalker, carri armati d'assedio, medici e ultralischi simili. (È un gioco abbastanza divertente per gli ingegneri del software, ma non rientra nell'ambito di questa domanda.)

terra dei bot

Il controllo bot ha tre livelli di crescente complessità: un'intelligenza artificiale predefinita, un linguaggio di programmazione simile a Scratch e un set ridotto di JavaScript chiamato BotLandScript. Sebbene l'editor integrato per BotLandScript sia ragionevole, devi caricare tutto il tuo codice come un singolo file con funzioni globali di alto livello ovunque. Naturalmente, questo inizia a diventare doloroso dopo un po 'se il codice inizia a diventare lungo e diversi robot condividono le stesse funzioni.

ambiente di programmazione

Per facilitare la scrittura di codice per più robot, ridurre la possibilità di errori involontari durante la codifica in JS nudo e aumentare le mie possibilità di battere altri giocatori, ho impostato il progetto TypeScript sopra riportato per fornire una libreria comune e un codice per ciascuno dei miei robot . La struttura della directory corrente è simile approssimativamente alla seguente:

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

libè il codice comune condiviso tra i bot e fornisce definizioni TypeScript per l'API Bot Land (non TS). Ogni bot ottiene quindi la propria cartella, con un file contenente il codice del bot e l'altro una piastra di caldaia tsconfig.json:

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

Quando ciascuno di essi tsconfig.jsonviene creato, crea un corrispondente bot.jsche contiene codice traspilato dal bot stesso e tutto il codice in common.js. Questa configurazione non è ottimale per alcuni motivi, tra gli altri: richiede un sacco di duplicati del boilerplate, rende difficile l'aggiunta di nuovi robot, include un sacco di codice non necessario per ciascun bot e richiede che ogni bot sia costruito separatamente.

Tuttavia, sulla base delle mie ricerche finora , non sembra che ci sia un modo semplice per fare quello che voglio. In particolare, l'utilizzo della nuova tsc -bopzione e dei riferimenti non funziona, poiché ciò richiede la modularizzazione del codice e Bot Land richiede un singolo file con tutte le funzioni definite al livello superiore.

Qual è il modo migliore per ottenere il maggior numero possibile di seguenti?

  • Non è necessario un nuovo boilerplate per aggiungere un nuovo bot (es. No tsconfig.jsonper bot)
  • Utilizzare importper le funzioni comuni per evitare di generare codice inutilizzato, ma poi ...
  • Stampa comunque tutte le funzioni come un singolo file nel formato specifico di Bot Land
  • Un singolo passo di generazione che produce più file di output, uno per ciascun bot
  • Bonus: integrazione del processo di compilazione con VS Code. Al momento esiste un corrispondente boiler tasks.jsonper la costruzione di ciascun sottoprogetto.

Suppongo vagamente che la risposta implichi probabilmente qualcosa di simile a Grunt tsc, ma non ne so abbastanza per esserne sicuro.


È necessario che tutti i robot abbiano cartelle separate? O è sufficiente che ogni bot si trovi al livello principale in un singolo file? (es. <root>/MissileKite.ts)
a1300 del

1
Tutti i file bot trasferiti devono essere nominati bot.js?
a1300,

La radice in un singolo file sarebbe preferibile; sono in cartelle separate a causa del separato tsconfig.json. I file bot traspilati possono essere nominati con qualsiasi nome, preferibilmente la versione .js del file originale. L'ho impostato in questo modo ora nel repo in uscita a build/MissileKite.js.
Andrew Mao,

1
@ andrew-mao Puoi dare un'occhiata al mio modello per i progetti GAS che risponde alla maggior parte delle tue esigenze (ma si rivolge a un ambiente diverso) Se ti soddisfa, potrei essere in grado di adattarlo per te la prossima settimana. github.com/PopGoesTheWza/ts-gas-project-
starter

La tsconfig-gas.jsoncosa rilevante da guardare lì?
Andrew Mao,

Risposte:


2

Ecco il mio tentativo di rispondere alle tue esigenze.

File notevoli:

  • src/tsconfig-botland.jsoncontiene le impostazioni per qualsiasi script bot.land (comprese le dichiarazioni personalizzate in cui sono passato types/bot-land/index.d.ts). È possibile che per modificare le strictimpostazioni che ho usato.
  • src/tsconfig.jsoncontiene riferimenti a tutti i tuoi robot. Questo è il file da modificare ogni volta che si desidera aggiungere un altro script bot

Uno script bot è composto da almeno due file: uno minimalista tsconfig.jsone uno o più .tsfile di script.

Per esempio src/AggroMiner/tsconfig.json:

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

Nella maggior parte dei casi, per avviare un nuovo script bot dovresti:

  1. copia qualsiasi cartella bot (es. src/AggroMiner) in una nuova cartella insrc
  2. modifica il src/<newBotFolder>/tsconfig.jsonper modificare il outFilecon il nome del tuo bot
  3. modificare src/tsconfig.jsone aggiungere un riferimento asrc/<newBotFolder>

Sono stati impostati i seguenti script npm/ yarn:

  • build per costruire tutti i robot
  • build-cleanche cancella la buildcartella prima di eseguire abuild
  • formatper eseguire Prettier su tutti i .tsfile insrc
  • lint per eseguire un controllo tslint su tutti gli script dei bot

Ora stai esaurendo le tue esigenze:

  • Non è necessario un nuovo bollettino per aggiungere un nuovo bot (ad es. Nessun tsconfig.json per bot)

Per raggiungere questo obiettivo richiederebbe la creazione di alcuni script che enumerassero la cartella / gli script dei bot ... e configurassero il relativo bot tsconfig.jsonper l'esecuzione tsc. A meno che non sia strettamente necessario, una configurazione minima (descritta sopra) potrebbe essere sufficiente.

  • Utilizzare l'importazione per le funzioni comuni per evitare di generare codice inutilizzato, ma poi ...

Innanzitutto, tieni presente che se inizi a utilizzare qualsiasi modulo export/ importistruzione, avrai bisogno di terze parti aggiuntive da impacchettare / albero per ottenere un singolo file di output. Da quello che ho potuto raccogliere su Bot.land, i tuoi script sono in esecuzione sul server. A meno che il deadcode non abbia un impatto sulle prestazioni del tuo bot, non mi preoccuperei davvero.

  • Stampa comunque tutte le funzioni come un singolo file nel formato specifico di Bot Land

Fatto.

  • Un singolo passo di generazione che produce più file di output, uno per ciascun bot

Fatto.

  • Bonus: integrazione del processo di compilazione con VS Code. Esiste attualmente un task.json corrispondente corrispondente per la costruzione di ciascun sottoprogetto.

Gli npmscript dovrebbero apparire nella lista dei compiti di vsc (almeno nella mia) rendendo così tasks.jsoninutili.


Deadcode è un ottimo compromesso per tutto ciò che hai fatto qui; puoi farmi sapere perché hai usato types/bot-landle definizioni e perché hai scelto le strictimpostazioni?
Andrew Mao,

Tipi / bot-land / index.d.ts è davvero il tuo .d.ts originale da lib, rinominato e posizionato in modo diverso. Î presumo che descriva il contesto generale di esecuzione bot.land per tutti gli script e quindi mi assicuro che sia sempre disponibile in ogni script bot. Le impostazioni 'rigide' sono qui solo perché ho copiato pigramente le mie impostazioni preferite (lo stesso per le impostazioni più belle). Questi dovrebbero essere adattati alle preferenze dell'utente (tu).
PopGoesTheWza,

Mi chiedo solo se ci sia una ragione abituale in cui inserirla typeso se fosse solo un modo specifico di organizzare ciò che hai scelto.
Andrew Mao,

L'unica ragione è che supponendo che fosse il contesto bot.land. Pensalo come se le tipizzazioni @ types / node fossero già disponibili negli script
nodejs

1
Una cartella / types è uno dei luoghi convenzionali in cui si inseriscono dichiarazioni di tipi esterni (vale a dire un contesto di esecuzione specifico come il motore di botland o moduli / pacchetti JavaScript non tipizzati, che non vengono utilizzati qui)
PopGoesTheWza,

3

Potresti effettivamente utilizzare i riferimenti al progetto. Segui questi passaggi per ottenere gli stessi risultati che stavi ottenendo per i tuoi file originali, con tutte le funzioni al massimo livello in un unico file. Tuttavia, non sono riuscito a trovare una soluzione per importare solo le funzioni necessarie nei robot. Cioè, senza usare importazioni ed esportazioni.

Nel tuo tsconfig.json alla radice

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

Quindi, nella tua cartella lib, aggiungi un tsconfig.json in questo modo

{
  "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"
  ]
}

Dobbiamo apportare alcune modifiche a data.ts, movement.ts e utils.ts in modo che ts non ci dia fastidio con errori di compilazione.

data.ts

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

(...)

movement.ts


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

utils.ts

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

Successivamente, aggiungiamo base.json alla radice (il tsconfig.json dei robot lo estenderà).

base.json

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

e il tsconfig.json dei robot (adattarsi in base ai robot)

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

Questo è tutto. Adesso corri e basta

tsc -b

Quindi ho pensato a qualcosa del genere, ma la ragione per cui non funziona è perché il file che ottiene l'output sul tuo ramo ha un sacco di cose come questa in alto, e il gioco ha bisogno di un file con tutte le funzioni al suo interno. Quindi dovrei raggruppare manualmente tutti gli output compilati insieme per creare il file che avrei caricato, invece di copiare semplicemente il file incollato. `" usa rigoroso "; esporta .__ esModule = true; var data_1 = request ("../ lib / data"); var movement_1 = request ("../ lib / movement"); var utils_1 = request ("../ lib / utils"); `
Andrew Mao,

Ma funziona dal momento che lib è anche output (incorporato) nella cartella build (grazie ai riferimenti).
jperl,

Stavo modificando il mio commento - vedi sopra. O dai un'occhiata a quello build/MissileKite.jsche viene emesso quando costruisci il repository originale.
Andrew Mao,

@AndrewMao scusa, solo ora capisco cosa intendevi per "perché ciò richiede che il codice sia modularizzato e Bot Land richiede un singolo file con tutte le funzioni definite al livello più alto". Ho pensato di usare "prepend: true" ma ciò richiede l'uso di outFile e ts non ci permetterà di compilare i file in lib poiché alcuni dipendono da altri.
jperl,

@AndrewMao Ho aggiunto il supporto Webpack. Ho modificato il post e inviato le modifiche al repository. Fammi sapere se è meglio.
jperl,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.