如何在使用 Google protobuf 时调用困在 "System.register()" 模块中的 javascript 函数(从打字稿生成)?

How to invoke a javascript function (generated from typescript) trapped within "System.register()" module while using Google protobuf?

更新: 看来问题出在protobuf。我对其他解决方案也很好,这有助于我解决 Google protobuf 问题。这个问题归结为:

我保留以下问题以备将来使用。


我们已将我们的应用程序从 Javascript 转移到 Typescript,以获得 OOP 等的明显优势。
早些时候从 Html 调用直接 javascript 函数就像:

<script>window.MyFunction()</script>

现在使用 Typescript,所有文件都合并到一个自动生成的 .js 文件中。
在这个单个文件中,每个文件的单独代码都隔离在 System.register() 内。它通常看起来像:

System.register("<filename>", ["<import_1>", ..., "<import_N>"], 
  function (exports_13, context_13) {
    "use strict";

...

  function MyFunction () { ... } // somewhere inside the external function
}

简而言之,.ts 文件中编写的所有内容都包含在 运行 tsc 编译器之后的未命名函数中。

现在,我不知道如何调用一个函数,它被困在另一个函数中,而另一个函数又列在 System.register(...)

问题:从 Html 文件外部调用此类函数的正确语法是什么?

<script> ??? </script>

更新

HTML 尝试在 body 标签中以下列方式调用:

  <script>
    System.import("Main").then(  // Main.ts is one of the file
      function (module)
      {
        throw 0;  // Temporary, to see if we reach till here
        module.main();  // "main()" is the function, which is the entry point
      });
  </script>

在我的代码中,我使用 "browserify" 以便能够为 JS 使用 Google protobuf。该错误仅针对 protobuf 相关文件。这些定义和源文件以 .d.ts 和 .js 格式存在。
错误如下所示:

js: Uncaught (in promise) Error: Fetch error: 404 NOT FOUND
Instantiating http://localhost:50000/folder/external/Server_pb
Loading http://localhost:50000/folder/external/_External
Loading Main 

请注意,50000 是临时端口,"folder" 只是保存 .js 的任何文件夹。 "Server_pb" 是生成的自定义 protobuf 文件。

我的问题可以恰当地描述为非常类似于 this link


相关:

"google-protobuf" 以 systemjs 的方式使用时会出现问题。似乎 Google 只为 nodejs 创建了它。 :-)
为了能够在 Javascript 中为浏览器 使用 protobuf,我们必须手动执行一些操作。这种手动样板文件工作也可以使用一些脚本来完成。

我给出了一个迭代的方式,关于如何实现这个:

  1. 第一步是为JS和TS生成protobuf。同样使用以下命令:

    protoc <file1.proto> <file2.proto> ... <fileN.proto>
    --proto_path=<proto_folder> \
    --cpp_out=<cpp_folder> \
    --js_out=import_style=commonjs,binary:<js_folder> \
    --ts_out=import_style=commonjs,binary:<ts_folder>

  2. 请注意,我们使用的是 commonjs(而不是 systemjs)。图例:

    • <proto_folder> = 存储所有这些 file1/2/N.proto 文件的文件夹路径
    • <cpp_folder> = 要存储 C++ file1/2/N.pb.cc/h 文件的文件夹路径
    • <js_folder> = 您要存储 file1/2/N_pb.js 文件的文件夹
    • <ts_folder> = 您要存储 file1/2/N_pb.d.ts 文件的文件夹
  3. 现在所有的.d.ts(Typescript定义)文件中,都有一定的代码行,会出现编译错误。我们需要评论这些行。手动做,很麻烦。因此,您可以使用 sed(或 Windows 中的 ssed,Mac 中的 gsed)。例如,以

    开头的行
    • sed -i "s/^ static extensions/\/\/ static extensions/g" *_pb.d.ts;
    • 同上 static serializeBinaryToWriter
    • 同上 static deserializeBinaryFromReader
    • sed -i "s/google-protobuf/\.\/google-protobuf/g" *_pb.d.ts; // "./google-protobuf" is correct way to import
  4. 现在,在生成 *_pb.d.ts 时,protoc 编译器不遵循 Typescript 的包装。例如,如果在 fileN.proto 中提到了 package ABC.XYZ,那么 fileN.pb.h 将被包裹在 namespace ABC { namespace XYZ { ... } } 中。在 Typescript 的情况下不会发生同样的情况。所以我们必须在文件中手动添加这些。但是,这里不会像上面那样简单的find/replace。相反,我们必须只找到任何 export class 的第一次出现(这是生成的原型)并包装命名空间。下面是命令:

    • sed -i "0,/export class/{s/export class/export namespace ABC { export namespace XYZ {\n &/}" fileN_pb.d.ts;
    • sed -i -e "$a} }" fileN_pb.d.ts;
  5. 对于生成的 _pb.js 文件,google-protobuf 包的初始导入必须以 ./ 为前缀

    • sed -i "s/google-protobuf/\.\/google-protobuf/g" *_pb.js;
  6. 现在用 tsc -p "<path to the tsconfig.json>" 编译自定义 Typescript 文件,其中 tsconfig.json 可能看起来像(见箭头):

    { "compileOnSave": true, "compilerOptions": { "removeComments": true, "preserveConstEnums": true, "module": "CommonJS", <======= "outDir": "<path to generated js folder>", }, "include": ["../*"], "files": ["<path to file1.ts>", ..., "<path to file2.ts>" }

  7. 现在是非常重要的一步。对生成的 *_pb.d.ts 文件的所有引用都应在自定义文件的 1 中引用。如果需要,该自定义文件可能包含生成的 类 周围的包装器。这将有助于限制仅在该文件中进行字符串替换,这将在接下来的步骤中进行解释。例如,创建自定义文件名 MyProtobuf.tsimport 您的 proto 如下:

    • import * as proto from './fileN; // from fileN.d.ts
  8. 在上面的步骤中,需要注意的是名字"proto"很关键。使用该名称,自动生成 .js 文件。如果您的项目中有多个 proto 文件,那么您可能需要再创建 1 个文件来导出所有文件,然后导入该 1 个文件:

    • // in 'MyProtobufExports.ts' file
      export * from './file1'
      export * from './file2'
      export * from './fileN'
    • import * as proto from './MyprotobufExports // in MyProtobuf.ts file
  9. 经过以上2步,protobuf的用法为,var myClass = new proto.ABC.XYZ.MyClass;

  10. 现在继续我们上面讨论的重要步骤。当我们生成等效的 _pb.js 和我们的自定义 .js 文件时,仍然不会以某种方式找到特殊名称符号 proto。尽管一切都被包裹起来了。这是因为自动生成的 JS 文件(来自 TS 文件)将声明一个 var proto。如果我们评论那个,那个问题就没有了。

    • sed -i "s/var proto = require/\/\/ &/g" Protobuf.js;
  11. 最后一步是将所有.js文件上的browserify放到一个文件中,如下所示。因此,将只有一个 .js 文件,我们必须处理 [good or bad]。在此命令中,顺序非常重要。 file1_pb.js 应该在 file2_pb.js 之前,如果 file1.proto 是由 file2.proto 导入的,反之亦然。如果没有 import 则顺序无关紧要。在任何情况下 _pb.js 应该在自定义 .js 文件之前。

    • browserify --standalone file1_pb.js fileN_pb.js MyProtobuf.js myfile1.js myfileN.js -o=autogen.js
  12. 由于代码是浏览器化的,函数的调用可以通过以下方式完成:

    • window.main = function (...) { ... } // entry point somewhere in the fileN.ts file
      <script>main(...)</script> // in the index.html

仅通过上述步骤,我就可以让 "google-protobuf" 在我的浏览器项目中工作。