Charger et consommer les modules JS hérités (par exemple IIFE) via les importations de modules ES6

9

J'ai des fonctions IIFE pour une partie du code de bibliothèque dans une application héritée qui doit fonctionner pour IE10 + (pas de chargement de module ES6, etc.).

Cependant, je commence à développer une application React qui utilisera ES6 et TypeScript et je veux réutiliser le code que j'ai déjà sans dupliquer les fichiers. Après un peu de recherche, j'ai découvert que je souhaitais utiliser un modèle UMD pour permettre à ces fichiers de bibliothèque de fonctionner à la fois en tant <script src=*>qu'importations et pour permettre à l'application React de les importer via le chargement du module ES6.

J'ai trouvé la conversion suivante:

var Utils = (function(){
  var self = {
    MyFunction: function(){
      console.log("MyFunction");
    }
  };
  return self;
})();

à

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (factory((global.Utils = {})));
}(this, (function (exports) { 
  exports.MyFunction = function(){
      console.log("MyFunction");
    };
})));

Cela permettra le chargement via la Import Utils from './Utils.js'commande et permettra également son insertion à l'aide d'une balise de script<script src='Utils.js'></script>

Cependant, certains de mes IIFE utilisent d'autres IIFE comme dépendance (mauvais je sais mais une réalité).

var Utils = Utils; // Used to indicate that there is dependency on Utils
var RandomHelper = (function(){
  var self = {
    DoThing: function(){
      Utils.MyFunction();
    }
  };
  return self;
})();

Si vous tournez correctement RandomHelperetUtils dans des fichiers qui peuvent être importés, REACT application n'est pas compatible avec cette technique. Faire simplement

Import Utils from './Utils.js'
Import RandomHelper from './RandomHelper.js'

ne fonctionne pas parce que je crois que Utils n'est pas à portée de fenêtre. Il se chargera sans problème maisRandomHelper.DoThing() jettera que Utils n'est pas défini.

Dans l'application héritée

<script src='Utils.js'></script>
<script src='RandomHelper.js'></script>

fonctionne parfaitement.

Comment puis-je faire en sorte que RandomHelper puisse utiliser Utils dans une application React, en la gardant compatible avec IE et ES5 tout en fonctionnant avec React. Peut-être en quelque sorte définir une fenêtre / variable globale?

PS: Je comprends que le but du chargement du module ES6 est de gérer les dépendances et mes IIFE existants ne sont pas idéaux. Je prévois éventuellement de changer de classe es6 et un meilleur contrôle des dépendances, mais pour l'instant, je veux utiliser ce qui est disponible sans être réécrit

ParoX
la source
4
React utilise jsx et aucun navigateur ne comprend jsx, vous avez donc besoin de babel de toute façon, il est inutile de ne pas utiliser les instructions d'importation dans un projet react car vous devez quand même utiliser babel. React s'éloigne également d'OO, donc dire que vous voulez utiliser des classes ES6 avec react n'a pas beaucoup de sens. Il prend toujours en charge les classes mais évolue vers des composants fonctionnels.
HMR
Oui, j'ai babel / webpack et j'utilise le framework CRA.
ParoX
Dans node.js, je peux également utiliser global.Utils = (func ... et var Utils = global.Utils; then.
Tom
Pourrait frotter un peu de composant Web avec des stenciljs, j'imagine en fonction de ce que vous devez prendre en charge.
Chris W.
1
Je pense que vous devriez vraiment passer à la syntaxe d'importation ES6 pour tout ce que vous souhaitez utiliser dans votre nouvelle application, et la transpiler à nouveau au format IIFE (ou simplement UMD) pour l'application héritée. Vous n'avez pas à réécrire le fichier complet, mais corrigez les déclarations de dépendance.
Bergi

Réponses:

2

Commençons par éliminer les fonctionnalités du module, si elles ne sont pas explicitement exportées, sont étendues en privé au module de définition . Vous ne pouvez pas contourner ce fait. Mais vous pouvez envisager des solutions de contournement.

1. En supposant qu'une modification minimale du code hérité est acceptable

Une solution de contournement avec des modifications minimes à votre code hérité consisterait simplement à ajouter Utilset RandomHelperà l' windowobjet. Par exemple, changez var Utils = (...)();pour window.Utils = (...)();. Par conséquent, l'objet sera accessible à partir de l'objet global à la fois par les codes hérités (chargés via import) et la base de code plus récente.

2. En supposant qu’aucune modification du code hérité ne peut être tolérée

Un nouveau module ES6 doit être créé en tant que proxy pour charger les scripts hérités:

// ./legacy-main.js

const utilsScript = await fetch( './Utils.js' )
const randomHelperScript = await fetch( './RandomHelper.js' )

const utilsScriptText = await utilsScript.text()
const randomHelperScriptText = await randomHelperScript.text()

// Support access to `Utils` via `import` 
export const Utils = Function( `${utilsScriptText}; return Utils;` )()
// Additionally support access via global object 
Object.defineProperty(window, 'Utils', { value: Utils })

// Support access to `RandomHelper` via `import`
// Note that `Utils` which is a dependency for `RandomHelper` ought to be explicitly injected
// into the scope of execution of `RandomHelper`.
export const RandomHelper = Function( 'Utils', `${randomHelperScriptText}; return RandomHelper;` )( Utils )
// Additionally support access via global object 
Object.defineProperty(window, 'RandomHelper', { value: RandomHelper })

Enfin, vous pouvez importer Utilset à RandomHelperpartir en legacy-main.jscas de besoin:

import { Utils, RandomHelper } from './legacy-main.js'

Utils.MyFunction()
RandomHelper.DoThing()
Igwe Kalu
la source
0

Une approche que vous pourriez envisager est une forme d' injection de dépendance : demandez à votre application React de recevoir RandomHelper, ou certaines de ses propriétés, du monde extérieur. Ensuite, vous pouvez le retirer lorsque vous êtes prêt à couper le cordon.

var Utils = (function(){
  var self = {
    MyFunction: function(name){
      return `Hello, ${name}!`;
    }
  };
  return self;
})();

var RandomHelper = (function(){
  var self = {
    DoThing: function(name){
      return Utils.MyFunction(name);
    }
  };
  return self;
})();

const ComponentOne = ({hello}) => {
  return <h1>{hello('ComponentOne')}</h1>;
}

const ComponentTwo = ({hello}) => {
  return <h2>{hello('ComponentTwo')}</h2>
}

const App = ({ExternalFunctions}) => {
  return (
    <header>
      <ComponentOne hello={ExternalFunctions.hello} />
      <ComponentTwo hello={ExternalFunctions.hello} />
    </header>
  )
}

ReactDOM.render(
  <App ExternalFunctions={{hello: RandomHelper.DoThing}} />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Marcus Vinícius Monteiro
la source