Replies: 3 comments 3 replies
-
I like those observations and the feedback. While investigated some of the named existing implementations for Astro, I also had a similar issue with the docs & clarity. We also realized that using a JS runtime in addition to I think I can speak for Astro, that we are also supportive of the outlined goal, however we also want to stress that there should be an "easy" migration path for frameworks which currently use |
Beta Was this translation helpful? Give feedback.
-
Hello! Thank you for the feedback. Allow me to clear up some confusion.
I agree that the current name is a poor choice. The Vite Runtime API in its current state is Vite Client (as opposed to Vite server) or Vite Module Loader.
It doesn't distinguish between them because Vite Runtime is 100% a client API, it's not meant to be used on the server. The only usecase where it should be used on the server is the current Vite SSR implementation. And I think this is where the confusion comes up. There is no unified API that should be used on the server to call As far as I know, there was already an open discussion about this new API on Discord and we are open to hearing your thoughts on how it might be possible to expose this API in a unified way on top of the current ViteRuntime API (probably renamed in the next version). |
Beta Was this translation helpful? Give feedback.
-
Thanks again for the feedback @IgorMinar. We look forward to iron out together a design that works for Workerd (and all other use cases in the table). I think @sheremet-va may have shared this with you already, but for others interested in this discussion, we are working on a new proposal that supersedes the released version of Vite Runtime API. You can check it out in docs form here: Vite Environment API docs. And we are discussing it here: |
Beta Was this translation helpful? Give feedback.
-
This discussion is started as an offshoot from #15774 with focus on alternative JS runtime support in Vite in an interchangeable way that for example would enable support for Cloudflare Workers/workerd in Vite.
Our team at Cloudflare investigated the Vite Runtime API as released in v5.1 and their suitability for adding support for alternative JS runtimes to Vite. We’ve also looked at the newly created plugins that utilize this new API (e.g. vite-node-miniflare by hi-ogawa, vite-envs by sapphi-red, hydrogen by shopify) and even built a set of plugins of our own to get a hands on experience.
Our goal is to devise an API contract for Vite, Vite plugins, and JS runtimes that would allow for the JS runtimes to be swappable with minimal support burden for Vite plugin authors (often web framework authors) and offer full feature fidelity for developers that use Vite for their application development.
After our research we came to the conclusion that the current Vite Runtime APIs as released in version 5.1 are a great step forward for the ecosystem, but might need to be evolved further to address two groups of issues we identified when experimenting with these APIs:
Composability: the APIs don’t go far enough to enable the ecosystem where Vite plugin developers, web framework authors, and JS runtime authors can establish a composable contract that would enable seamless support for alternative JS runtimes in Vite.
Clarity: we found the APIs a bit confusing to use because of ambiguity in naming terminology and lack of clarity in how and where some of the APIs are intended to be used.
More information about our findings follows, but we want to highlight that we think that both of these areas are addressable if the API is further evolved, and we are happy to collaborate with the Vite team as well as the framework plugin authors to land on a design that will work better for the Vite ecosystem.
While we find the composability issues to be more severe than the clarity, for the sake of clarity of this feedback it might be easier to start with this area first.
Clarity of the intended API usage
In spite of reading the announcement, API documentation, and some of the examples of API usage in various repositories, it took us longer than expected to effectively use the Runtime APIs. In the retrospect, we believe that two things could be improved:
The Vite Runtime API overloads the term “runtime” which can carry two meanings. Our understanding of the Vite Runtime API and its design only clicked once we realized that the term “runtime” was used by Vite to primarily mean the module loader (Vite-specific code that stitches and kicks off execution of code transpiled by Vite) and not a JavaScript VM (a virtual machine where JavaScript code executes).
This issue might seem relatively minor, but it prevents effective and non-ambiguous communication which is a significant obstacle that results in misunderstandings and increased barriers to entry.
In this document we disambiguate between the two meanings, by always prefixing the term “runtime” with “JS” to mean the VM, or “Vite” to mean the Vite Runtime APIs and Vite’s module loader.
Our recommendation is to disambiguate this terminology in the introduction of the Runtime API developer docs.
The Runtime API documentation doesn’t sufficiently distinguish between the “server” and “client” parts of the API surface.
By “server” we mean, parts of the API are meant to be used from within the context of the ViteDevServer and are meant to be directly used by Vite plugins. These APIs are exported via the main “vite” module, but this information is omitted from the API docs.
By “client” we mean the parts of the API that are meant to be used within the JS context of the running application, and are meant to be used by the implementers of custom Vite runtimes. These APIs are exported via the “vite/runtime” module.
Our recommendation is that the documentation is split into two distinct parts, and each section clarifies the intended usage of the documented APIs and the module from which the APIs can be exported.
Additionally, we found that the ViteRuntime API is used in Vite’s documentation and examples as an “isomorphic” API (used by both the server and the client code), which we think is problematic as we’ll document in the following section focused on API composability, and recommend to reclassify and document this API as “client” only.
API Composability concerns
As stated earlier, our goal is to make it possible for web framework authors to create Vite plugins, which can support multiple JS runtimes with minimal overhead for these plugin authors as well as their users.
In an ideal world, a developer building an application with Astro, Remix, or other web framework and deploying this application in production to JS runtime of their choice (e.g. Node, Cloudflare Workers, or others) should be able to configure Vite to use the same JS runtime during development, all while taking full advantage of Vite’s dev server, HMR, and ecosystem of various plugins.
While the Vite Runtime API makes it possible to use Vite’s runtime in alternative JS runtimes, it doesn’t provide sufficient facilities and guidance for framework authors and JS runtime providers to establish a contract that would enable the JS runtime within which the application code runs to be easily swappable by Vite’s end users - the application developers.
In our findings, most of the Vite Runtime API currently only focuses on how to load code in a JS runtime, essentially serving as a module loader with the hot module replacement capability. Additionally, Vite also features the createViteRuntime API which is designated by the Vite team as the future replacement for the ssrLoadModule API. We think that the current
createViteRuntime
API is a problematic replacement forssrLoadModule
because it doesn't support Vite plugins for frameworks and alternative JS runtimes to be composed interchangeably by the application developer.If a web framework plugin directly uses the createViteRuntime API or the produced ViteRuntime instance for the purpose of executing server-side application code, this plugin will be locked into executing this application code within the same Node.js VM that is shared with the
ViteDevServer
instance, and the plugin won’t be reusable as-is with an alternative JS runtime.The crux of the problem is that the default
ViteRuntime
implementation provided by the createViteRuntime API relies on JS context sharing betweenViteDevServer
and the application code. To illustrate this, let’s look at the ViteRuntime#executeEntryPoint API and an example inspired by Vite's documentation examples, which returns an exports object of the executed module and use it:Now step 4, invoking the loaded function directly, is possible only if the Vite runtime shares the JS runtime (VM) with ViteDevServer (created in step 1), which allows you to pass the
myExportedFunction
reference from the Vite runtime directly to the callee of theexecuteEntrypoint
API. Interestingly, this JS context sharing behavior is shared withssrLoadModule
, which we experimented with in the past and found it unsuitable for supporting alternative JS runtimes.The reason for this incompatibility is that alternative JS runtimes use a separate OS process and JS context to load and execute the application code via the Vite runtime, so they can’t support directly invocation of
myExportedFunction
from ViteDevServer. Instead we’d need to connect the ViteDevServer JS context (running in Node.js) and the JS context running the Vite Runtime + the application code (running in an alternative JS runtime) via an async and serializable communication channel / RPC which would enable the Vite server code to invokemyExportedFunction
indirectly.This requirement to use some RPC between the framework plugin and the Vite runtime running in an alternative JS runtime, significantly changes the design of the framework plugin, thus making the default
createViteRuntime
/ViteRuntime
implementation non-swappable with one powered by an alternative JS runtime like Cloudflare Workers. For this reason, we think thatcreateViteRuntime
/ViteRuntime
APIs offered as successor to thessrLoadModule
API should be revised.The next steps
We do believe that there is a path forward that would make the JS runtimes in Vite swappable, and inspired by the ongoing work in vite-node-miniflare by hi-ogawa, vite-envs by sapphi-red, hydrogen by shopify we prototyped sketches of API designs that would achieve JS runtime swappability.
But before go too far in proposing API changes, we’d like to pause here and validate our assumption that the Vite core team is interested in considering an alternative design that would enable Vite plugins created by JS runtime vendors and framework authors to be composable. We believe that a composable API design would be great for Vite as it would enable a rich ecosystem of Vite plugins that support interchangeability of JS runtimes used for executing the server-portion of web applications built with Vite.
We also invite web framework plugin authors to chime in and voice their needs, in particular confirm their desire to have most of their web framework plugin code be JS runtime agnostic and reusable across JS runtimes. We already heard from some web framework representatives that are supportive of this effort, and strongly believe that framework plugin authors should have a strong voice in this discussion, as they'll be the primary consumers of these Vite APIs.
Beta Was this translation helpful? Give feedback.
All reactions