使用webpack编译的JSInterop在blazor中未定义

Mar*_*rco 3 javascript typescript webpack blazor blazor-webassembly

我有一个 Blazor WebAssembly 应用程序,在其中我尝试使用 JSInterop 包含 TypeScript/javascript 代码,但当 Webpack 在构建期间创建 js 代码时,该代码会失败。

hello-world.js在 my 中创建一个wwwroot包含以下内容的简单文件时:

export function showAlertSimple() {
    alert("hello world");
}
Run Code Online (Sandbox Code Playgroud)

我可以使用以下方法非常轻松地调用它:

export function showAlertSimple() {
    alert("hello world");
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试对在不同位置创建的 typescript 文件执行相同操作,然后使用 webpack 将其编译为 ES6,将其放入同一文件夹中,blazor 将无法调用该方法:

./NpmJs/src/hello-world2.ts

export function showAlertFromWebPack() {
    alert("Hello World from webpack");
}
Run Code Online (Sandbox Code Playgroud)

./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'
};
Run Code Online (Sandbox Code Playgroud)
public class HelloWorld : JSModule
{
    public HelloWorld(IJSRuntime js) 
        : base(js, "./js/hello-world.js")
    {
    }

    public async Task ShowAlert() => await InvokeVoidAsync("showAlert");
}
Run Code Online (Sandbox Code Playgroud)

然后,这会在浏览器控制台中引发以下异常:

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).
Run Code Online (Sandbox Code Playgroud)

文件本身已正确加载。我可以在源选项卡中看到它。

我在这里缺少什么?

为了完整起见,这里是 JSModule 类,我无耻地从 Steven Sanderson 在 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();
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*rco 5

我找到了 2 个可行的解决方案。一种使用 webpack,另一种则放弃 webpack 并用vitejs替代。

使用webpack,我们需要启用experiments.outputModulehttps://webpack.js.org/configuration/experiments/#experimentsoutputmodule)并设置output.library.typemodulehttps://webpack.js.org/configuration/output/#outputlibrarytype):

最终的配置将如下所示:

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'
};
Run Code Online (Sandbox Code Playgroud)

使用vitejs vite.config.js,配置将如下所示:

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`,
      },
   }
});
Run Code Online (Sandbox Code Playgroud)

Vite 本身会生成 2 个文件:

  • your-package-name.es.js
  • your-package-name.umd.js

您需要链接/使用 blazor 内的 es 文件,然后就可以开始了。