Open mactyr opened 2 years ago
@mactyr Thanks for posting! We'll take a look as soon as possible.
In the mean time, there are a few ways you can help speed things along:
Please remember: never post in a public forum if you believe you've found a genuine security vulnerability. Instead, disclose it responsibly.
For help with questions about Sails, click here.
Hey @mactyr, thank you for all the info. Do you have any thoughts about where we could document this behavior, that would have made it easier to debug?
@eashaw, fair question. Really what I think is that sails should not remove anything from the require cache; then there's no surprising behavior to document!
So, first I'd ask, is it absolutely necessary that the cache be bypassed/edited in the contexts where sails uses include-all in the first place? Or is it just default behavior that's never been questioned because no one's noticed it causing problems? I don't know enough about sails internals to answer that myself.
Assuming that the cache bypassing is strictly necessary, you might look at using stealthy-require, which I noticed being used by another package I import. stealthy-require temporarily empties the require cache in order to bypass it, but then restores the cache after it's done with whatever it's been asked to require
, so the cache behaves more as expected for the rest of the application. (Though there is still some possibility for breakage in that any module imported by include-all would be a different copy than the one the rest of the application is using.)
If the behavior can't be changed (or until it's changed) I'd suggest documenting it somewhere up front in the configuration section (e.g. https://sailsjs.com/documentation/reference/configuration) since that's where I noticed the problem manifesting. You could note that any module previously require
d by the application prior to loading the configuration, and that is also required by a configuration file, will be swapped out for a re-initialized copy after the configuration loads. There may be other places where include-all is used as well, but that's the one that burned me.
Also, my hope is that just having this issue on record will help! When I googled terms like "sails require cache" nothing helpful came up, but hopefully it will now for others. :slightly_smiling_face:
Hey @mactyr, I'm sitting with @mikermcneil and going over the history of this decision.
Here's what I learned:
We're open to having this be configurable, but it would involve testing and feedback from people in the community that use an implementation of auto-reload.
Thank you for all the detail and for prompting us to have a discussion!
Ok, thanks for looking into it. A couple of clarifying questions:
I'm experiencing a similar issue. In my case, it essentially means that without intrusive, counter-intuitive patches, I can't leverage the singleton nature of node modules if Sails's objects require them.
Node version: 14.16.0 Sails version (sails): 1.4.2 ORM hook version (sails-hook-orm): N/A Sockets hook version (sails-hook-sockets): N/A Organics hook version (sails-hook-organics): N/A Grunt hook version (sails-hook-grunt): N/A Uploads hook version (sails-hook-uploads): N/A DB adapter & version (e.g. sails-mysql@5.55.5): N/A Skipper adapter & version (e.g. skipper-s3@5.55.5): N/A
In my sails application's config/local.js, I require some shared configuration from outside my sails directory (but within my broader code base) to help determine my sails configuration. E.g., in local.js I have:
shared-dir/ has an index.js file that exposes a number of modules within that directory including
config
. I then useconfig
to help determine my sails configuration.shared-dir/ also contains a file called (for example) shared-object.js, which is also exported by shared-dir/index.js as
shared-object
. My code base is expectingshared-object
to always be the same object regardless of where or when it isrequire
d. That is, I'm relying on the normal behavior of node's require cache to ensure that every time I require ../../shared-dir/shared-object.js I get the same object. I am not expecting shared-object.js to be re-evaluated from scratch every time I require it, resulting in a new instance of the object, because that's not how node works.However, I've now discovered that by default, sails' include-all deletes from the require cache anything that it includes and anything required by those files, and so on! This results in different parts of my application having independent, unrelated copies of
shared-object
depending on whether they wererequire
d before or after a given use of include-all. This caused a bug in my application that was quite difficult to track down because the root cause seemed contrary to everything the node documentation/community says about how the require cache works.A comment in help-include-all-sync.js describes this default deletion behavior as "sane defaults". I don't know enough about the history/goals of that package to understand why cache deletion was chosen as the default, but to me changing core platform mechanics without loud and clear documentation does not seem... sane. :shrug:
In the example outlined above, I should be able to work around the problem by changing
to
so that the rest of the directory (including shared-object) doesn't get swept up in include-all's deletion routine, but I will probably have to hunt down other instances of this as well, and the deletion behavior remains a potential source of bugs for anyone who isn't aware of the need to carefully consider the way they scope their
require
s within sails.