Muat dan gunakan modul JS lawas (mis. IIFE) melalui impor modul ES6

9

Saya memiliki fungsi IIFE untuk beberapa kode perpustakaan dalam aplikasi lawas yang perlu bekerja untuk IE10 + (Tidak memuat modul ES6, dll).

Namun, saya mulai mengembangkan aplikasi Bereaksi yang akan menggunakan ES6 dan TypeScript dan saya ingin menggunakan kembali kode yang sudah saya miliki tanpa menduplikasi file. Setelah sedikit riset, saya menemukan bahwa saya ingin menggunakan pola UMD untuk memungkinkan file-file perpustakaan ini berfungsi baik sebagai <script src=*>impor dan untuk memungkinkan aplikasi React untuk mengimpornya melalui pemuatan modul ES6.

Saya datang dengan konversi berikut:

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

untuk

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

Ini akan memungkinkan pemuatan melalui Import Utils from './Utils.js'perintah dan juga memungkinkannya untuk dimasukkan menggunakan tag skrip<script src='Utils.js'></script>

Namun, beberapa IIFE saya menggunakan IIFE lain sebagai ketergantungan (buruk yang saya tahu tetapi kenyataan).

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

Jika diubah dengan benar RandomHelperdan Utilsmenjadi file yang dapat diimpor, aplikasi Bereaksi tidak kompatibel dengan teknik ini. Melakukan secara sederhana

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

tidak berfungsi karena saya percaya Utils tidak dilingkupi jendela. Ini akan memuat tanpa masalah tetapi RandomHelper.DoThing()akan melemparkan bahwa Utils tidak didefinisikan.

Di aplikasi lawas

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

bekerja dengan sempurna.

Bagaimana saya bisa membuat RandomHelper dapat menggunakan Utils dalam aplikasi Bereaksi, menjaganya agar tetap kompatibel dengan IE dan ES5 tetapi masih berfungsi sebagai reaksi. Mungkin entah bagaimana mengatur variabel jendela / global?

PS: Saya mengerti inti dari pemuatan modul ES6 adalah untuk menangani dependensi dan IIFE saya saat ini tidak ideal. Saya berencana untuk akhirnya beralih kelas es6 dan kontrol ketergantungan yang lebih baik tetapi untuk sekarang saya ingin menggunakan whats yang tersedia tanpa menulis ulang

Parox
sumber
4
Bereaksi menggunakan jsx dan tidak ada browser yang mengerti jsx sehingga Anda perlu babel, tidak ada gunanya untuk tidak menggunakan pernyataan impor dalam proyek reaksi karena Anda harus tetap menggunakan babel. Bereaksi juga bergerak menjauh dari OO sehingga mengatakan Anda ingin menggunakan kelas ES6 dengan reaksi tidak masuk akal. Itu masih mendukung kelas tetapi bergerak menuju komponen fungsional.
HMR
Ya saya punya babel / webpack dan saya menggunakan kerangka kerja CRA.
Parok
Dalam node.js saya juga dapat menggunakan global.Utils = (func ... dan var Utils = global.Utils; lalu.
Tom
Bisa menggosok beberapa komponen cinta web di atasnya dengan beberapa stensil yang saya bayangkan tergantung pada apa yang Anda butuhkan untuk mendukung.
Chris W.
1
Saya pikir Anda benar-benar harus pindah ke sintaks impor ES6 untuk semua yang ingin Anda gunakan di aplikasi baru Anda, dan mentransformasikannya kembali ke format IIFE (atau hanya UMD) untuk aplikasi lawas. Anda tidak perlu menulis ulang file yang lengkap, tetapi perbaiki deklarasi dependensi.
Bergi

Jawaban:

2

Mari kita selesaikan dulu, fitur modul, jika tidak diekspor secara eksplisit, dicakup secara pribadi ke modul yang menentukan . Anda tidak dapat menyiasati fakta ini. Tetapi ada beberapa opsi penyelesaian yang dapat Anda pertimbangkan.

1. Dengan asumsi modifikasi kode legacy yang minimal dapat diterima

Cara mengatasinya dengan perubahan minimal pada kode lawas Anda adalah dengan hanya menambahkan Utilsdan RandomHelperke windowobjek. Misalnya, ubah var Utils = (...)();ke window.Utils = (...)();. Akibatnya, objek akan dapat diakses dari objek global dengan kode legacy (dimuat via import) dan basis kode yang lebih baru.

2. Dengan asumsi sama sekali tidak ada modifikasi dalam kode warisan dapat ditoleransi

Modul ES6 baru harus dibuat sebagai proksi untuk memuat skrip lawas:

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

Akhirnya, Anda dapat mengimpor Utilsdan RandomHelperdari legacy-main.jssaat diperlukan:

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

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

Salah satu pendekatan yang dapat Anda pertimbangkan adalah beberapa bentuk injeksi ketergantungan : minta aplikasi Bereaksi Anda menerima RandomHelper, atau beberapa propertinya, dari dunia luar. Kemudian Anda bisa melepasnya saat Anda siap memotong kabelnya.

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
sumber