5

For the last day I researched a mysterious issue in which a moment-timezone feature would not work under particular, seemingly arbitrary circumstances. I discovered that the runtime version of my moment-timezone library was changing at some point from version 0.5.17 to 0.5.13.

Before adding more details, is this a node.js issue or a moment-timezone issue?

The specific problem with moment-timezone I ended up resolving using yarn selective-version-resolutions, but if this is a actually a node.js issue, I'm thinking more extreme measures are called for (yarn install --flat?).

I don't know which dependency was causing the version to change at runtime, but this was the relevant section from my yarn.lock file before adding the resolutions section:

moment-timezone@0.5.17:
  version "0.5.17"
  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.17.tgz#3c8fef32051d84c3af174d91dc52977dcb0ad7e5"
  dependencies:
    moment ">= 2.9.0"

moment-timezone@^0.5.0, moment-timezone@^0.5.4, moment-timezone@~0.5.5:
  version "0.5.13"
  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.13.tgz#99ce5c7d827262eb0f1f702044177f60745d7b90"
  dependencies:
    moment ">= 2.9.0"

As you can see, my direct dependency was on version 0.5.17, but the dependency of my other modules was getting resolved to version 0.5.13. But I don't understand how at some point my dependency was getting resolved to 0.5.13.

To check the moment-timezone version I simply used moment.tz.version. That means that in my production code, the following code printed 0.5.17 until at some point suddenly printing 0.5.13:

const moment = require('moment-timezone');
console.log(`moment.tz.version: ${moment.tz.version}`);

One last detail: the moment-timezone function that was breaking when the version changed to 0.5.13 was the optional flag on the moment.tz function added in version 0.5.14, in this code:

moment(utcDateTime, format).clone().tz(timezone, true)

Can anyone explain how this is possible? I hope it's a moment-timezone bug and not a node.js bug...

joniba
  • 3,339
  • 4
  • 35
  • 49
  • Do you have a `package-lock`? Delete it and your `node_modules`, check you have the correct version in your `package.json` and then run `npm install`. – Max Baldwin May 17 '18 at 15:20
  • @MaxBaldwin, how does that explain module versions changing at runtime? As I said, I resolved the specific issue using yarn selective-version-resolutions. – joniba May 17 '18 at 16:05
  • When you install npm, or yarn in your case, will look at your `yarn.lock` before it looks at your `package.json`. It works almost like a cache. If it sees a reference to a package it is installing, it will install that version and skip the `package.json` – Max Baldwin May 17 '18 at 16:09
  • But it often happens that you have multiple versions of the same package referenced (in the yarn.lock file), and they are supposed to live harmoniously together. – joniba May 21 '18 at 07:42
  • It may have happened because of the order in which packages were added and a later run of a yarn command could have changed it. Since you have multiple dependencies referring different versions, you do need to use resolutions, as you already are doing. – Tarun Lalwani May 21 '18 at 09:13
  • @TarunLalwani But the package changed at runtime. Yarn does not participate in runtime module resolution. The package starts at version 0.5.17 and after some time in which the server is running suddenly changes to version 0.5.13. – joniba May 21 '18 at 16:26
  • That would be really weird. Are you using any watcher or commands which may for some reason be triggering yarn again? – Tarun Lalwani May 21 '18 at 16:33
  • @TarunLalwani, nope, there is definitely no server restart happening. – joniba May 23 '18 at 09:37
  • What other dependency that has moment-timezone@0.5.13 module on it ? – Ezzat May 28 '18 at 03:36

1 Answers1

1

I had the same issue today and after a couple of hours I think I figured out what's happening. If you check the moment-timezone code, you'll see that when it initializes, it requires moment, adds the tz property with all the things related to timezones and finally returns the moment instance modified:

So, if your direct dependency and the dependency in the other module resolved to the same moment version, the same object is modified twice, and the final version you get just depends on the order you required moment-timezone and the module that has moment-timezone as dependency.

In fact, in the moment-timezone code, you can see these lines commented out:

// Do not load moment-timezone a second time.
    // if (moment.tz !== undefined) {
    //  logError('Moment Timezone ' + moment.tz.version + ' was already loaded ' + (moment.tz.dataVersion ? 'with data from ' : 'without any data') + moment.tz.dataVersion);
    //  return moment;
    // }

I don't know why the developers commented out this, but obviously this is a known behavior.

Diego Garcia
  • 369
  • 2
  • 4
  • This helped me resolve a similar issue for moment / moment-timezone where the tz function disappeared from our moment objects. By searching my yarn lock file I found there was another version of moment being included. I changed my version to match the additional version in the lock file [not sure what else was requiring it] but that fixed it so that .tz was available on my moment objects again. Still needs regression testing but looks promising. – The Coder Sep 05 '22 at 04:33