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

[feedback] experimentalUseVirtualModules #273

Closed
samuelstroschein opened this issue Dec 11, 2024 · 17 comments
Closed

[feedback] experimentalUseVirtualModules #273

samuelstroschein opened this issue Dec 11, 2024 · 17 comments
Labels

Comments

@samuelstroschein
Copy link
Member

samuelstroschein commented Dec 11, 2024

Feedback wanted for the new bundler config experimentalUseVirtualModules which has been released recently.

import { paraglide } from "@inlang/paraglide-sveltekit/vite"
import { defineConfig } from "vite"

export default defineConfig({
	plugins: [
		paraglide({
			project: "./project.inlang",
			outdir: "./src/lib/paraglide",
+			experimentalUseVirtualModules: true,
		}),
    // ... other vite plugins
	],
})

The compiled output will only emit the runtime.d.ts and messages.d.ts files.

.
└── src/
    └── paraglide/
-        ├── messages/
-        │   ├── de.js
-        │   ├── en.js
-        │   ├── fr.js
-        │   └── ...
-        ├── messages.js
+        ├── messages.d.ts
-        └── runtime.js
+        ├── runtime.d.ts
@minht11
Copy link

minht11 commented Dec 11, 2024

We have monorepo setup where i18n is separate package, exporting vite plugin and compiled messages output. App launches using vite plugin from i18n package:

import { join } from 'node:path'
import { paraglide } from '@inlang/paraglide-vite'

/** @param {string} path  */
const resolve = (path) => join(import.meta.dirname, path)

/** @return {import('vite').PluginOption}  */
export const i18nPlugin = () =>
	paraglide({
		project: resolve('../project.inlang'),
		outdir: resolve('./paraglide'),
	})

After enabling experimentalUseVirtualModules: true types are correct but vite crashes with error:
image
Seems paraglide does not resolve virtual modules across package boundaries.


Could there be a way to keep type and js generation together? Not all things support vite or specifically paraglide vite plugin see. As a workaround we use paraglide CLI to generate output manually, not using it bundler plugin. For our case i18n package is shared, so when running different projects output should not change.


Speaking of CLI will it also get something similar to experimentalUseVirtualModules option? It would be nice to generate types without needing to run full vite build for typecheching and so on.

@jeiea
Copy link

jeiea commented Dec 12, 2024

What version of paraglide-next can test this?

@samuelstroschein
Copy link
Member Author

@jeiea not available for next js :(

  • the next js adapter does not use a bundler plugin of paraglide js :(
  • next js cooking their own solution with turbopack (instead of using vite...) means its not compatible with the vite plugin, nor via unplugin

@samuelstroschein
Copy link
Member Author

@minht11

Seems paraglide does not resolve virtual modules across package boundaries.

That would be a vite limitation. The limitation seems reasonable though. Vite can't know that dependencies use virtual modules. If you use Paraglide JS in a library, I strongly recommend to not use virtual modules.

Could there be a way to keep type and js generation together?

The virtual modules would be an opt-in flag. Else, Paraglide JS defaults to emitting JS with JSDoc/TS declaration files.

Speaking of CLI will it also get something similar to experimentalUseVirtualModules option? It would be nice to generate types without needing to run full vite build for typecheching and so on.

Yes. I plan to merge bundler logic into the paraglide-js package. If that happens, bundler logic (like emitting declaration files) could easily be adapted for the CLI too.

In general, I plan to expose the Paraglide JS compiler for v2. You, and everyone else, will be able to leverage the Paraglide compiler to build your own scripts on top.

@minht11
Copy link

minht11 commented Dec 12, 2024

That would be a vite limitation. The limitation seems reasonable though. Vite can't know that dependencies use virtual modules. If you use Paraglide JS in a library, I strongly recommend to not use virtual modules.

The library code is not bundled, its source code, which passes directly through vite, if it is not possible to resolve relative paths correctly, maybe explicit import like import 'paraglide:messages.js' could be used. In any case I am just bikesheding.

Else, Paraglide JS defaults to emitting JS with JSDoc/TS declaration files.

Will it be possible to enable both at the same time? Now its one or another. Other than that, looking forward to v2 🚀

@samuelstroschein
Copy link
Member Author

Will it be possible to enable both at the same time? Now its one or another. Other than that, looking forward to v2 🚀

Great idea.

Instead of having useVirtualModules, we could have emit: ["virtualModules", "declartionFiles", "jsFiles"] etc. People could mix & match.

@manuel3108
Copy link

I'm not sure if I'm doing something wrong, but using svelte-kit I always get the following vite error: Failed to resolve import "./messages/index/hello_world.js" from "$paraglide-internal-virtual-module:messages.js". Does the file exist?. I'm assuming that the imports will also need to be rewritten to use the new virtual module?

Reproduction

  1. Run pnpx sv create and add paraglide (select that you want to add the demo)
  2. Update paraglide to at least version 15
  3. Reinstall dependencies
  4. Add experimentalUseVirtualModules: true, to vite.config.ts
  5. Start dev server and navigate to /demo/paraglide

I also tried reproducing this with the example app provided in the monorepo, but I had so many different errors after downloading the relevant directory using this tool https://download-directory.github.io that i gave up.

Am I missing something or doing something wrong?

Copy link
Member Author

Can you create a reproduction repository that I can clone?

./messages/index/hello_world.js

This import looks suspicious. There should not be an index/hello_world.js file. Only a messages.js file.

@manuel3108
Copy link

Can you create a reproduction repository that I can clone?

Sure, here you go: https://github.com/manuel3108/paraglide-virtual-module-repro. I tried to split everything up into separate commits, so you can clearly see what I changed. After cloning and installing deps run pnpm dev and navigate to /demo/paraglide

@fromaline
Copy link

@samuelstroschein, maybe it’s just me, but when I enable experimentalUseVirtualModules and add a new message to en.json, I encounter the following error:

TypeError: __vite_ssr_import_6__.new_message is not a function

It seems like the messages aren’t being regenerated properly when using experimentalUseVirtualModules. That said, the feature itself is super handy!

Copy link
Member Author

I will look into manuel's reproduction over the holidays. Working on other v2 tickets in the meantime like #282.

Already got #206 done.

@fromaline
Copy link

@samuelstroschein, oh, you’re already aware of this issue — great to hear that! Thanks for your incredible work!

@samuelstroschein
Copy link
Member Author

@ everyone in this thread:

What benefit do you hope to get with virtual modules?

I am currently implementing Paraglide JS 2.0 which seems to eliminate the benefits of the virtual modules flag:

  1. The default compile output has been switched to per-message modules, which eliminates the optimized tree-shaking virtual modules of v1.0.
  2. A dedicated emitTsDeclarations flag exists to avoid the need for allowJs in the tsconfig.

Is there a benefit aside of optimized tree-shaking and ts declaration files that i am missing?

@minht11
Copy link

minht11 commented Jan 6, 2025

Personally I don't mind either. Sveltekit generates actual files in DEV and most people aren't bothered of it. Having actual files does makes it simpler to understand the output and resolution for modules in complex setups (my monorepo setup comment)

One possible benefit might be performance for HRM/memory with a lot of files, but that is just a wild guess and might not even matter.

switched to per-message modules

Can you elaborate about that? One message, one javascript module file?

@samuelstroschein
Copy link
Member Author

Can you elaborate about that? One message, one javascript module file?

Yes. That helps bundlers tree-shake more efficiently. The output is configurable. The old default, per locale modules, is still supported.

@manuel3108
Copy link

@ everyone in this thread:

What benefit do you hope to get with virtual modules?

Goal would be to not at all emit files in any user facing directories like $lib in SK. Currently, properly adding paraglide also requires making tools like eslint and prettier aware of $lib/paraglide as they should ignore this directory. Ideally, such a thing would not be necessary at all. This was detected in sveltejs/cli#308

@samuelstroschein
Copy link
Member Author

Compiling Paraglide into .sveltekit should work now with v2.0. The vite plugin watches the emitted files, regardless of where they are emitted to.

I think there is no added benefit of virtual modules. Even with virtual modules, the declarations need to be emitted. Emitting the declarations entails emitting a prettierignore.

Closing this for now. Re-open if you disagree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants