Carica e consuma moduli JS legacy (ad es. IIFE) tramite l'importazione di moduli ES6


9

Ho alcune funzioni IIFE per parte del codice della libreria in un'applicazione legacy che deve funzionare per IE10 + (nessun caricamento del modulo ES6, ecc.).

Tuttavia, sto iniziando a sviluppare un'app React che utilizzerà ES6 e TypeScript e voglio riutilizzare il codice che già ho senza duplicare i file. Dopo un po 'di ricerche ho scoperto che avrei voluto utilizzare un modello UMD per consentire a questi file di libreria di funzionare sia come <script src=*>importazioni sia per consentire all'app React di importarli tramite il caricamento del modulo ES6.

Ho pensato alla seguente conversione:

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

per

(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");
    };
})));

Ciò consentirà il caricamento tramite Import Utils from './Utils.js'comando e consentirà inoltre di inserirlo utilizzando un tag di script<script src='Utils.js'></script>

Tuttavia, alcuni dei miei IIFE usano altri IIFE come dipendenza (male lo so, ma una realtà).

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

Se trasforma correttamente RandomHelpere Utilsin file che possono essere importati, l'app React non è compatibile con questa tecnica. Facendo semplicemente

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

non funziona perché credo che Utils non abbia una finestra. Si caricherà senza problemi ma RandomHelper.DoThing()genererà che Utils non è definito.

Nell'app legacy

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

funziona perfettamente.

Come posso avere RandomHelper in grado di usare Utils in un'app React, mantenendola compatibile con IE ed ES5 ma ancora reagendo. Forse in qualche modo l'impostazione di una finestra / variabile globale?

PS: capisco che il punto del caricamento del modulo ES6 è gestire le dipendenze e i miei IIFE esistenti non sono ideali. Ho intenzione di cambiare eventualmente le classi es6 e un migliore controllo delle dipendenze, ma per ora voglio usare ciò che è disponibile per essere senza riscrivere


4
React usa jsx e nessun browser capisce jsx quindi hai bisogno di babel comunque, non serve a niente usare le dichiarazioni di importazione in un progetto di reazione perché devi comunque usare babel. Anche React si sta allontanando da OO, quindi dire che vuoi usare le classi ES6 con reazioni non ha molto senso. Supporta ancora le classi ma si sta muovendo verso componenti funzionali.
HMR,

Sì, ho babel / webpack e utilizzo il framework CRA.
ParoX,

In node.js posso anche usare global.Utils = (func ... e var Utils = global.Utils; quindi.
Tom

Potrei strofinare un po 'di amore per i componenti web con alcuni stencil che immagino a seconda di ciò che devi supportare.
Chris W.

1
Penso che dovresti davvero passare alla sintassi di importazione ES6 per tutto ciò che desideri utilizzare nella tua nuova app e trasferirla nuovamente nel formato IIFE (o semplicemente UMD) per l'applicazione legacy. Non è necessario riscrivere il file completo, ma correggere le dichiarazioni di dipendenza.
Bergi,

Risposte:


2

Prima di tutto, le funzionalità del modulo, se non vengono esportate esplicitamente, sono di ambito privato nel modulo di definizione . Non puoi aggirare questo fatto. Ma ci sono opzioni alternative che potresti prendere in considerazione.

1. Si presume che una modifica minima del codice legacy sia accettabile

Un lavoro in giro con modifiche minime al codice legacy sarebbe quella di aggiungere semplicemente Utilse RandomHelperal windowall'oggetto. Ad esempio, passare var Utils = (...)();a window.Utils = (...)();. Di conseguenza, l'oggetto sarà accessibile dall'oggetto globale sia con i codici legacy (caricati tramite import) sia con la base di codice più recente.

2. Supponendo che non sia assolutamente tollerabile alcuna modifica nel codice legacy

È necessario creare un nuovo modulo ES6 come proxy per il caricamento degli script legacy:

// ./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 })

Infine, puoi importare Utilse RandomHelperda legacy-main.jsquando richiesto:

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

Utils.MyFunction()
RandomHelper.DoThing()

0

Un approccio che potresti prendere in considerazione è una forma di iniezione di dipendenza : fai in modo che la tua app React riceva RandomHelper, o alcune delle sue proprietà, dal mondo esterno. Quindi puoi rimuoverlo quando sei pronto a tagliare il cavo.

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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.