OK, ogarnąłem. Nie trzeba ani webpacka, ani gulpa, ani niczego takiego. Oto lista rzeczy, które trzeba zrobić, żeby mieć typescript na .NetCore Razor. Ten typscript jest debugowalny, ale pod Chromem. To już jest ograniczenie z MS. No to lecimy:
- Upewnij się, że masz zainstalowane node.js w Visual Studio. Po prostu uruchom Visual Studio Installer, kliknij guzik "Modify" przy Twojej wersji Visuala, znajdź moduł Node.js i upewnij się, że jest zainstalowany.
- Wykonaj kroki wymagane do dodania TypeScript do Twojego projektu. Wszystko jest opisane tutaj: https://docs.microsoft.com/pl-pl/visualstudio/javascript/tutorial-aspnet-with-typescript?view=vs-2019
- Upewnij się, że plik package.json ma takie wpisy w devDependencies:
"@types/jquery": "3.5.0",
"@types/bootstrap": "4.5.0",
"@types/jquery-validation-unobtrusive": "3.2.32"
i inne, których używasz. To powyżej po prostu dodaje do TypeScript typy dla JQuery, Bootstrap i JQueryValidation. JQuery, Bootstrap i JQueryValidation są domyślnie używane przez .NetCore Razor Pages/MVC, więc podejrzewam, że też tego używacie.
- Upewnij się, że Twój tsconfig.json wygląda tak:
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "ES6",
"outDir": "wwwroot/js",
"esModuleInterop": true,
"module": "AMD",
"moduleResolution": "Node"
},
"compileOnSave": true,
"include": [
"scripts/**/*"
],
"exclude": [
"node_modules"
]
}
Najważniejsze rzeczy tutaj to:
- target ustawiony na ES6 (możesz próbować też z ES5)
- esModuleInterop ustawiony na true
- module ustawione na AMD (to oznacza, że moduły będą ładowane asynchronicznie - to chyba domyślne ustawienie dla przeglądarek)
- moduleResolution ustawione na Node
- W swoim pliku .ts używaj exportów i importów. Na przykład, plik person.ts:
export class Person
{
//kod
}
export function foo()
{
//kod
}
W drugim pliku, np:
import { Person } from "./person";
export class ClassThatUsesPerson
{
_person: Person;
//kod
}
Upewnij się, że importujesz pliki BEZ rozszerzenia. Czyli "./person" zamiast "./person.ts". Też "./" powinno znaleźć się na początku.
- Możesz importować inne biblioteki, których używasz i zainstalowałeś za pomocą npm - w podobny sposób. Np. ja zainstalowałem i używam autonumeric, więc importuję to tak:
import AutoNumeric from 'autonumeric'
- Pobierz bibliotekę requireJS (google) - to jest kluczowe
- Teraz kilka zmian w pliku _Layout.cshtml
- pozbądź się jQuery i bootstrap z nagłówków. Zakładając, że skopiowałeś requireJS do "~/libs/requirejs.js", powinieneś dodać takie skrypty:
<script src="~/lib/requirejs.js"></script>
<script src="~/js/entrypoint.js"></script>
Zakładam, że trzymasz swoje pliki js w katalogu "~/js". A więc teraz powinieneś stworzyć tam plik entrypoint.js, który powinien wyglądać mniej więcej tak:
requirejs.config({
baseUrl: "/js",
shim: {
bootstrap: {
"deps": ["jquery"]
}
},
paths: {
jquery: "https://ajax.googleapis.com/ajax/libs/jquery/3.5.0/jquery.min",
bootstrap: "https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min",
"jquery-validation": "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.validate.min",
"jquery.validate.unobtrusive": "https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min"
}
});
require(["jquery", "bootstrap", "app"], function (jq, bs, app) {
app.App.init();
});
Teraz kilka słów wyjaśnienia.
Na początku konfigurujesz bibliotekę requireJS (poczytaj o konfiguracji na stronie tej biblioteki). W dużym skrócie: baseUrl to domyślne miejsce, w którym requireJS będzie szukał Twoich plików js.
Shim
jest potrzebny do bootstrapa. Paths
- tutaj definiujesz ścieżki do modułów. Po prostu dodaj URLe do modułów, które ładujesz z netu. Tutaj jQuery, bootstrap i jqueryValidations są potrzebne, żeby móc używać jQuery, bootstrap i walidacji :)
Ważne - upewnij się, że includujesz bootstrap.bundle.min, a nie bootstrap.min. Wersja bundle ma kilka innych bibliotek już w sobie (np. popper.js), co baaardzo ułatwia inne rzeczy. No i zmniejsza ilość requestów jakie wychodzą.
UWAGA! Nazwy modułów "jquery-validation"
i "jquery.validate.unobtrusive"
są istotne. Inaczej walidacja nie będzie działać. Te moduły (głównie jquery-validation) muszą nazywać się dokładnie tak.
Po konfiguracji widzisz taki kod:
require(["jquery", "bootstrap", "app"], function (jq, bs, app) {
app.App.init();
});
To mówi po prostu: "Teraz załaduj moduły: jquery, bootstrap i app". Zauważ, że moduł app
to jest mój moduł. init()
to statyczna funkcja z klasy App. Robię tutaj rzeczy, które normalnie byłyby robione na document.ready lub body.onload.
W ostatnim kroku, upewnij się, że NIE MASZ nigdzie skryptów ładowanych w ten sposób: <script src="...">
(pamiętaj też o plikach utworzonych przez Visual Studio :)) Teraz skrypty ładujesz jedynie przez requirejs, używając funkcji require.
Więc na przykład zamiast:
<script src="~/js/person.js"></script>
powinieneś mieć:
require(["person"]);
Też nie musisz martwić się o zależności. Tzn. jeśli np. plik person.js ma zależności do innych plików (a w .ts zrobiłeś odpowiednie importy), to requirejs o wszystko zadba. A więc, jesli normalnie musiałeś zaincludować kilka skryptów:
<script src="~/js/lib1.js"><script>
<script src="~/js/person.js"></script>
(gdzie person.js zależał w jakiś sposób od lib1.js), to teraz includujesz tylko person:
require(["person"]);
A jeśli w pliku person masz jakąś klasę, możesz teraz utworzyć jej obiekt:
<script>
var personObj;
require(["person"], function(personFile) {
personObj = new personFile.Person();
});
</script>
To tyle. Proste, nie? Hurray me! :)