简体   繁体   中英

Webpack code splitting breaks instanceof between chunks

tl:dr;

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. Basically I want to package several small modules onto bundles to migrate softly without moving whole project onto new js stack.

I found out that Webpack can do this with code splitting, and package shared code into bundles on it's own with some configuration. 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.

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 .

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)

The abstract modal is bundled automatically to modal-utils.js as it's shared between modules.

Next, I have another big bundle called filter.js . This one literally creates instance of ModalFilter const modalFilter = new ModalFilter(...) . I think it's work mentioning that instance of modalFilter declared to the global window variable. 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:

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. As code chunks separated ( modal.js has no same code with modal-utils.js ) the creator function should be the same. 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. The ModalManager could have own environment I believe. But code called is 100% the same. Could that webpackJsonp bundle-arrays be the source of the problem? 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 ?

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)? Also, I see the externals feature of Webpack, but haven't figured out how to use that in my case. In general, I'm ok with current set up except instanceof issue. 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.

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. 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. Obviously we didn't want to migrate these all at once over to .ts as the effort was too high.

What we ended up doing was identifying .js scripts which needed to run on specific pages and added these into webpack as entry files. 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.


What does this look like?

legacy.index.ts: For every single supporting .js file that we wanted to reference in any way in .ts .

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

This then allowed us to import and use this in the .ts files:

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


In reply to @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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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