简体   繁体   English

Webpack 代码拆分会破坏块之间的 instanceof

[英]Webpack code splitting breaks instanceof between chunks

tl:dr; tl:博士;

class ModuleInBundleA extends ModuleInBundleC { … }

window.moduleInBundleB.foo(new ModuleInBundleA())
class ModuleInBundleB { 
    public foo(bar: ModuleInBundleA|ModuleInBundleC|number) {
        if (bar instanceof ModuleInBundleA || bar instanceof ModuleInBundleC) { 
            // always false
            … 
        }
    }
}

Details:细节:

I'm trying to start using TypeScript + Webpack 4.41.6 on the project that has mostly old codebase.我正在尝试在主要具有旧代码库的项目上开始使用 TypeScript + Webpack 4.41.6。 Basically I want to package several small modules onto bundles to migrate softly without moving whole project onto new js stack.基本上我想将几个小模块打包到包中,以便在不将整个项目移动到新的 js 堆栈的情况下进行软迁移。

I found out that Webpack can do this with code splitting, and package shared code into bundles on it's own with some configuration.我发现 Webpack 可以通过代码拆分来做到这一点,并通过一些配置将共享代码打包成自己的包。 However I can't really control what will be in every bundle unless I build every bundle separately and then only share types, using my own modules as external libraries and that's bit frustrating.但是,我无法真正控制每个包中的内容,除非我单独构建每个包然后只共享类型,使用我自己的模块作为外部库,这有点令人沮丧。

Maybe on this point you can say that I'm doing something wrong already and I would like to hear how can I achieve my goal of using bundles just as vanilla javascript (controlling defer/async on my own and using script tag on my own as well), and I don't really want to pack everything as an independent package with own configuration, types export and so on.也许在这一点上,您可以说我已经做错了,我想听听我如何实现使用捆绑包作为普通 javascript 的目标(自己控制延迟/异步并使用自己的脚本标记作为好吧),而且我真的不想将所有内容打包为具有自己的配置、类型导出等的独立包。

Hope you got overall context.希望你有整体背景。 Closer to the point.更接近正题。

I have the following function, that is bundled to it's own chunk called modal-manager.js .我有以下功能,它被捆绑到它自己的名为modal-manager.js的块中。

public showModal (modal: ModalFilter|AbstractModal|number) {
    let modalId: number;

    console.log(modal);
    console.log(typeof modal);
    console.log(modal instanceof ModalFilter);
    console.log(modal instanceof AbstractModal);

    if (modal instanceof AbstractModal) {
        modalId = modal.getId();
    } else {
        modalId = modal;
    }
    ...
};

(Originally it had no ModalFilter as ModalFilter inherits AbstractModal but I included it for demonstration purposes) (最初它没有ModalFilter因为ModalFilter继承了AbstractModal但我为了演示目的包含了它)

The abstract modal is bundled automatically to modal-utils.js as it's shared between modules.抽象模态会自动捆绑到modal-utils.js因为它在模块之间共享。

Next, I have another big bundle called filter.js .接下来,我有另一个名为filter.js大包。 This one literally creates instance of ModalFilter const modalFilter = new ModalFilter(...) .这个字面上创建了 ModalFilter const modalFilter = new ModalFilter(...)实例。 I think it's work mentioning that instance of modalFilter declared to the global window variable.我认为这是提到向全局window变量声明的 modalFilter 实例的工作。 The trouble is that filter.js calls modal.js code (through window.modalFilter.showModal(modalFilter) ) with no problems whatsoever, but I see the following result of console.log:问题是filter.js调用modal.js代码(通过window.modalFilter.showModal(modalFilter) )没有任何问题,但我看到 console.log 的以下结果:

ModalFilter {shown: false, loading: false, closing: false, html: init(1), id: 0, …}
modal.bundle.23e2a2cb.js:264 object
modal.bundle.23e2a2cb.js:265 false
modal.bundle.23e2a2cb.js:266 false

I disabled mapping to get more into code and see this:我禁用了映射以获取更多代码并看到:

ModalManager.prototype.showModal = function (modal) {
    var modalId;
    console.log(modal);
    console.log(typeof modal);
    console.log(modal instanceof _builder_component_modal_filter__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"]);
    console.log(modal instanceof _modal_abstract__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"]);
    if (modal instanceof _modal_abstract__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"]) {
        modalId = modal.getId();
    }
    else {
        modalId = modal;
    }
    this.modals[modalId].show();
    this.scrollLock(modalId);
};

With my understanding of how javascript works, instanceof should check the object-creator function.根据我对 javascript 工作原理的理解,instanceof 应该检查对象创建器函数。 As code chunks separated ( modal.js has no same code with modal-utils.js ) the creator function should be the same.由于代码块是分开的( modal.jsmodal-utils.js没有相同的代码),creator 函数应该是相同的。 However, getting more to the details I see that webpackJsonp can be really tricky and calling them from kind-of independent environments, still it should be the same environment where FilterModal , AbstractModal is called.然而,更多地了解细节,我发现webpackJsonp可能非常棘手,并且从某种独立的环境中调用它们,但它仍然应该是调用FilterModalAbstractModal的相同环境。 The ModalManager could have own environment I believe.我相信ModalManager可以有自己的环境。 But code called is 100% the same.但是调用的代码是 100% 相同的。 Could that webpackJsonp bundle-arrays be the source of the problem? webpackJsonp捆绑数组可能是问题的根源吗? If so, how can I avoid that and make modal.js bundle understand that both filter.js and others reference the same AbstractModal from modal-utils.js ?如果是这样,我怎样才能避免这种情况并使modal.js包理解filter.js和其他人都从modal-utils.js引用相同的AbstractModal

If I'm doing it wrong, is there a simple way to start bundling small and efficient scripts build with TypeScript and Webpack (or other tools)?如果我做错了,是否有一种简单的方法可以开始捆绑使用 TypeScript 和 Webpack(或其他工具)构建的小型高效脚本? Also, I see the externals feature of Webpack, but haven't figured out how to use that in my case.另外,我看到了 Webpack 的externals功能,但还没有弄清楚如何在我的情况下使用它。 In general, I'm ok with current set up except instanceof issue.一般来说,除了instanceof问题,我对当前设置没问题。 The reason I want to avoid multiple builds is that I'll probably have dozens of smaller bundles that shared across different modules and having dozen of npm packages for each seems excessive.我想避免多次构建的原因是我可能会有几十个较小的包,它们在不同的模块之间共享,并且每个包都有几十个 npm 包似乎过多。

Prefacing this with;以此为序; I don't know the answer to the exact issue that you are facing in regards to the instanceOf part of your question.我不知道您在问题的instanceOf部分面临的确切问题的答案。 This is aimed at the "how did you do it" part.这是针对“你是怎么做到的”部分的。


Approx.大约4 weeks ago we also changed from a .js to .ts implementation with about 1-2 hunderd .js files. 4 周前,我们还使用大约 1-2 个.js文件从.js更改为.ts实现。 Obviously we didn't want to migrate these all at once over to .ts as the effort was too high.显然,我们不想一次性将这些全部迁移到.ts因为工作量太大。

What we ended up doing was identifying .js scripts which needed to run on specific pages and added these into webpack as entry files.我们最终做的是识别需要在特定页面上运行的.js脚本,并将它们作为入口文件添加到 webpack 中。 Then for all of the other suporting scripts, if we required their contents in our new .ts files, we actually created a large index/barrel file for them all, imported them in and then webpack will automatically include these in the correct scope alongside their respective .ts files.然后对于所有其他支持脚本,如果我们需要在新的.ts文件中包含它们的内容,我们实际上为它们创建了一个大的索引/桶文件,将它们导入,然后 webpack 会自动将它们包含在正确的范围中相应的.ts文件。


What does this look like?这看起来像什么?

legacy.index.ts: For every single supporting .js file that we wanted to reference in any way in .ts . legacy.index.ts:对于我们想要在.ts以任何方式引用的每个支持.js文件。

var someFile_js = require("someFile.js");
export { someFile_js };

This then allowed us to import and use this in the .ts files:这允许我们在.ts文件中导入和使用它:

import { someFile_js } from './legacy.index';


In reply to @tonix . 回复@tonix To load a defined list: 要加载定义的列表:

webpack.config配置文件

const SITE_INDEX = require('./path-to-js-file/list.js') module.exports = { entry: SITE_INDEX ... }

list.js列表.js

 { "filename1": "./some-path/filename1.js" "filename2": "./some-path/filename2.ts" }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM