Laden und verbrauchen Sie ältere JS-Module (z. B. IIFEs) über ES6-Modulimporte

9

Ich habe IIFE- Funktionen für einen Teil des Bibliothekscodes in einer Legacy-Anwendung, die für IE10 + funktionieren muss (kein Laden des ES6-Moduls usw.).

Ich beginne jedoch mit der Entwicklung einer React-App, die ES6 und TypeScript verwendet, und möchte den bereits vorhandenen Code wiederverwenden, ohne die Dateien zu duplizieren. Nach einigen Recherchen stellte ich fest, dass ich ein UMD-Muster verwenden möchte, damit diese Bibliotheksdateien sowohl als <script src=*>Importe als auch von der React-App über das Laden des ES6-Moduls importiert werden können.

Ich habe mir folgende Konvertierung ausgedacht:

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

zu

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

Dies ermöglicht das Laden über einen Import Utils from './Utils.js'Befehl und das Einfügen mithilfe eines Skript-Tags<script src='Utils.js'></script>

Einige meiner IIFE verwenden jedoch andere IIFE als Abhängigkeit (schlecht, ich weiß, aber eine Realität).

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

Wenn es richtig drehen RandomHelperund Utilsin Dateien , die importiert werden können, reagieren die App mit dieser Technik nicht kompatibel sind. Einfach machen

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

funktioniert nicht, weil ich glaube, dass Utils keinen Fensterbereich hat. Es wird ohne RandomHelper.DoThing()Probleme geladen, aber es wird ausgelöst, dass Utils nicht definiert ist.

In der Legacy-App

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

funktioniert einwandfrei.

Wie kann ich RandomHelper dazu bringen, Utils in einer React-App zu verwenden, damit IE- und ES5-kompatibel bleiben und trotzdem reagieren können? Vielleicht irgendwie ein Fenster / eine globale Variable setzen?

PS: Ich verstehe, dass der Sinn des Ladens des ES6-Moduls darin besteht, mit Abhängigkeiten umzugehen, und meine vorhandenen IIFEs sind nicht ideal. Ich habe vor, irgendwann die es6-Klassen und eine bessere Abhängigkeitskontrolle zu wechseln, aber jetzt möchte ich das verwenden, was verfügbar ist, ohne es neu zu schreiben

ParoX
quelle
4
React verwendet jsx und kein Browser versteht jsx, sodass Sie ohnehin babel benötigen. Es hat keinen Sinn, importanweisungen in einem reagierenden Projekt nicht zu verwenden, da Sie babel ohnehin verwenden müssen. React entfernt sich auch von OO, sodass es nicht viel Sinn macht zu sagen, dass Sie ES6-Klassen mit React verwenden möchten. Es unterstützt weiterhin Klassen, bewegt sich jedoch in Richtung funktionaler Komponenten.
HMR
Ja, ich habe Babel / Webpack und verwende das CRA-Framework.
ParoX
In node.js kann ich auch global.Utils = (func ... und var Utils = global.Utils; dann.
Tom
Könnte ein bisschen Webkomponenten-Liebe mit ein paar Schablonen darauf reiben, die ich mir vorstelle, je nachdem, was Sie unterstützen müssen.
Chris W.
1
Ich denke, Sie sollten wirklich auf die ES6-Importsyntax für alles umsteigen, was Sie in Ihrer neuen App verwenden möchten, und sie wieder in das IIFE-Format (oder einfach UMD-Format) für die Legacy-Anwendung umwandeln. Sie müssen nicht die gesamte Datei neu schreiben, sondern die Abhängigkeitsdeklarationen korrigieren.
Bergi

Antworten:

2

Lassen Sie uns dies zunächst aus dem Weg räumen. Wenn Modulfunktionen nicht explizit exportiert werden, werden sie privat auf das definierende Modul übertragen . Sie können diese Tatsache nicht umgehen. Es gibt jedoch Umgehungsoptionen, die Sie in Betracht ziehen können.

1. Angenommen, eine minimale Änderung des Legacy-Codes ist akzeptabel

Eine Lösung mit minimalen Änderungen an Ihrem Legacy-Code besteht darin , das Objekt einfach hinzuzufügen Utilsund RandomHelperzu ergänzen window. Wechseln Sie beispielsweise var Utils = (...)();zu window.Utils = (...)();. Folglich kann sowohl über Legacy-Codes (geladen über import) als auch über eine neuere Codebasis vom globalen Objekt aus auf das Objekt zugegriffen werden.

2. Es wird davon ausgegangen, dass absolut keine Änderungen am Legacy-Code toleriert werden können

Ein neues ES6-Modul sollte als Proxy zum Laden der Legacy-Skripte erstellt werden:

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

Schließlich können Sie importieren Utilsund RandomHelperaus legacy-main.jsbei Bedarf:

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

Utils.MyFunction()
RandomHelper.DoThing()
Igwe Kalu
quelle
0

Ein Ansatz, den Sie in Betracht ziehen könnten, ist eine Form der Abhängigkeitsinjektion : Lassen Sie Ihre React-App RandomHelper oder einige seiner Eigenschaften von der Außenwelt erhalten. Dann können Sie es entfernen, wenn Sie bereit sind, das Kabel abzuschneiden.

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
quelle