Skonfiguruj projekt TypeScript z typowymi zależnościami, aby zbudować wiele zwykłych plików wyjściowych JavaScript

10

Obecnie piszę kilka skryptów dla Bot Land . Bot Land to gra strategiczna w czasie rzeczywistym, w której zamiast kontrolować jednostki za pomocą myszy i klawiatury, piszesz kod kontrolujący boty za pośrednictwem interfejsu API, a następnie boty walczą z botami innych. Jeśli znasz jednostki w SC2, możesz tworzyć boty podobne do mrugających prześladowców, czołgów oblężniczych, medyków i ultralisk. (To dość zabawna gra dla inżynierów oprogramowania, ale to nie wchodzi w zakres tego pytania).

bot land

Kontrola botów ma trzy poziomy rosnącej złożoności: domyślną sztuczną inteligencję, język programowania podobny do Scratch oraz ograniczony zestaw JavaScript o nazwie BotLandScript. Chociaż wbudowany edytor BotLandScript jest rozsądny, musisz przesłać cały kod jako jeden plik z globalnymi funkcjami najwyższego poziomu wszędzie. Oczywiście zaczyna to boleć po pewnym czasie, jeśli twój kod zaczyna się wydłużać, a różne boty mają te same funkcje.

środowisko programistyczne

Aby ułatwić pisanie kodu dla wielu botów, zmniejszyć ryzyko niezamierzonych błędów podczas kodowania w czystym JS i zwiększyć moje szanse na pokonanie innych graczy, skonfigurowałem powyższy projekt TypeScript, aby zapewnić wspólną bibliotekę oraz kod dla każdego z moich botów . Obecna struktura katalogów wygląda mniej więcej tak:

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

libjest wspólnym kodem dzielonym przez boty i zawiera definicje TypeScript dla (nie-TS) Bot Land API. Każdy bot otrzymuje następnie swój własny folder, z jednym plikiem zawierającym kod bota, a drugim - płytką zbiorczą tsconfig.json:

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

Po tsconfig.jsonzbudowaniu każdego z nich tworzony jest odpowiedni bot.jskod, który zawiera transpilowany kod z samego bota, a także cały kod common.js. Ta konfiguracja jest nieoptymalna z kilku powodów, między innymi: wymaga dużej ilości zduplikowanych płyt kotłowych, utrudnia dodawanie nowych botów, zawiera wiele niepotrzebnego kodu dla każdego bota i wymaga, aby każdy bot był budowany osobno.

Jednak na podstawie moich dotychczasowych badań nie wydaje się, że istnieje prosty sposób na robienie tego, co chcę. W szczególności użycie nowej tsc -bopcji i odniesień nie działa, ponieważ wymaga to modularyzacji kodu, a Bot Land wymaga jednego pliku ze wszystkimi funkcjami zdefiniowanymi na najwyższym poziomie.

Jaki jest najlepszy sposób na uzyskanie jak największej liczby poniższych możliwości?

  • Nie jest wymagana nowa płyta kotła, aby dodać nowego bota (np. Nie tsconfig.jsonna bota)
  • Użyj importdla typowych funkcji, aby uniknąć generowania nieużywanego kodu, ale potem ...
  • Nadal wyprowadzasz wszystkie funkcje jako jeden plik w specyficznym formacie Bot Land
  • Jeden krok kompilacji, w którym powstaje wiele plików wyjściowych, po jednym dla każdego bota
  • Bonus: zintegrowanie procesu kompilacji z VS Code. Obecnie istnieje odpowiednio plansza tasks.jsondo budowy każdego podprojektu.

Domyślam się, że odpowiedź prawdopodobnie wiąże się z czymś takim jak Grunt tsc, ale nie wiem wystarczająco dużo na ten temat.

Andrew Mao
źródło
Czy konieczne jest, aby wszystkie boty miały osobne foldery? A może wystarczy, że każdy bot znajduje się na poziomie głównym w jednym pliku? (np. <root>/MissileKite.ts)
1300
1
Czy wszystkie transpilowane pliki botów muszą mieć nazwy bot.js?
a1300,
Preferowane byłoby rootowanie w jednym pliku; znajdują się w osobnych folderach ze względu na osobne tsconfig.json. Przeszczepione pliki botów mogą mieć dowolną nazwę, najlepiej wersję oryginalnego pliku .js. Mam to ustawione w ten sposób teraz w repozytorium wyjściowym do build/MissileKite.js.
Andrew Mao,
1
@ andrew-mao Możesz rzucić okiem na mój szablon dla projektów GAS, który spełnia większość twoich wymagań (ale ukierunkowanie na inne środowisko) Jeśli ci to odpowiada, być może będę w stanie dostosować go dla ciebie w przyszłym tygodniu. github.com/PopGoesTheWza/ts-gas-project-starter
PopGoesTheWza
Czy tsconfig-gas.jsonwarto tam spojrzeć?
Andrew Mao,

Odpowiedzi:

2

Oto moja próba odpowiedzi na twoje wymagania.

Ważne pliki:

  • src/tsconfig-botland.jsonprzechowuje ustawienia dla dowolnego skryptu bot.land (w tym niestandardowych deklaracji, do których przeprowadziłem się types/bot-land/index.d.ts). Możesz zmienić strictustawienia, których użyłem.
  • src/tsconfig.jsonzawiera odniesienia do wszystkich twoich botów. Jest to plik do edycji za każdym razem, gdy chcesz dodać kolejny skrypt bota

Skrypt bota to co najmniej dwa pliki: minimalistyczny tsconfig.jsoni jeden lub więcej .tsplików skryptowych.

Na przykład src/AggroMiner/tsconfig.json:

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

W większości przypadków, aby uruchomić nowy skrypt bota, powinieneś:

  1. skopiuj dowolny folder bota (tj src/AggroMiner ) do nowego folderu podsrc
  2. edytuj src/<newBotFolder>/tsconfig.json aby edytować outFilez nazwą twojego bota
  3. edytować src/tsconfig.json i dodaj odniesienie dosrc/<newBotFolder>

Ustawiono następujące npm/ yarnskrypt:

  • build zbudować wszystkie boty
  • build-cleanktóre usuwają buildfolder przed uruchomieniembuild
  • formaturuchomić Prettier na wszystkich .tsplikach poniżejsrc
  • lint aby uruchomić sprawdzanie tslint na wszystkich skryptach bota

Teraz wyczerpują się twoje wymagania:

  • Nie jest wymagana nowa płyta kotła, aby dodać nowego bota (np. Brak tsconfig.json na bota)

Aby to osiągnąć, należy utworzyć skrypt, który wyliczy folder / skrypty bota ... i skonfiguruje odpowiedni dla każdego bota tsconfig.jsoni uruchomtsc . O ile nie jest to absolutnie konieczne, minimalna konfiguracja (opis powyżej) może być wystarczająca.

  • Użyj importu do typowych funkcji, aby uniknąć generowania nieużywanego kodu, ale potem ...

Po pierwsze, pamiętaj, że jeśli zaczniesz używać dowolnego modułu export/ importinstrukcji, będziesz potrzebować dodatkowej strony trzeciej do spakowania / uzgadniania drzewa w celu uzyskania pojedynczego pliku wyjściowego. Z tego, co mogłem zebrać w Bot.land, twoje skrypty działają na serwerze. O ile deadcode nie wpływa na wydajność twojego bota, tak naprawdę nie zawracałbym sobie głowy.

  • Nadal wyprowadzasz wszystkie funkcje jako jeden plik w specyficznym formacie Bot Land

Gotowy.

  • Jeden krok kompilacji, w którym powstaje wiele plików wyjściowych, po jednym dla każdego bota

Gotowy.

  • Bonus: zintegrowanie procesu kompilacji z VS Code. Istnieją obecnie odpowiednio `` kotłowe zadania ''. Json do budowy każdego podprojektu.

Te npmskrypty powinien pojawić się na liście zadań VSC (przynajmniej robią w kopalni) co powoduje, że tasks.jsonzbędne.

PopGoesTheWza
źródło
Deadcode to dobry kompromis dla wszystkiego, co tutaj stworzyłeś; czy możesz mi jednak powiedzieć, dlaczego użyłeś types/bot-landdefinicji i dlaczego wybrałeś strictustawienia?
Andrew Mao
Typy / bot-land / index.d.ts to naprawdę twój oryginalny plik .d.ts z biblioteki lib, którego nazwa została zmieniona i umieszczony inaczej. Î załóżmy, że w pewien sposób opisuje ogólny kontekst wykonywania bot.land dla wszystkich skryptów, dlatego upewniam się, że jest on zawsze dostępny w każdym skrypcie bota. Ustawienia „ścisłe” są tutaj tylko dlatego, że leniwie skopiowałem moje ulubione ustawienia (to samo dla ładniejszych ustawień). Powinny być one dostosowane do preferencji użytkownika (Ciebie).
PopGoesTheWza
Zastanawiam się tylko, czy istnieje jakiś zwyczajny powód, aby to włożyć, typesczy też był to tylko określony sposób organizacji, który wybrałeś.
Andrew Mao,
Jedynym powodem jest założenie, że był to kontekst bot.land. Pomyśl o tym jak o tym, że @ typy / typy węzłów są już dostępne w twoich skryptach
nodejs
1
Folder A / types jest jednym z konwencjonalnych miejsc, w których umieszcza się deklaracje typów zewnętrznych (tj. Kontekst wykonania specyficzny, taki jak silnik botland lub nietypowe moduły / pakiety JavaScript, które nie są tutaj używane)
PopGoesTheWza
3

Możesz użyć referencji projektu. Wykonaj następujące kroki, aby uzyskać takie same wyniki, jak w przypadku oryginalnych plików, ze wszystkimi funkcjami na najwyższym poziomie w jednym pliku. Jednak nie mogłem znaleźć rozwiązania, aby zaimportować tylko potrzebne funkcje do botów. To znaczy bez korzystania z importu i eksportu.

W tsconfig.json w katalogu głównym

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

Następnie w folderze lib dodaj plik 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"
  ]
}

Musimy wprowadzić kilka zmian w data.ts, move.ts i utils.ts, aby ts nie przeszkadzał nam w błędach kompilacji.

data.ts

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

(...)

move.ts


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

utils.ts

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

Następnie dodajemy base.json w katalogu głównym (tsconfig.json botów go przedłuży).

base.json

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

i tsconfig.json bots (dostosuj zgodnie z botami)

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

Otóż ​​to. Teraz po prostu biegnij

tsc -b
jperl
źródło
Pomyślałem o czymś takim, ale to nie działa, ponieważ plik, który dostaje się do twojego oddziału, ma na górze mnóstwo takich rzeczy, a gra potrzebuje jednego pliku ze wszystkimi funkcjami. Musiałbym więc ręcznie połączyć wszystkie skompilowane dane wyjściowe, aby utworzyć plik, który przesłałem, zamiast po prostu skopiować plik. `` użyj ścisłego ''; eksportuje .__ esModule = true; var data_1 = wymagany („../ lib / data”); var ruch_1 = wymagany („../ lib / ruch”); var utils_1 = wymagany („../ lib / utils”); `
Andrew Mao,
Ale działa, ponieważ lib jest również wyprowadzany (budowany) w folderze kompilacji (dzięki referencjom).
jperl
Byłem w trakcie edytowania mojego komentarza - patrz wyżej. Lub spójrz na to, build/MissileKite.jsco jest generowane podczas budowania oryginalnego repo.
Andrew Mao,
@AndrewMao przepraszam, dopiero teraz rozumiem, co miałeś na myśli mówiąc „ponieważ wymaga to zmodularyzowania kodu, a Bot Land wymaga jednego pliku ze wszystkimi funkcjami zdefiniowanymi na najwyższym poziomie”. Myślałem o użyciu „prepend: true”, ale to wymaga użycia outFile, a ts nie pozwoli nam skompilować plików w lib, ponieważ niektóre są zależne od innych.
jperl
@AndrewMao Dodałem obsługę Webpack. Zredagowałem post i opublikowałem zmiany w repozytorium. Daj mi znać, jeśli będzie lepiej.
jperl