【问题标题】:Loading dependencies with or without react在有或没有反应的情况下加载依赖项
【发布时间】:2021-10-18 16:00:35
【问题描述】:

我有一个旧的 IIFE,它通过 <script src 注入到遗留页面中。

但是,我想在 react 应用程序中使用所有这些旧库。我只需要使用暴露的全局函数。

我认为加载依赖项可以通过脚本或通过 react 的 import 或 nodejs require 工作

这是一个示例 IIFE 的示例

example.js:

var $ = $;
var geocomplete = $.fn.geocomplete;
var OtherExternalLib = OtherExternalLib;

var Example = (function() {
    return {
        init: function () {
            // stuff
        }
    }
)();

遗留代码调用Example.init(),同样,react 代码将调用相同的函数。

$ (jQuery), $.fn.geocomplete, and OtherExternalLib 是所有必须加载的依赖项,它们应该按需加载,或者只是抛出一个很大的错误消息。

我怀疑如果解决方案动态加载 example.js 看起来像

var $ = load("\libs\jquery.js");
var geocomplete = load("\libs\$.fn.geocomplete.js");
var OtherExternalLib = load("\libs\OtherExternalLib.js");

var Example = (function() {
    return {
        init: function () {
            // stuff
        }
    }
)();

并且遗留应用程序仍然可以使用<script src=example.js,而 React 可以使用 import {Example} from example

可以理解,这在某种程度上是在新应用程序中使用遗留代码的一种迂回方式,所以我对如何最好地公开 IIFE(有或没有依赖项)并在 React 中使用它的其他想法持开放态度

【问题讨论】:

标签: javascript reactjs loader


【解决方案1】:

我在我的项目中使用 react+typescript 有一些限制,这就是为什么我必须动态导入我的包(我的项目在带有 AMD 模块的 shell 项目中运行,没有我自己的启动,并更改项目文件的获取方式捆绑)。

由于我只能在运行时动态使用依赖模块,因此我不得不假设它们在构建和捆绑时是有效的。他们中的大多数是IIFE。 所以我使用了惰性动态导入。

类似的东西

import("somePolyfill");

这将由 TSC 翻译

new Promise(function (resolve_3, reject_3) { require(["arrayPolyfill"], resolve_3, reject_3); }); 

这将调用 IIFE 并执行 polyfill 或初始化任何窗口或全局变量,因此其余代码都知道这一点。 如果它返回一个模块或通过错误可以像正常的承诺一样处理然后捕获。

所以我创建了一个包装器

export class DepWrap {
public static Module: any = {};

public constructor() {
    this.getPI();
    this.getSomeModule();
}

public async getPI() {
    DepWrap.Module["PI"] = 3.14;
}

public async getSomeModule() {
    await import('somepath/somemodule').then(($package) => {
        DepWrap.Module["somemodule"] = $package;
    }).catch(() => {
        window.console.log("Some Module error");
    });
}

}

这被编译成

define(["require", "exports", "tslib"], function (require, exports, tslib_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DepWrap = /** @class */ (function () {
    function DepWrap() {
        this.getPI();
        this.getSomeModule();
    }
    DepWrap.prototype.getPI = function () {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                DepWrap.Module["PI"] = 3.14;
                return [2 /*return*/];
            });
        });
    };
    DepWrap.prototype.getSomeModule = function () {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, new Promise(function (resolve_1, reject_1) { require(['somepath/somemodule'], resolve_1, reject_1); }).then(function ($package) {
                            DepWrap.Module["somemodule"] = $package;
                        }).catch(function () {
                            window.console.log("Some Module error");
                        })];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    DepWrap.Module = {};
    return DepWrap;
}());
exports.DepWrap = DepWrap;

});

有了这个,我可以使用我的包装器中的所有依赖模块,每次我需要导入一个新的模块时,我都会创建另一个函数来将它添加到我的包装模块中。

import { DepWrap } from "wrapper/path";
const obj = new DepWrap(); // initialize once in the beginning of project so it would import all the dependencies one by one .

之后在所有文件中,我可以从包装器中导入我的模块

import { DepWrap } from "wrapper/path";
const { PI, somemodule} = DepWrap.Module;

我不确定代码是否也适用于您的场景,但我想稍微调整一下可能会对您的 useCase 派上用场。

另外:如果您正在编写单元测试用例,那么忽略模块并可以为此创建一个模拟,这样您就可以测试您的实际代码了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2019-01-31
    • 2011-02-18
    相关资源
    最近更新 更多