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

Invalidate imported module cache #5548

Closed
keroxp opened this issue May 17, 2020 · 6 comments
Closed

Invalidate imported module cache #5548

keroxp opened this issue May 17, 2020 · 6 comments
Labels
cli related to cli/ dir feat new feature (which has been agreed to/accepted)

Comments

@keroxp
Copy link
Contributor

keroxp commented May 17, 2020

I'm writing code using dynamic module import for dynamically generated code (tool like node-dev). In Deno, once module imported dynamically, they will be never updated while process running. Are there some way to invalidate module cache? In node.js, required module can be deleted.

Deno.writeTextFileSync("./target.ts", "export const value = 1;");
const v1 = await import("./target.ts")
console.log(v1.value); // 1
Deno.writeTextFileSync("./target.ts", "export const values = 2");
const v2 = await import("./target.ts")
console.log(v2.value); // should be 2 but got 1
@kitsonk
Copy link
Contributor

kitsonk commented May 18, 2020

Currently there isn't an API to invalidate the cache, and I am not sure we would want to do that.

I think the real use case here is "I dynamically imported a module, but the module changed without restarting the current workload, and I expected that module to reflect that."

I think we would have to investigate v8's ability to purge a module that is loaded, because each module exists in the isolate, and so if the module is still referenced, does that change all existing references to that module.

Is there a more specific use case of why this would be required? "Hot module reloading" is a bit of a dangerous thing and there are other ways to support development environments.

@bartlomieju bartlomieju added cli related to cli/ dir feat new feature (which has been agreed to/accepted) labels May 18, 2020
@keroxp
Copy link
Contributor Author

keroxp commented May 19, 2020

I'm developing SSR module like Next.js. It behaves as express's serveStatic and loads and renders jsx file dynamically. On develop environment, jsx templates are often updated so I have to restart Deno process each time (via Deno.watchFs).

@richytong
Copy link

the compiler apis may have what you're looking for @keroxp. I'm working on something similar but am running into reload issues that seem to be addressed in #5253. Here's a temporary hacky workaround for single file jsx + no imports

const [, bundled] = await Deno.bundle('/entry.js', {
  '/entry.js': await readFileStr(pathToJsxEntrypoint),
})

example jsx

const Hey = x => (
  <div>
    <h1>Hey</h1>
    {x.children}
  </div>
)

const Ho = () => <h1>Ho</h1>

const Root = () => (
  <Hey>
    <h1>Ayo</h1>
    <Ho />
  </Hey>
)

ReactDOM.render(<Root />, document.querySelector('#root'))

and React + ReactDOM are loaded via script tags at the moment.. yeah not too pretty

@mdubourg001
Copy link

I'm working on a project where a way to invalidate imported module cache would actually be really useful: I'm watching a directory (using Deno.watchFs) and I'm dynamically importing the modules inside of it to evaluate them. Whenever one these modules change, I would want to import it again to evaluate it with its new changes, what the import cache does not allow me to do.

The "hack" I found is to first copy the content of the module's file to a temp file, and to import and evaluate the temp file before deleting it.

@apiel
Copy link

apiel commented Jun 13, 2020

For dynamic import you can use the same system as for invalidating cache in a url:

await import(`./target.ts?${Math.random()}.ts`); // or with a # instead of ?

I keep the extension at the end cause it might be useful when you are using JSX files.
The problem with this method is the child that you import inside the dynamic import, those one will still be cached.
The other option, already mentioned before is to copy all the files you want to uncache inside a temp folder, and load your module from this different path, so v8 will not be able to use cache, since it is a new path.

The possibility to clear the cache might not be possible with the current implementation of Deno. Deno is using the standard module from V8 and V8 seem to don't support any uncaching feature like this (from my understanding Nodejs is not using the standard module from V8 but instead all import are converted to require, that is using custom loader written in JS, I think commonjs; not sure about all this stuff). So the alternative would be to do the same as nodejs, have your own module loader, maybe with transpiling your code before to send it to deno and replace all the import with the method of your custom loader. But this is really not easy task.

Another option would be to use web workers to isolate our instance https://deno.land/manual/runtime/workers but right now there is bug in worker, it seem to use the same cache #6116 :-/ Hopefully it will be soon fixed, and we could then handle HMR through workers.

@kitsonk
Copy link
Contributor

kitsonk commented Nov 10, 2020

The expectation of ES Modules is that they instantiated in memory per the specification and cannot be "invalidated" and reloaded.

Basically this same restriction applies to Node.js with ESM, though they have a loader API that allows you to hook the resolve and load and there are solutions which handle generating unique modules every time one is requested to support dynamic module replacement. I have opened #8327 to suggest something similar for Deno.

Considering what is requested here cannot be achieved given the way ES Modules work, I am closing this in favour of #8327.

@kitsonk kitsonk closed this as completed Nov 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli related to cli/ dir feat new feature (which has been agreed to/accepted)
Projects
None yet
Development

No branches or pull requests

6 participants