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

Node ESM loader #17

Merged
merged 8 commits into from
Feb 27, 2023
Merged

Node ESM loader #17

merged 8 commits into from
Feb 27, 2023

Conversation

cyco130
Copy link
Owner

@cyco130 cyco130 commented Dec 20, 2022

This PR implements a Node ESM loader that transpiles modules with Vite. It enables sourcemaps and breakpoints, fixing #6.

The problem

By default, Vite transforms modules loaded with ssrLoadModule into an async function using a function constructor. So the following module:

import { foo } from "./foo.js";

foo();

is transformed into something like the following:

async function(/* bunch of bookkeeping stuf */) {
  "use strict";
  const __vite_ssr_import_1__ = await __vite_ssr_import__("./foo.js");
  __vite_ssr_import_1__.foo();
}

This way, Vite can create, in runtime, pseudo-modules with full control over module resolution, transformation, and execution.

Unfortunately, functions created from strings have limited support for sourcemaps and breakpoints, making it painful to debug server-side code when using frameworks like Rakkas, vite-plugin-ssr, SvelteKit, Astro, Qwik.js, or SolidStart.

The solution

This PR disables Vite's builtin SSR transform and implements a Node ESM loader to resolve and transform SSR modules instead. The loader uses Vite's dev server to perform the resolutions and transformations. Since it hooks into Node's builtin loading mechanism, sourcemaps and breakpoints work as expected. It's also faster and -potentially- more compatible.

Usage

If you're already using vavite, you can simply use vavite dev --use-loader instead of vite dev. Otherwise:

  • Install @vavite/node-loader as a dev dependency.
  • Add import { nodeLoaderPlugin } from "@vavite/node-loader/plugin" to your Vite config
  • Add nodeLoaderPlugin() to your Vite plugins
  • Run your project with vavite-loader vite dev (or vavite-loader rakkas dev, vavite-loader astro dev, etc.)

Compatibility

The ability to skip the SSR transform landed on Vite 4.1.0. Make sure you have the correct version.

It should work with any Vite SSR project or framework that uses ssrLoadModule to load SSR modules in the same process as Vite itself. I tested with the following:

  • vite-plugin-ssr with React and Vue
  • Rakkas
  • SvelteKit
  • SolidStart (upgrade to Vite 4.1!)
  • Astro
  • Qwik.js

Nuxt 3 doesn't work because it seems to have implemented its own fix using the node:vm module to load SSR modules.

I only did in-depth testing with Rakkas and I did encounter a few glitches on SvelteKit and Astro. But, overall, it seems to work.

It doesn't work on WebContainers (StackBlitz) or Deno.

Limitations

  • ESM loaders are experimental
  • This approach may be leaking memory on every module invalidation

@cyco130 cyco130 force-pushed the feat/esm-loader branch 4 times, most recently from 88990ac to 3c53ea4 Compare February 27, 2023 09:09
@cyco130 cyco130 changed the title WIP: Node ESM loader Node ESM loader Feb 27, 2023
@cyco130 cyco130 added the enhancement New feature or request label Feb 27, 2023
@epavanello
Copy link

It works also for sveltekit!
thanks a lot!

@iMrDJAi iMrDJAi mentioned this pull request Jul 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants