web-dev-qa-db-fra.com

Bazel + Angular + SocketIO Causes: Uncaught TypeError: XMLHttpRequest n'est pas un constructeur

Je veux ajouter ngx-socket-io à mon Angular application. J'utilise Bazel pour exécuter mon Angular dev-server. Malheureusement ngx-socket-io ne semble pas fonctionner avec le ts_devserver hors de la boîte. J'obtiens cette erreur dans la console du navigateur:

Uncaught TypeError: XMLHttpRequest is not a constructor
    at ts_scripts.js?v=1587802098203:16776
    at Object.23.../transport (ts_scripts.js?v=1587802098203:16780)
    at o (ts_scripts.js?v=1587802098203:11783)

Cela semble être causé par xmlhttprequest-ssl qui est une dépendance de engine.io-client et il est nécessaire par ngx-socket-io. Mais ce problème se produit uniquement avec ts_devserver . Exécuter l'application Angular app dans production fonctionne parfaitement.

Reproduction minimale

Vous pouvez facilement l'essayer vous-même: https://github.com/flolu/bazel-socketio-issue

Exécutez simplement yarn install puis yarn dev (cela provoque l'erreur dans la console du navigateur @ http: // localhost: 42 ). Et notez que yarn prod @ http: // localhost: 808 fonctionne très bien!

Modifier 1

Actuellement, il semble y avoir un autre problème sous Windows. Vous ne pouvez donc essayer l'exemple de dépôt que si vous utilisez Mac ou Linux

13
Florian

Le problème vient de engine.io-client, Qui est utilisé en interne par socket.io-client:

Lorsque socket.io-client Est construit en tant que module UMD déclenché par

     "@npm//socket.io-client:socket.io-client__umd",

dans BUILD.bazel, la touche browser de engine.io-client/package.json:

 "browser": {
   "ws": false,
   "xmlhttprequest-ssl": "./lib/xmlhttprequest.js"
 },

est apparemment ignoré.

Par conséquent, les instructions require('xmlhttprequest-ssl') dans node_modules/engine.io-client/lib/transports/*.js Restent dans la version UMD. Comme xmlhttprequest-ssl Est destiné aux environnements sans tête Node et ne fonctionne pas dans les navigateurs, cela entraîne une erreur.

Je n'ai pas trouvé de raison/problème pour ce comportement, mais j'ai trouvé une solution (qui ne devrait pas être considérée comme une solution de contournement):

Réécrivez engine.io-client Avec un script postinstall:

  1. installer le package shelljs: yarn add -D shelljs
  2. mettre à jour postinstall dans package.json à: "postinstall": "node --preserve-symlinks --preserve-symlinks-main ./postinstall-patches.js && ngcc"
  3. mettez le code suivant dans postinstall-patches.js à la racine du projet:
try {
  require.resolve('shelljs');
} catch (e) {
  // We are in an bazel managed external node_modules repository
  // and the resolve has failed because node did not preserve the symlink
  // when loading the script.
  // This can be fixed using the --preserve-symlinks-main flag which
  // is introduced in node 10.2.0
  console.warn(
      `Running postinstall-patches.js script in an external repository requires --preserve-symlinks-main node flag introduced in node 10.2.0. ` +
      `Current node version is ${process.version}. Node called with '${process.argv.join(' ')}'.`);
  process.exit(0);
}

const {set, cd, sed, ls} = require('shelljs');
const path = require('path');
const log = console.info;

log('===== about to run the postinstall-patches.js script     =====');
// fail on first error
set('-e');
// print commands as being executed
set('-v');

cd(__dirname);

log('\n# patch engine.io-client: rewriting \'xmlhttprequest-ssl\' to browser shim');
ls('node_modules/engine.io-client/lib/transports/*.js').forEach(function (file) {
  sed('-i', '\'xmlhttprequest-ssl\'', '\'../xmlhttprequest\'', file);
});

log('===== finished running the postinstall-patches.js script =====');

(Inspiration: https://bazelbuild.github.io/rules_nodejs/#patching-the-npm-packages , qui renvoie à l'exemple https://github.com/angular/ angular/blob/master/tools/postinstall-patches.js )

  1. yarn install
  2. yarn dev

Je soumettrai une demande d'extraction à votre repro GitHub dans quelques minutes.


Alternatives possibles , impossible de les faire fonctionner:

  • utilisez socket.io-client/dist/socket.io.js mais avec un "shim UMD" supplémentaire car il semble être un module "UMD anonyme", OU
  • un peu de magie npm_umd_bundle

Voir le problème Chaque nouveau dépôt npm nécessite une approche unique pour l'ajouter à ts_devserver # 1055 in bazelbuild/rules_nodejs pour plus d'informations sur les deux méthodes.

5
Sebastian B.