-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Add a way to dynamically import the same module multiple times #6946
Comments
This is a requirement to make Deno's security system work, since analysis is made on compile time, then modules cached so they can be immutable, hence not breaking the sandbox in the process. I would argue that altering the content of a module in runtime is not only insecure but also pointless, what possible use case would you have for something like this that can't be solved by restarting the Deno process? |
A module-based extendable proxy server with packet spoofing. If you want to change logic of some module, you have to restart a server and a program which is communicating though it. Or anything else that should run constantly but give a user freedom to extend its logic. |
Because that is very similar to the way browsers work. Clearly dynamic implies something to you that it doesn't actually mean to imply, it means "allow me to conditionally run this code in the current execution context", but all the rules to how modules are fetched, compiled and imported apply whether it be static or dynamic. |
@lem0nify Instead of changing the query string, you can change the hash. When you do this the new cached code replaces the old. However it will not cause remote dependencies to be re-downloaded. Only recompiled (if the source is local and changed) and re-executed. Does that meet your needs? |
@nayeemrmn No, it doesn't. Did you properly read my issue? I ask about module reloading in runtime, without necessity to even restart a process. UPD. What does your reaction mean? Did I wrongly understand your answer? Is it possible to recache module and reload it in runtime? |
Basically what you are asking for is hot module reloading... That is problematic in a lot of ways. ES Modules and their exports are immutable by design. As stated in #5548 we should find better ways to do this to support things like development. There is discussion in #6694 about this as well. Instead of asking for a specific feature, what use case are you trying to solve? |
@kitsonk I've mentioned before, in my answer to Soremwar, but I can explain more detailed. There is a project called tera-toolbox. It is framework for modding an online-game called TERA Online through proxifying game traffic and packet hooking. It supports module hot reloading but it is written in Nodejs and uses classic My goal is to write a similar framework for a different online-game (I won't mention which game exactly if you don't mind) but I like deno much more than nodejs in many other aspects so I want to switch to it from node. |
Based on my understanding this is one core design related to ES6 imports and while theoretically we can do hacks to force the runtime to "forget" about a module and its dependencies (since we have control to In the meantime, we still have a |
I can't understand guys why are you so worried about compatibility with standards and V8 design dogmas. V8 is designed to work in browsers on client side with a bunch of restrictions. If we've already ripped V8 out of its intended environment to use JS on the server side, what's wrong with making some changes to its set of rules and opening up some additional features useful for server and desktop development? Especially considering that these changes contradict the standard only in terms of implementation, not in terms of use. |
@lem0nify Node didn't follow the ECMA standards either. Now every update they have to make is a pain in the ass for the devs Why do you think ES modules are still experimental 5 years later? |
|
@lem0nify Standard compliance is a core idea of the project from almost Day 1, as we want to maximize browser compatibility for many common utility modules. IMO you either accept the standard and follow the rules, or throw the standards out of the window and do your own thing (and in that case, we offer the option of Node-like require in standard modules -- which is not part of the core binary). A middle ground between the two, while sound tempting, is likely to eventually result in some kind of a turmoil in the long run: small bits of complexity added to support a non-standard feature while trying to maintain standard compliance would gradually grow and become huge burden and legacy. If this general need gains enough traction, the standards committee would react -- which often will provide deeper insight and more comprehensive solution than the hacks we can do to just support a single specific use case |
@Soremwar Because they designed something not in the best way. And the best way doesn't have to be full compliance with the standards, I think. @kitsonk Are you talking specifically about the following goal?
Do you at least in theory imagine such program? A library, maybe, but not an application. But the library targeting to compatibility with web browsers won't use dynamic imports, I guess. And also, how about Okay, even considering these goals, why not make some cache cleaning tools inside @kevinkassimo Okay, sure, it sounds convincing. But I still call on you, smart guys who contribute to Deno to think about ways to implement module hot reloading without need to use NodeJS compatibility API (which forces me to write modules in CommonJS style). Maybe a good and painless compromisse can be found. |
I think removing a cached file is doable without chaning any specs or treatment. Not tested: You could theoretically call |
@timreichen Sad but no. Looks like deno process remembers content of every imported |
let i = 0;
// Initial import:
let mod = await import(`./mod.ts#${i++}`);
// Reload:
mod = await import(`./mod.ts#${i++}`);
// Reload:
mod = await import(`./mod.ts#${i++}`); |
@nayeemrmn Sure, but:
|
Won't it just get garbage collected like anything?
Yeah that's a bug. |
@nayeemrmn Oh, wait. No, we don't need
As far as I understand, no. Maybe, JavaScript objects will be GC'ed but not deno process' RAM cache I've told two messages before about. |
@lem0nify, I think if ES module caches aren't implemented using GC-friendly "weak refs" (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef), that's a potential bug/enhancement to V8/whatever actually implements the module cache. If they do, OTOH, and your code doesn't hold any strong refs to the old module, it should be GC'ed just fine. But even if your modules leak, for your particular use-case that should be a total non-issue. Unless the modules are allocating many MiBs of memory and holding strong refs to all that memory, you'd have to reload your module thousands, maybe millions of times for it to cause any significant memory usage problems. My two cents is that hash-based cache-busting should suit your use-case and most others pretty well. It's pretty ugly, but that's probably a simpler solution than figuring how to safely expose the module cache like Node does. Also, it's a widely known cache-busting technique, so it's not like you're doing anything too exotic there. Like some have pointed out, one of Deno's goals is to keep the solid sandbox characteristics of browser JS and APIs, so imo this reluctance to even give it much thought is pretty understandable. I don't develop Deno but I think the idea does raise some red flags :P Kudos for your great taste in waifu. |
Lots of good conversation here. In the end, though, we are not going to "break" the way ES Modules are loaded in v8. The way Node.js community is a module loader API and a "transparent" module hashing solution (e.g. quibble's ESM support). That is something that might work for Deno as well and have opened up #8327 to suggest that. Because we won't directly consider this suggestion, I am respectfully closing in favour of #8327. |
Deno doesn't support
require
but there is one thing whererequire
wins against ES6 imports:In Node.js we can do
and delete required file from cache to load it again after it get changed in runtime. With imports we can't do like this. Even if we use dymanic imports (
await import("./module.ts")
) twice, we both times get the module Deno loaded first time.There is a workaround about it. We can add a query parameter to file path like this:
and it will be loaded again and we get a new its version. But the problem is that BOTH versions of this module will exist in the cache, I suppose. That's not cool.
Why do we even have to store dynamically imported modules in cache? Maybe better make them uncached and garbage-collected and make it possible to import the same module multiple times and each time get the current module content without any ugly workarounds? Otherwise it looks like dynamic imports are just called dynamic but still work in a static way.
The text was updated successfully, but these errors were encountered: