通过 ES6 模块导入加载和使用遗留 JS 模块(例如 IIFE)
Load and consume legacy JS modules (e.g. IIFEs) via ES6 module imports
我有 IIFE 旧应用程序中需要为 IE10+ 工作的一些库代码的函数(没有 ES6 模块加载等)。
但是,我开始开发一个将使用 ES6 和 TypeScript 的 React 应用程序,我想重用我已有的代码而不复制文件。经过一番研究后,我发现我想使用 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 不在 window 范围内。它会毫无问题地加载,但是 RandomHelper.DoThing()
会抛出 Utils is not defined.
在旧版应用程序中
<script src='Utils.js'></script>
<script src='RandomHelper.js'></script>
完美运行。
我怎样才能让 RandomHelper 能够在 React 应用程序中使用 Utils,使其与 IE 和 ES5 兼容,但仍然可以在 React 中工作。也许以某种方式设置 window/global 变量?
PS:我理解ES6模块加载的重点是处理依赖关系,我现有的IIFE并不理想。我计划最终切换 es6 类 和更好的依赖控制,但现在我想使用可用的东西而无需重写
让我们先解决这个问题,模块功能,如果没有明确导出,则在私有范围内定义模块。你无法回避这个事实。但是您可以考虑一些解决方法。
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 })
最后,您可以在需要时从 legacy-main.js
导入 Utils
和 RandomHelper
:
import { Utils, RandomHelper } from './legacy-main.js'
Utils.MyFunction()
RandomHelper.DoThing()
您可以考虑的一种方法是某种形式的 dependency injection:让您的 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>
我有 IIFE 旧应用程序中需要为 IE10+ 工作的一些库代码的函数(没有 ES6 模块加载等)。
但是,我开始开发一个将使用 ES6 和 TypeScript 的 React 应用程序,我想重用我已有的代码而不复制文件。经过一番研究后,我发现我想使用 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 不在 window 范围内。它会毫无问题地加载,但是 RandomHelper.DoThing()
会抛出 Utils is not defined.
在旧版应用程序中
<script src='Utils.js'></script>
<script src='RandomHelper.js'></script>
完美运行。
我怎样才能让 RandomHelper 能够在 React 应用程序中使用 Utils,使其与 IE 和 ES5 兼容,但仍然可以在 React 中工作。也许以某种方式设置 window/global 变量?
PS:我理解ES6模块加载的重点是处理依赖关系,我现有的IIFE并不理想。我计划最终切换 es6 类 和更好的依赖控制,但现在我想使用可用的东西而无需重写
让我们先解决这个问题,模块功能,如果没有明确导出,则在私有范围内定义模块。你无法回避这个事实。但是您可以考虑一些解决方法。
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 })
最后,您可以在需要时从 legacy-main.js
导入 Utils
和 RandomHelper
:
import { Utils, RandomHelper } from './legacy-main.js'
Utils.MyFunction()
RandomHelper.DoThing()
您可以考虑的一种方法是某种形式的 dependency injection:让您的 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>