Как вызвать функцию javascript (сгенерированную из машинописного текста), захваченную в модуле System.register () при использовании Google protobuf?

Обновление. Похоже, проблема связана с protobuf. Меня устраивает и другое решение, которое помогает мне исправить проблемы с Google protobuf. Эта проблема сводится к следующему:

  • Как интегрировать Google protobuf с Typescript / Javascript для браузера?

Я оставляю ниже вопрос для использования в будущем.


Мы переместили наше приложение с Javascript на Typescript для очевидных преимуществ ООП и т. Д.
Ранее вызов прямой функции javascript из Html был таким же простым, как:

<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", чтобы иметь возможность использовать protobuf Google для JS. Ошибка возникает только для файлов, связанных с 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 - это временный порт, а «папка» - это просто любая папка, в которой хранятся .js. Server_pb - это созданный пользовательский файл protobuf.

Мою проблему можно точно описать как эту ссылку .


Связанный:


person iammilind    schedule 29.06.2018    source источник
comment
window.myfn(), если вы уверены, что он window   -  person Daniel Lizik    schedule 29.06.2018
comment
@DanielLizik, присвоение window.myfn = function () {} в этом случае не сработает, потому что после автогенерации файла .js все глобальные операторы будут частью функции.   -  person iammilind    schedule 29.06.2018
comment
system.js и ваш пакет импортированы? как и этот stackoverflow.com/a/44485955/763564 также Что вы возвращаете из анонимной внутренней функции?   -  person emran    schedule 02.07.2018
comment
@ terminally-chill, да, импортируются и system.js, и autogen.js (в комплекте). Также мы пытаемся использовать Google-protobuf. Из-за чего мы должны использовать браузер. Следовательно, окончательный файл, который представляет собой набор многих файлов .ts, также содержит некоторый код для просмотра. Анонимная внутренняя функция возвращает другую функцию (она слишком сложна для такого новичка, как я, из-за TS в JS). См. Раздел Обновление.   -  person iammilind    schedule 02.07.2018


Ответы (1)


С "google-protobuf" возникают проблемы при использовании в стиле systemjs. Похоже, что Google создал его только для nodejs. :-)
Чтобы иметь возможность использовать protobuf в Javascript для браузера, нам нужно сделать несколько вещей вручную. Такую ручную работу с шаблонами можно выполнить и с помощью некоторых скриптов.

Я предлагаю итеративный способ достижения этого:

  1. Первый шаг - сгенерировать protobuf как для JS, так и для TS. Используйте следующую команду для того же:

    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> = folder path where all these file1/2/N.proto files are stored
    • <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 (определение машинописного текста) есть определенные строки кода, которые будут давать ошибки компилятора. Нам нужно прокомментировать эти строки. Делать это вручную очень громоздко. Следовательно, вы можете использовать sed (или ssed в Windows, gsed в Mac). Например, строки, начинающиеся с,

    • 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 этого не происходит. Поэтому нам нужно вручную добавить их в файл. Однако здесь не будет простого поиска / замены, как указано выше. Скорее, мы должны найти только первое вхождение любого 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. Первоначальный импорт пакета google-protobuf также должен иметь префикс ./ в случае сгенерированного файла _pb.js.

    • sed -i "s/google-protobuf/\.\/google-protobuf/g" *_pb.js;
  6. Теперь скомпилируйте пользовательские файлы Typescript с tsc -p "<path to the tsconfig.json>", где 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 файлы должны быть указаны в одном из ваших пользовательских файлов. Этот пользовательский файл может содержать оболочки вокруг сгенерированных классов, если это необходимо. Это поможет ограничить замену строк только в этом файле, что объясняется в следующем шаге. Например, создайте собственное имя файла как MyProtobuf.ts и import ваш proto следующим образом:

    • import * as proto from './fileN; // from fileN.d.ts
  8. На шаге выше важно отметить, что имя "proto" имеет решающее значение. С этим именем автоматически создаются файлы .js. Если в вашем проекте несколько прото-файлов, возможно, вам придется создать еще 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. С указанными выше двумя шагами использование 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. Последний шаг - поместить browserify во все файлы .js в один файл, как показано ниже. Из-за этого будет только один .js файл, нам придется иметь дело с [хорошим или плохим]. В этой команде очень важен порядок. 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" работать в моем проекте для браузера.

person Swapnil    schedule 08.07.2018