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

Feature: Generalized ssrLoadModule() #4081

Closed
4 tasks done
wlib opened this issue Jul 2, 2021 · 6 comments
Closed
4 tasks done

Feature: Generalized ssrLoadModule() #4081

wlib opened this issue Jul 2, 2021 · 6 comments

Comments

@wlib
Copy link

wlib commented Jul 2, 2021

Clear and concise description of the problem

Vite uses html files as entry points at both dev and build time. I created a plugin that abstracts this by generating the html content with an esm module before vite internally transforms it. During dev, is relies on ViteDevServer.ssrLoadModule() as if it was a form of dynamic import() but with vite transforms and fast invalidation.

But there are two major problems that get in the way of many important plugin use cases:

  1. ssrLoadModule() was made to load "client-type" code in node, failing to load anything like import fs from "fs/promises" (within the normal vite dev configuration, at least). require() will not work as a substitute for ssrLoadModule().
  2. ssrLoadModule() relies on a ViteDevServer, meaning that there is no way to apply its value (of applying vite transforms to e.g. (j|t)sx? modules) during vite's build mode.

This has forced my plugin into a corner of only being able to work with vanilla node during build time and not being allowed to import any node api's (even dynamically within an if (false) block!) during dev time. This makes my "lowest common denominator" allowed code almost useless, for arbitrary reasons.

Suggested solution

Snowpack has already declared the intention of moving towards fully generalized node SSR, which is exactly what we need. The best solution is basically to integrate what my plugin was aiming to implement directly into vite (abstract index.html as the entry point). But the easiest solution is to simply generalize ssrLoadModule() into a version that:

  1. Explicitly is made to load anything that vite can process as if it were just a dynamic import() of node esm
  2. Works with a module graph that does not necessarily have to be inside a ViteDevServer, enabling its usage within e.g. a build plugin's load() hook just as easily as in dev server middleware

Alternative

I hacked together a vite-incompatible function that simply built a temporary node esm file out of my prerendering code (including JSX) using esbuild and import()ed that file as file:/temporarily/built/module.mjs?cache-buster=Math.random(). It worked exactly how I expected as a proof of concept, with the only issues being efficiency for caching/invalidation (vite's module graph is valuable here) and that it was incompatible with vite's plugins (I had to hack the jsxInject, any variable define's, and had no automatic path rebasing).

Obviously, a vite-native version would be far more streamlined and allow for many more useful plugin applications.

Additional context

No response

Validations

@wlib
Copy link
Author

wlib commented Jul 2, 2021

Forgot to link for Snowpack mention:

https://github.com/snowpackjs/snowpack/issues/3491

@wlib
Copy link
Author

wlib commented Jul 2, 2021

Just a note that I found a sort-of workaround for ssrLoadModule() failing to allow imports for node core modules. It involves adding the modules to the _ssrExternals array via the configuration. It still will fail to resolve from node_modules, though, and also has a non-URL import.meta.url.

Even with such caveats in this workaround, it should be obvious that the current problems are not inherent to vite's design and can't be considered out of scope for the project either.

@wlib
Copy link
Author

wlib commented Jul 2, 2021

I also found a workaround for build time, where I just create a dev server to use ssrLoadModule(), but it would be ideal if I did not have to because it conflates semantics, and is therefore really a hack.

@bluwy
Copy link
Member

bluwy commented Mar 12, 2022

Hi @wlib. I wonder if this feature request still needed?

  1. ssrLoadModule() was made to load "client-type" code in node, failing to load anything like import fs from "fs/promises" (within the normal vite dev configuration, at least). require() will not work as a substitute for ssrLoadModule().

ssrLoadModule is able to load node-only code with import fs from "fs/promises" IIRC, so this should work today.

2. ssrLoadModule() relies on a ViteDevServer, meaning that there is no way to apply its value (of applying vite transforms to e.g. (j|t)sx? modules) during vite's build mode.

Transforming files in build mode should use normal Vite plugins as you have more control of how the final build output/chunks comes out. I don't quite understand how ssrLoadModule should affect build mode? Hope you can clarify more on that.

I think ultimately the ecosystem has grown a lot recently on this area, especially with Vitest spearheading the usage of Vite's SSR transforms in NodeJS. For example, vite-node is used to power Vitest by leveraging Vite as a Node runtime.

@patak-dev
Copy link
Member

For reference, see also the use of vite-node in Nuxt nuxt/framework#2795

@bluwy
Copy link
Member

bluwy commented Jun 26, 2022

Closing due to lack of response, but I think the above comment covers what this issue is proposing.

@bluwy bluwy closed this as completed Jun 26, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Jul 11, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants