Blazor组件库JS隔离调用TypeScript库showHello函数报错求助
我有一个用TypeScript编写的JavaScript库,编译后的代码如下:
(function(f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.richTextEditor = f() } } )(function() { var define, module, exports; return (function() { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = "function" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error("Cannot find module '" + i + "'"); throw a.code = "MODULE_NOT_FOUND", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function(r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]); return o } return r } )()({ 1: [function(require, module, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.showHello = void 0; const greet_1 = require("./greet"); function showHello(divName, name) { const elt = document.getElementById(divName); elt.innerText = (0, greet_1.sayHello)(name); } exports.showHello = showHello; } , { "./greet": 2 }], 2: [function(require, module, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sayHello = void 0; function sayHello(compiler) { return `Hello from ${compiler}`; } exports.sayHello = sayHello; } , {}] }, {}, [1])(1) });
我尝试在Blazor中通过JSInterop调用该库的showHello函数,使用的C#代码如下:
public class TypeScriptInterop { private readonly Lazy<Task<IJSObjectReference>> _moduleTask; public TypeScriptInterop(IJSRuntime jsRuntime) { _moduleTask = new(()=> jsRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/Blazored.RichTextEditor/js/bundle.generated.js").AsTask()); } public async ValueTask TsButtonClicked() { var javaScript = await _moduleTask.Value; if (_moduleTask.IsValueCreated) { Console.WriteLine("Captured Js"); } await javaScript.InvokeVoidAsync("richTextEditor.showHello", "greeting", "Ubhaya"); } }
运行时出现以下错误:
WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not find 'richTextEditor.showHello' ('richTextEditor' was undefined).
直接在Blazor WASM项目的index.html中通过<script src="./_content/Blazored.RichTextEditor/js/bundle.generated.js"></script>引入该JS文件就能正常运行。但我正在开发Blazor组件库,希望采用JS隔离的方式实现,请问当前方案下如何解决这个问题?
问题核心:当用Blazor的JS隔离方式(import)加载模块时,模块不会自动将richTextEditor挂载到全局对象(如window),但你的C#代码仍在尝试调用全局作用域下的richTextEditor.showHello,导致找不到对象。
以下是两种可行的解决方式:
方式1:修改TypeScript源码与打包配置(推荐)
如果能修改TS源码,直接将需要暴露的方法以ES模块格式导出:
// 主TS文件 import { sayHello } from './greet'; export function showHello(divName: string, name: string) { const elt = document.getElementById(divName); if (elt) { elt.innerText = sayHello(name); } }
然后调整打包工具(如Webpack、Rollup)的配置,将输出格式设置为ES模块(output.module: true或类似配置)。编译后的JS会包含export语句,不再依赖全局挂载。
方式2:适配现有打包后的JS文件
如果无法修改源码或打包配置,可在现有JS文件末尾添加一行代码,显式导出模块内容:
// 在现有打包代码的最后添加 export const showHello = window.richTextEditor.showHello; // 或导出整个对象 // export const richTextEditor = window.richTextEditor;
这样Blazor通过import加载模块时,就能获取到导出的方法。
调整C#调用代码
无论采用哪种方式,都需要修改C#的调用逻辑,直接调用模块导出的方法,而非全局对象:
public async ValueTask TsButtonClicked() { var javaScript = await _moduleTask.Value; // 如果导出的是单个showHello方法 await javaScript.InvokeVoidAsync("showHello", "greeting", "Ubhaya"); // 如果导出的是整个richTextEditor对象 // var editor = await javaScript.InvokeAsync<IJSObjectReference>("richTextEditor"); // await editor.InvokeVoidAsync("showHello", "greeting", "Ubhaya"); }
注意事项
- 确保打包后的JS文件是ES模块格式(包含
export语句),Blazor的JS隔离仅支持ES模块。 - JS隔离的核心是避免污染全局作用域,因此尽量采用模块导出的方式暴露方法,不要依赖全局变量。
内容的提问来源于stack exchange,提问作者Ubhaya Kalanamiththa

