Diversity w polskim IT
Kedren Villena
Kedren VillenaSoftware Engineer @ ClinkIT Solutions

Używanie pakietów npm w aplikacji Blazor

Sprawdź, jak używać pakietów npm w aplikacji Blazor, aby móc wykorzystać pełnię ich możliwości.
29.10.20195 min
Używanie pakietów npm w aplikacji Blazor

Blazor jest świetnym frameworkiem do UI, dzięki któremu możemy używać C# na frontendzie. Są jednak przypadki, w których nadal trzeba korzystać z nowoczesnych bibliotek JavaScript. Zwłaszcza tych dostępnych na npm

Jak więc korzystać z modułów JS dostarczanych przez npm?

Wymagania wstępne:

  • zainstalowanie .NET Core 3.0
  • zainstalowanie Node.JS


Zbudujmy aplikację Blazor od zera:

$ dotnet new blazorserverside --auth Individual


To polecenie utworzy nową aplikację Blazor.

Spróbujmy uruchomić:

$ dotnet run


Działa zgodnie z oczekiwaniami.

W przypadku modułu npm, którego będziemy używać, wykorzystamy moment.js, który jest prostym modułem do obsługi czasu w JS.

Utwórzmy folder o nazwie JsLib w naszej aplikacji Blazor:

Teraz zainicjujemy nowy projekt npm w folderze JsLib:

$ cd JsLib
$ npm init


Po prostu zostaw pustą odpowiedź. Nie będziemy się teraz na tym skupiać.

Utwórz nowy katalog src w folderze JsLib i nowy plik index.js:

Plik index.js będzie służył jako „root” z którego będziemy wystawiać biblioteki, których używamy.

Teraz dodamy moment.js za pośrednictwem npm. Wykonamy to w katalogu JsLib:

$ npm install moment


Plik package.json powinien teraz zawierać następujące elementy:

Następnie utworzymy nowy plik o nazwie time_lib.js w folderze src:

Dodaj następujący kod:

import moment from 'moment';

export function getCurrentTime() {
    return moment().format();
}


Wywołamy to teraz w index.js i wystawimy funkcję, którą może wywołać aplikacja Blazor:

import { getCurrentTime } from './time_lib';

export function GetCurrentTime() {
    return getCurrentTime();
}


W powyższym przykładzie JsInterop dla Blazor wywoła funkcję GetCurrentTime().

Teraz użyjemy pakietu webpack, aby spakować naszą bibliotekę i umieścić wynik wewnątrz wwwroot/js w naszej aplikacji Blazor.

Teraz w folderze JsLib wywołamy:

$ npm install webpack webpack-cli


To doda zależności, których użyjemy o stworzenia paczki z naszą biblioteką do webpack i webpack-cli. Folder zależności powinien teraz zawierać webpack i webpack-cli:

Teraz utworzymy webpack.config.js w folderze JsLib, który będzie obsługiwał konfigurację webpack:

Dodaj to do webpack.config.js:

const path = require("path");

module.exports = {
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            }
        ]
    },
    output: {
        path: path.resolve(__dirname, '../wwwroot/js'),
        filename: "my_lib.js",
        library: "MyLib"
    }
};


Powyższa konfiguracja każe webpackowi wykonać następujące czynności:

  • Użyć babel-loader, ponieważ używamy składni ES6.
  • Nazwać dołączoną bibliotekę my_lib.js i ustawić bibliotekę główną, która zostanie dołączona do window (po stronie klienta) i nazwie ją MyLib.  Więcej na ten temat później.
  • Umieścić dołączoną bibliotekę na wwwroot/js.


Teraz zaktualizujemy package.json, aby dodać build, który wywoła webpack.

Dodaj to do sekcji „scripts” w pliku package.json:

"build": "webpack --mode production"


Plik package.json będzie teraz wyglądał następująco:

Ponieważ użyliśmy składni ES6, musimy dodać zależności babel. Uruchomimy polecenie w folderze JsLib:

$ npm install babel-loader @babel/core --save-dev


Spowoduje to dodanie potrzebnych zależności babel dla webpacka, by stworzyć poprawną paczkę z naszą biblioteką. Teraz pakiet.json będzie wyglądać tak:

Zbudujmy teraz naszą bibliotekę za pomocą polecenia:

$ npm run build


To polecenie zbuduje bibliotekę i nasz pakiet do folderu wwwroot/js:

Jak widać, nasz plik my_lib.js znajduje się teraz w folderze wwwroot/js w naszej aplikacji Blazor.

Skorzystajmy teraz z naszej biblioteki w aplikacji Blazor.

Zaczniemy od dodania naszej biblioteki do plików JS używanych przez naszą aplikację Blazor. W _Host.cshtml dodaj następujący wiersz:

<script src="js/my_lib.js"></script>


Sekcja body _Host.cshtml powinna wyglądać mniej więcej tak:


Najpierw uruchommy naszą aplikację Blazor i przekonajmy się, że nasza biblioteka faktycznie tam jest. Po uruchomieniu otwórz przeglądarkę (moja to Chrome) i sprawdź, czy nasza biblioteka została wczytana:

Powodem, dla którego window faktycznie zawiera MyLib, jest właściwość library dodana w output w webpack.config.js.

Ponieważ jest to teraz część elementu window, możemy teraz wywołać to w naszej aplikacji Blazor :)

Utwórz nową stronę w katalogu Pages i nazwij ją Time.razor:

Time.razor będzie zawierał następujący kod:

@page "/time"
@inject IJSRuntime JsRunTime

<button class="btn btn-primary" @onclick="@GetCurrentTime">Get Current Time</button>

@CurrentTime

@code {
    private MarkupString CurrentTime = new MarkupString("");

    async void GetCurrentTime()
    {
        var dateTime = await JsRunTime.InvokeAsync<string>("MyLib.GetCurrentTime");

        CurrentTime = new MarkupString(dateTime);

        StateHasChanged();
    }
}


Powyższy kod używa JsInterop Blazora i wywołuje MyLib.GetCurrentTime z naszej biblioteki.

Uruchom aplikację Blazor i przejdź do /time:

Naciśnij przycisk, a otrzymasz wynik z biblioteki, którą utworzyliśmy.

Jak widzisz, możemy teraz używać modułów npm i wystawić je jako biblioteki naszej aplikacji Blazor :)


Bonus

Integracja naszego npm run build z dotnet build.

Zmodyfikuj plik .csproj na podobny do poniższego:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>7.3</LangVersion>
    <UserSecretsId>aspnet-BlazorNpmLib-3AB59FEC-F75E-4E24-9EC0-874FBF1316F3</UserSecretsId>
    <JsLibRoot>JsLib\</JsLibRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(JsLibRoot)node_modules\**</DefaultItemExcludes>
  </PropertyGroup>

  <ItemGroup>
    <Content Remove="$(JsLibRoot)**" />
    <None Remove="$(JsLibRoot)**" />
    <None Include="$(JsLibRoot)**" Exclude="$(JsLibRoot)node_modules\**" />
  </ItemGroup>

  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(JsLibRoot)node_modules') ">
    <!-- Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
    <Exec WorkingDirectory="$(JsLibRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(JsLibRoot)" Command="npm run build" />
  </Target>

  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(JsLibRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(JsLibRoot)" Command="npm run build" />
  </Target>

  <ItemGroup>
    <None Update="app.db" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="3.0.0-preview6.19307.2" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0-preview6.19307.2" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="3.0.0-preview6.19307.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0-preview6.19304.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0-preview6.19304.10" />
  </ItemGroup>

</Project>


Pomysł ten został skopiowany z szablonu react-redux. Krótkie podsumowanie jest takie, że wywołania npm są zintegrowane z poleceniem kompilacji dotnet.

Po opublikowaniu, biblioteka jest kopiowana do folderu wwwroot/js, więc nie trzeba nic konfigurować przy releasach.

Oto przykładowy folder dist po uruchomieniu dotnet publish -o dist:

Jak widać, plik my_lib.js jest najpierw kopiowany do katalogu źródłowego, aby po skompilowaniu go przez dotnet, już tam istniał.

Zauważ, że wciąż można tu dużo naprawić. Ale teraz przynajmniej widzimy, że moduły npm mogą być używane jako biblioteki dla aplikacji Blazora :)


Oryginał tekstu w języku angielskim przeczytasz tutaj.

<p>Loading...</p>