Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error with requiring modules because of incorrect sequencing for shared bundles when running in --lazy mode #9177

Closed
natan-stripe opened this issue Aug 3, 2023 · 3 comments
Labels

Comments

@natan-stripe
Copy link

🐛 bug report

This is a similar but different issue to the one fixed in #9093 which @jondlm mentioned in his comment here: #9093 (comment)

The issue seems to be that, in certain cases, Parcel isn't properly blocking execution until all modules have been downloaded and added to the parcelRequire module map.

This results in errors which look like:

Uncaught (in promise) Error: Cannot find module '3qBDj'
    at newRequire (main.js:61:19)
    at newRequire (experience-1.0d761226.js?1691102495451:53:18)
    at newRequire (dependency-1.8d0776f1.js?1691102495603:53:18)
    at newRequire (dependency-1.8d0776f1.js?1691102495603:45:18)
    at localRequire (dependency-1.8d0776f1.js?1691102495603:84:35)
    at bMz2a.lodash (dependency-1.8d0776f1.js?1691102495603:582:15)
    at Function.newRequire (dependency-1.8d0776f1.js?1691102495603:71:24)
    at experience-1.0d761226.js?1691102495451:595:27
    at async Promise.all (index 0)
    at async exports.default (experience-1.0d761226.js?1691102495451:582:52)

🎛 Configuration (.babelrc, package.json, cli command)

Here's a repo with the steps to reproduce the issue: https://github.com/natan-stripe/lazy-testbed/tree/main

🤔 Expected Behavior

During the initial lazy build and load, either the shared dependency (lodash in the example) should be inlined into both of the modules which depend on it or their execution should be blocked until the shared bundle is downloaded.

The way it works on subsequent loads is that the bundles get grouped together with a Promise.all from the logic here: https://github.com/parcel-bundler/parcel/blob/v2/packages/runtimes/js/src/JSRuntime.js#L481. On initial load, though, the array of loaderModules does not include the shared bundle.

😯 Current Behavior

The two async bundles (dependency-1, dependency-2) get downloaded and executed immediately before the shared asset bundle has had time to download and resolve which results in them being unable to resolve the references to the shared asset (lodash).

💁 Possible Solution

I'm not familiar enough with Parcel's internals still to be able to suggest a good fix, but, I think the issue is most likely in the logic of bundleGraph.getBundlesInBundleGroup which is used here: https://github.com/parcel-bundler/parcel/blob/v2/packages/runtimes/js/src/JSRuntime.js#L349

If this function returned an array with both the target bundle (dependency-1 or dependency-2) and the shared bundle, then I believe that the rest of the logic would work correctly.

🔦 Context

This is blocking us from being able to use Parcel in devmode because of our heavy usage of dynamic imports throughout the application. We really need --lazy in order for it to be feasible for us to run the application, but, because of the ordering and shared bundle issue here, we bump into errors unexpectedly throughout the application.

💻 Code Sample

https://github.com/natan-stripe/lazy-testbed/tree/main

🌍 Your Environment

Software Version(s)
Parcel 2.0.0-nightly.1348
Node v18.14.0
npm/Yarn yarn 1.22.19
Operating System OSX
@jondlm
Copy link
Contributor

jondlm commented Aug 9, 2023

flowchart TD
    A(main.ts) -->|async| B(experience-1)

    B -->|async| C(dependency-1)
    B -->|async| D(dependency-2)
    subgraph loaded simultaneously with `Promise.all`
        direction RL
        C
        D
    end
    C --> E(lodash)
    D --> E
Loading

It looks like the lazy mode algorithm sees either dependency-1 or dependency-2 (whichever races first) and decides to split lodash into a shared bundle. It does this correctly but it doesn't correctly detect there should be multiple loaders that should block the execution of the dependency-* file that depends on the shared bundle. On the failing first page load we're hitting this case. Then on the subsequent load we're hitting this case and the code correctly waits for the shared bundle to load before executing the sync code.

It's not clear yet whether this is a fundamental limitation of trying to split shared bundles out when Parcel has only seen part of the graph. It seems like there's a fix lurking somewhere here but we haven't nailed it down yet.

Our workaround for the moment is to crank minBundles to a really large number. That causes the bundler to simply inline lodash into both bundles and the first load works correctly.

@maximgeerinck
Copy link

maximgeerinck commented Jan 18, 2024

I'm getting this in the latest version v2.11.0 where whenever i use both import("my-lib") and somewhere else import from "my-lib"; it throws unknown module found and fails to build (watch mode only!).

Setting minBundles to like 100000 didn't work

Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

@github-actions github-actions bot added the Stale Inactive issues label Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants