โหลดและใช้โมดูล JS ดั้งเดิม (เช่น IIFE) ผ่านการนำเข้าโมดูล ES6


9

ฉันมีฟังก์ชั่นIIFEสำหรับรหัสห้องสมุดบางส่วนในแอปพลิเคชันรุ่นเก่าที่ต้องทำงานกับ IE10 + (ไม่มีการโหลดโมดูล ES6 เป็นต้น)

อย่างไรก็ตามฉันเริ่มพัฒนาแอป React ที่จะใช้ ES6 และ TypeScript และฉันต้องการใช้รหัสที่ฉันมีอยู่แล้วโดยไม่ต้องทำซ้ำไฟล์ หลังจากการวิจัยเล็กน้อยฉันพบว่าฉันต้องการใช้รูปแบบ UMD เพื่อให้ไฟล์ไลบรารีเหล่านี้ทำงานได้ทั้ง<script src=*>การนำเข้าและอนุญาตให้แอป React นำเข้าผ่านการโหลดโมดูล ES6

ฉันมาด้วยการแปลงต่อไปนี้:

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

สิ่งนี้จะอนุญาตให้โหลดผ่านImport Utils from './Utils.js'คำสั่งและอนุญาตให้แทรกโดยใช้แท็กสคริปต์<script src='Utils.js'></script>

อย่างไรก็ตาม IIFE ของฉันบางคนใช้ IIFE ของคนอื่นเป็นพึ่งพา (แย่ฉันรู้ แต่ความจริง)

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

หากเปิดRandomHelperและเปลี่ยนUtilsเป็นไฟล์ที่สามารถนำเข้าได้อย่างถูกต้องแอป React ไม่สามารถใช้งานได้กับเทคนิคนี้ ทำง่าย ๆ

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

ไม่ทำงานเพราะฉันเชื่อว่า Utils ไม่ใช่การกำหนดขอบเขตหน้าต่าง มันจะโหลดโดยไม่มีปัญหา แต่RandomHelper.DoThing()จะโยนว่า Utils ไม่ได้ถูกกำหนดไว้

ในแอปรุ่นเก่า

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

ทำงานได้อย่างไร้ที่ติ

ฉันจะให้ RandomHelper สามารถใช้ Utils ในแอป React ได้อย่างไรทำให้ IE และ ES5 ทำงานร่วมกันได้ แต่ยังคงใช้งานได้อยู่ บางทีการตั้งค่าตัวแปร window / global อย่างใด?

PS: ฉันเข้าใจจุดของการโหลดโมดูล ES6 คือการจัดการกับการพึ่งพาและ IIFE ที่มีอยู่ของฉันไม่เหมาะ ฉันวางแผนที่จะเปลี่ยนคลาส es6 ในที่สุดและควบคุมการพึ่งพาได้ดีขึ้น แต่ตอนนี้ฉันต้องการใช้สิ่งที่มีอยู่โดยไม่ต้องเขียนใหม่


4
React ใช้ jsx และไม่มีเบราว์เซอร์ที่เข้าใจ jsx ดังนั้นคุณต้องใช้ babel อยู่แล้วไม่มีประโยชน์ที่จะไม่ใช้คำสั่ง import ในโปรเจ็กต์ react เพราะคุณต้องใช้ babel อยู่ดี ปฏิกิริยาก็ย้ายออกจาก OO เช่นกันดังนั้นการบอกว่าคุณต้องการใช้คลาส ES6 พร้อมการตอบสนองนั้นไม่สมเหตุสมผล มันยังคงสนับสนุนคลาส แต่กำลังเคลื่อนไปสู่ส่วนประกอบที่ใช้งานได้
HMR

ใช่ฉันมี babel / webpack และฉันใช้กรอบงาน CRA
ParoX

ใน Node.js ฉันยังสามารถใช้ global.Utils = (func ... และ var Utils = global.Utils. แล้ว
ทอม

สามารถถูองค์ประกอบเว็บบางอย่างที่รักมันด้วยstenciljsฉันจินตนาการขึ้นอยู่กับสิ่งที่คุณต้องการสนับสนุน
Chris W.

1
ฉันคิดว่าคุณควรจะย้ายไปที่ไวยากรณ์การนำเข้า ES6 สำหรับทุกสิ่งที่คุณต้องการใช้ในแอปใหม่ของคุณและแปลงกลับเป็นรูปแบบ IIFE (หรือเพียงแค่ UMD) สำหรับแอปพลิเคชันรุ่นเก่า คุณไม่จำเป็นต้องเขียนไฟล์ใหม่ทั้งหมด แต่แก้ไขการประกาศการพึ่งพา
Bergi

คำตอบ:


2

ให้ของได้รับออกจากทางนี้เป็นครั้งแรก, คุณสมบัติโมดูลหากไม่ได้ส่งออกอย่างชัดเจนถูกกำหนดขอบเขตของเอกชนที่จะกำหนดโมดูล คุณไม่สามารถหลีกเลี่ยงข้อเท็จจริงนี้ได้ แต่มีตัวเลือกการแก้ไขที่คุณอาจพิจารณา

1. ยอมรับการดัดแปลงเล็กน้อยของรหัสดั้งเดิมได้

การหลีกเลี่ยงการเปลี่ยนแปลงรหัสมรดกของคุณเพียงเล็กน้อยคือการเพิ่มUtilsและRandomHelperไปยังwindowวัตถุ ยกตัวอย่างเช่นการเปลี่ยนแปลงไปvar Utils = (...)(); window.Utils = (...)();ดังนั้นวัตถุจะสามารถเข้าถึงได้จากวัตถุทั่วโลกด้วยรหัสดั้งเดิม (โหลดผ่านimport) และฐานรหัสที่ใหม่กว่า

2. สมมติว่าไม่มีการดัดแปลงใด ๆ ในรหัสดั้งเดิมที่สามารถทนได้

ควรสร้างโมดูล ES6 ใหม่เป็นพร็อกซีสำหรับการโหลดสคริปต์ดั้งเดิม:

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

ในที่สุดคุณสามารถนำเข้าUtilsและRandomHelperจากlegacy-main.jsเมื่อต้องการ:

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

Utils.MyFunction()
RandomHelper.DoThing()

0

วิธีหนึ่งที่คุณสามารถพิจารณาได้คือรูปแบบหนึ่งของการฉีดพึ่งพา : ให้แอป React ของคุณได้รับ RandomHelper หรือคุณสมบัติบางอย่างจากโลกภายนอก จากนั้นคุณสามารถลบออกได้เมื่อคุณพร้อมที่จะตัดสายไฟ

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>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.