Parcel: Crosstalk between different unstated state containers for production builds

Created on 24 Sep 2019  路  5Comments  路  Source: parcel-bundler/parcel

馃悰 bug report

Imagine I'm making a questionnaire app. I'm using unstated (the non-next version) to, well, maintain state. One of the things I'm using it for is for paging, of which I have a few different nested routes. There's the main router, then one for questions, and then another pageable component elsewhere. Hopefully I can show via this mildly baffling line:

[MainRouteContainer:1,2,3,4,5:[QuestionsRouteContainer:1,2,...13],6,7,8,...]

Initially I had a general route container that the others extended. It looks a bit like this:

import { Container } from 'unstated';

class RouteContainer extends Container {
  state = { current: 0, direction: null };
  increment = () => {
    this.setState(({ current }) => ({ current: current + 1, direction: 'increment' }));
  }
  decrement = () => {
    this.setState(({ current }) => ({ current: current - 1, direction: 'decrement' }));
  }
  setPage = (page) => {
    this.setState({ current: page });
  }
}

export default RouteContainer;

Then I had MainRouteContainer and QuestionsRouteContainer which extended the above component. This worked fine when running from parcel index.html but doing parcel build index.html would make it so you would route normally in the MainRouteContainer, then you'd get to the questions page with the subrouting, and the questions would start at index 5, basically sharing the same index as the main route, even though they are different classes technically.

This was fixed by making the QuestionsRouteContainer no longer extend the RouteContainer and I just copied the contents of the RouteContainer into it, and it was fine. However I later added a third router which also had duplicated rather than extended content, but this weird bug came back again on production builds, where the third router would start at a non-0 index, taking its value from MainRouteContainer.

At this point I just scrapped RouteContainer and made all three containers use their entire own state and functions, but now the initial bug with the questions came back, even with no class extension!

The only way I managed to fix this is to make the three containers all use entirely different variable names for current. So there's currentM, currentQ, currentP. Then the bugs are squashed.

So I'm thinking, is ParcelJS thinking that this current variable is the same and shared between the three containers? And has this been experienced before or is it specific to my combination of unstated and parcel?

I will hopefully fill out this issue a bit more when I'm less busy, but if anyone knows what's going on I'd be really grateful.

Thanks!

馃實 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.12.3
| Node | v10.15.3 but also experienced on v12
| npm/Yarn | npm 6.9.0
| Operating System | MacOS but also Ubuntu

Bug Waiting

All 5 comments

I have tried replacing the state = {} ESnext syntax with a standard constructor and at first I thought it had done it but it was definitely a red herring.

I've thought about it a bit and am wondering whether it might be to do with them being nested? I made a tiny test where there were three containers as in my example but they were all used in one component, and I couldn't recreate the issue. I will try and see what the minimum reproducible example is and whether it's nested scope funkiness to blame

The only way I managed to fix this is to make the three containers all use entirely different variable names for current. So there's currentM, currentQ, currentP. Then the bugs are squashed.

I didn't completely understand your description of your project and the issue, bug
one known bug is that, in production builds, having multiple files with the same contents actually "merged" them so that in the places where one of these modules was imported, the same exact value was returned (#3523).
So: if you the JS files for your different paging state containers all have the exact same content, then this is a duplicate of #3523 (and you already found a workaround I would have suggested).

How interesting! Is that only if they're exactly the same? What counts as "identical"? Because they have different class names, but their contents are indeed the same. If I created a random function that returned null, would that work?

Maybe I should just move to Parcel 2 or do as I've done and make arbitrary changes to the different files.

At least I know I'm not going mad though 馃槈 thanks for the reply Niklas

What counts as "identical"?

In this case: the JS code after processing (e.g. babel/terser) is the same string. This is because the asset has is computed based solely on this string. So your identical JS modules all have the same hash and then overwrite themselves.

I'm closing this as a duplicate, feel free to ask any further questions though.

Was this page helpful?
0 / 5 - 0 ratings