javascript - JSInterop kompilert med webpack er udefinert i blazor
Jeg har en Blazor WebAssembly-applikasjon, der jeg prøver å inkludere TypeScript/JavaScript-kode ved bruk av JSInterop, som feiler når JS-koden blir laget av webpack under bygging.
Når jeg oppretter en enkel hello-world.js-fil i min wwwroot med følgende innhold:
export function showAlertSimple() {
alert("hello world");
}
Jeg kan påkalle det veldig enkelt ved å bruke:
public class HelloWorld : JSModule
{
public HelloWorld(IJSRuntime js)
: base(js, "./js/hello-world.js")
{
}
public async Task ShowAlert() => await InvokeVoidAsync("showAlert");
}
Hvis jeg prøver å gjøre det samme med en typescript-fil, som jeg opprettet et annet sted og deretter lar den kompilere ned til ES6 med webpack, og setter den i samme mappe, klarer ikke Blazor å kalle metoden:
./NpmJs/src/hello-world2.ts
export function showAlertFromWebPack() {
alert("Hello World from webpack");
}
./NpmJs/webpack.config.js
module.exports = {
entry: {
helloworld2: './src/hello-world2.ts',
},
module: {
rules: [
{
test: /\.ts?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../../wwwroot/js'),
},
devtool: 'source-map'
};
public class HelloWorld2 : JSModule
{
public HelloWorld2(IJSRuntime js)
: base(js, "./js/helloworld2.bundle.js")
{
}
public async Task ShowAlert() => await InvokeVoidAsync("showAlertFromWebPack");
}
Dette kaster da følgende unntak i nettleserkonsollen:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not find 'showAlertFromWebPack' ('showAlertFromWebPack' was undefined).
Error: Could not find 'showAlertFromWebPack' ('showAlertFromWebPack' was undefined).
Filene i seg selv lastes korrekt. Jeg kan se den i kildefanen.
Hva går jeg glipp av her?
For fullstendighets skyld, her er JSModule-klassen, som jeg skamløst har tatt fra Steven Sanderson på github.(https://github.com/SteveSandersonMS/AudioBrowser/blob/dd7a03d93b4de5e97efb333f1120792ee48c70ba/MediaFilesAPI/Util/JSModule.cs#L7)
public abstract class JSModule : IAsyncDisposable
{
private readonly Task<IJSObjectReference> moduleTask;
// On construction, we start loading the JS module
protected JSModule(IJSRuntime js, string moduleUrl)
=> moduleTask = js.InvokeAsync<IJSObjectReference>("import", moduleUrl).AsTask();
// Methods for invoking exports from the module
protected async ValueTask InvokeVoidAsync(string identifier, params object[]? args)
=> await (await moduleTask).InvokeVoidAsync(identifier, args);
protected async ValueTask<T> InvokeAsync<T>(string identifier, params object[]? args)
=> await (await moduleTask).InvokeAsync<T>(identifier, args);
// On disposal, we release the JS module
public async ValueTask DisposeAsync()
=> await (await moduleTask).DisposeAsync();
}
Svar #1
Jeg fant 2 fungerende løsninger. Den ene bruker webpack, den andre ved å kvitte seg med webpack og erstatte det med vitejs.
Ved å bruke webpack må vi aktivere experiments.outputModule (https://webpack.js.org/configuration/experiments/#experimentsoutputmodule) og sette output.library.type til module (https://webpack.js.org/configuration/output/#outputlibrarytype):
Den endelige konfigurasjonen vil da se slik ut:
module.exports = {
entry: {
helloworld2: './src/hello-world2.ts',
},
module: {
rules: [
{
test: /\.ts?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../../wwwroot/js'),
library: {
type: "module",
},
},
experiments: {
outputModule: true
},
devtool: 'source-map'
};
Ved bruk av vitejs i vite.config.js, vil konfigurasjonen se slik ut:
import * as path from 'path';
import { defineConfig } from "vite";
export default defineConfig({
appType: 'mpa',
build: {
target: 'esnext',
outDir: '../wwwroot/js',
lib: {
entry: path.resolve(__dirname, './src/index.ts'),
name: "YourPackageName",
fileName: (format) => `your-package-name.${format}.js`,
},
}
});
Vite vil da selv produsere 2 filer:
your-package-name.es.jsyour-package-name.umd.js
Du må koble til/bruke es-filen inne i Blazor, så er du klar til å gå.
