Загрузка и использование устаревших модулей 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<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, но при этом реагируя на него. Возможно, как-то установить окно / глобальную переменную?

PS: Я понимаю, что смысл загрузки модуля ES6 заключается в том, чтобы иметь дело с зависимостями, и мои существующие IIFE не идеальны. Я планирую со временем переключить классы es6 и улучшить контроль над зависимостями, но сейчас я хочу использовать то, что доступно, без переписывания

ParoX
источник
4
React использует jsx, и ни один браузер не понимает jsx, поэтому вам все равно нужен babel, нет смысла не использовать операторы импорта в проекте реагирования, потому что вы все равно должны использовать babel. React также отходит от ОО, поэтому говорить, что вы хотите использовать классы ES6 с реакцией, не имеет особого смысла. Он все еще поддерживает классы, но движется к функциональным компонентам.
HMR
Да, у меня есть babel / webpack, и я использую CRA Framework.
ParoX
В node.js я также могу использовать global.Utils = (func ... и var Utils = global.Utils; затем.
Том
Могли бы вытереть какую-то любовь к веб-компоненту с помощью некоторых stenciljs, которые я представляю в зависимости от того, что вам нужно поддерживать.
Крис У.
1
Я думаю, вам действительно следует перейти к синтаксису импорта ES6 для всего, что вы хотите использовать в своем новом приложении, и перенести его обратно в формат IIFE (или просто UMD) для унаследованного приложения. Вам не нужно переписывать весь файл, но исправьте объявления зависимостей.
Берги

Ответы:

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>

Маркус Виниций Монтейру
источник