salesforce/lwc

@lwc/rollup-plugin doesn't work with Vite

Opened this issue · 33 comments

Description

The LWC Rollup plugin seems to have a fundamental incompatibility with Vite's core set of plugins (which are not configurable). The issue stems from the fact that both the LWC Rollup plugin and Vite's build-html plugin attempt to transform LWC html files into javascript assets. It doesn't matter which plugin comes first in the chain, as either will break the other because both expect to receive valid html to transform (instead of the javascript that each plugin produces).

If Vite's build-html plugin comes first, it will also complain about LWC's html files lacking a doctype tag (ie <!DOCTYPE html>) as they typically only have a <template> tag along with their html snippets.

Steps to Reproduce

Example Vite configuration:

export default defineConfig({
    plugins: [
       lwc()
    ]
});

Expected Results

It would be nice if this "just worked" ™️.

Actual Results

Errors such as:

RollupError: src/modules/x/app/app.ts (1:9): "default" is not exported by "src/modules/x/app/app.html", imported by "src/modules/x/app/app.ts".

[CompilerError: [rollup-plugin-lwc-compiler] LWC1072: Missing root template tag file: /Users/djunger/code/electron-forge-vite/src/modules/x/app/app.html]

Browsers Affected

N/A

Version

All versions

Possible Solution

This may require a unique plugin distinct from the existing Rollup plugin, though it could also point to systemic integration issues with the LWC platform and its pseudo html templates.

Additional context/Screenshots
Add any other context about the problem here. If applicable, add screenshots to help explain.

Hi @danjunger

I know it doesn't work out of the box with vite, but I've made it work in many different vite setups using configuration or wrapping the plugin, and even monkey-patching internal vite plugins. But I've been working with very complex setups.

The bare minimum change would be playing with:

plugins: [{
  enforce: 'pre',// or post
  ...lwc({ /* rootDir etc */ })
}]

But generally you'll run into other issues (or not) depending on your setup.

In your case vite is resolving and transforming the .html import before the lwc plugin has a chance to do it. When it gets to the lwc plugin it is not in the expected format.

Can you share a repository that mimics your setup?

I'm sure I can make it work for you and we can add instructions to this repo (or maybe suggest a vite-specific plugin).

Actually a great long-term solution would be a vite-specific plugin wrapping the rollup plugin, but that requires accounting for many different types of setups which the plugin can handle inside the config and configResolved hooks.

Like I said, it doesn't matter the order because both plug-ins break each other. I can try to get a repo up later today.

here's a pretty minimal repro repo. https://github.com/danjunger/vite-repro

clone that and then:

  • npm i
  • npm run make -> explodes with:
An unhandled rejection has occurred inside Forge:
RollupError: src/modules/demo/app/app.ts (1:9): "default" is not exported by "src/modules/demo/app/app.html", imported by "src/modules/demo/app/app.ts".
file: /Users/dan/code/vite-repro/src/modules/demo/app/app.ts:1:9

@danjunger I'm not familiar with electron/forge etc, but I made it work under npm run start. danjunger/vite-repro#1

I suppose you just need to replicate the solution in the other config files to get npm run make to work.

Screenshot 2024-10-11 at 20 11 10

Yes, I know it's hacky, especially disabling the vite css processing, but it's the only way for now. Vite is opinionated on css processing so they need to provide a better way to hook into it (or lwc needs to conform to vite by using their query params ?inline ?raw which I don't think is reasonable)

@cardoso thanks a lot for looking into this. Will give this a try.

@danjunger my pleasure. Let me know how it goes and if you run into more issues. I'd love to know everything that can break using LWC with Vite. That would help build an eventual lwc vite plugin (official or not).

Thanks for opening the issue. I have managed to get the @lwc/rollup-plugin to work with Vitest for a simple use case, but it required some additional configuration.

There is also a fundamental issue with CSS, because of how LWC transforms .css into .js versus how Vite does it: vitejs/vite#17700

In addition, we are actively working on a new SSR compiler (@lwc/ssr-compiler, @lwc/ssr-runtime) which does not hook into Vite's existing SSR/environments system.

There is probably significant work to adapt @lwc/rollup-plugin to fully support Vite/Vitest, and it may require creating a new plugin or extending the Rollup plugin.

@nolanlawson I'm currently using vite in my work, using a similar approach I suggested to @danjunger , which works around the issues you mentioned. I even managed to make it work with SLDS. So far I haven't hit any snags.

Do you have thoughts on providing something similar in this repository (as experimental)? What would be the requirements?

If it's too big a commitment for this repo in the short term, I'm thinking about publishing it unofficially, and it could be 'upstreamed' later.

Edit: I'm not sure about the SSR part, as I haven't used it for work yet, but I'd love the chance to dive deeper into it and get it working with vite.

@cardoso I'd be really interested to see your proof-of-concept as a standalone repo. I don't think we want to announce "official" support for Vite yet (either in @lwc/rollup-plugin or an as-yet-unpublished Vite plugin), but I am curious to know how you worked around the CSS issues.

BTW we had an internal report of someone working around it by disabling Vite's built-in CSS behavior:

{
  name: 'disable-css-plugin',
  enforce: 'pre',
  configResolved(config) {
    for (const plugin of config.plugins) {
      if (['vite:css', 'vite:css-post'].includes(plugin.name)) {
        plugin.transform = () => {}
      }
    }
  }
}

@nolanlawson yes, that's exactly what I did here, plus working around a resolution issue for the empty css virtual module.

danjunger/vite-repro#1

I'll come up with a standalone repo soon.

I also wanted to mention that we have run into issues again trying to use LWCs that come from an npm package. It seems like the same problem with conflicting parsing of the html templates but for whatever reason the existing workaround didn't work there where it worked for LWCs that were local to the project.

@danjunger could you provide a repo with the issue? I haven't used LWCs from npm yet, but would like to see it working.

I can't share our library because it's internal, but seemingly any npm module with LWCs (configured via npm: <npm_module_name>) will run into similar issues

Is your project written in TypeScript? LWC module resolution is incompatible with TypeScript module resolution. The fix is to add an entry to your tsconfig paths for every single LWC module specifier that fails to resolve. (Including within all nested dependencies / hidden files.)

That's tedious, so it's on our roadmap to provide tooling to automate the process (and/or update LWC module resolution to be more node-compatible). But that won't be available for a number of months.

@danjunger @wjhsf I was able to use npm dependencies (eg: lightning-base-components) with and without ts without needing to specify tsconfig paths.

Here's the repo:

https://github.com/cardoso/vite-plugin-lwc-example

$ npm i
$ npm run dev

It uses vite-plugin-lwc which I published today (source).

PS: vite build won't work. Only vite dev. I'm still solving this, but for the build script I guess you can just use regular rollup.

Vite plugin doesn't work at all for me. Same issues with html templates.

Thanks for the feedback @danjunger . I'm actively developing the vite plugin and using it, so if I manage to reproduce something like your issue and push a fix I'll let you know. If you ever find a way to push a minimal reproduction, I'll also look into it.

@danjunger I just released vite-plugin-lwc 0.1.1 with some solid improvements:

  • Removed most hacks. HTML imports are now handled the way vite expects, which could fix your issue.
  • Both dev and build are working.
  • It now requires zero configuration, just like the rollup plugin.
import { defineConfig } from "vite";
import lwc from "vite-plugin-lwc";

export default defineConfig({
  plugins: [
    lwc(),
  ],
});

Example

Stackblitz
Repository
GitHub Pages

Plugin

NPM
Repository

@cardoso is this new plugin expecting a particular pattern for component names/paths? i'm getting an error failing to resolve a component:

Error: [vite]: Rollup failed to resolve import "routing/router" from "/Users/dan/code/lwc-example/src/modules/example_app/app/app.html?import"

routing/router is just a component within the template of app that's not being resolved (its in another namespace from app)... i've also tried providing the "modules" param that lwc is accustomed to...

also seeing some errors about optional css files not being found.

@danjunger I just moved a component to another namespace in the integration test and it seems to work. It might be a bit more involved to reproduce your issue. I'll try expanding these tests tomorrow to see if I can reproduce. What does your index.html and js/ts entry point look like? Perhaps it's the underscore in example_app? 🤷

Does your issue happen in dev and build?

Also, are you using ssr by any chance?

I've only now started working on ssr support (example) and it seems to have the css issue still, but I can see where the problem is and the fix should be easy.

In the csr example which even imports lightning-base-components, I don't get css errors anymore.

@danjunger actually, I just published a quick fix. 0.3.1. The logic I'm using to resolve absolute paths in html is a bit more correct now (not perfect). It could solve your issue. The empty css issue is gone even in ssr now.

The change refers to this:

https://github.com/cardoso/vite-plugin-lwc/blob/4751ea9852af33f070769e4614e11455b396c480/packages/vite-plugin-lwc/src/lwc.ts#L54-L61

This hack is a bit problematic, but I'm slowly improving / getting rid of it.

I still get errors about the missing implicit stylesheets in v0. 3.2

@danjunger are you using native stylesheets? I haven't tested that.

Would you be able to share the error? No problem if you need to redact some of it.

Related: #4800

hey @cardoso, i updated the original repro repo to use the vite-plugin-lwc plugin. when i run npm start it fails with this error about not finding the (optional) css files.

9:57:43 AM [vite] Pre-transform error: Failed to resolve import "./app.css" from "src/modules/demo/app/app.html". Does the file exist?
9:57:43 AM [vite] Internal server error: Failed to resolve import "./app.css" from "src/modules/demo/app/app.html". Does the file exist?
  Plugin: vite:import-analysis
  File: /Users/dan/code/vite-repro/src/modules/demo/app/app.html:1:35
  1  |  import _implicitStylesheets from "./app.css";
     |                                    ^
  2  |  import _implicitScopedStylesheets from "./app.scoped.css?scoped=true";
  3  |  import {freezeTemplate, parseFragment, registerTemplate} from "lwc";
      at TransformPluginContext._formatError (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:49193:41)
      at TransformPluginContext.error (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:49188:16)
      at normalizeUrl (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:63984:23)
      at async file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:64116:39
      at async Promise.all (index 0)
      at async TransformPluginContext.transform (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:64043:7)
      at async PluginContainer.transform (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:49034:18)
      at async loadAndTransform (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:51867:27)
      at async viteTransformMiddleware (file:///Users/dan/code/vite-repro/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:61824:24)

npm run make also fails with an error about the index.css file which is being imported in the main entrypoint of the frontend app (renderer.ts):

An unhandled rejection has occurred inside Forge:
RollupError: src/index.css (1:5): Expected ';', '}' or <eof> (Note that you need plugins to import files that are not JavaScript)
file: /Users/dan/code/vite-repro/src/index.css:1:5

1: body {
        ^
2:   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
3:     Arial, sans-serif;

@danjunger thanks so much for the repro!

It seems removing the "include" option fixes your issue:
danjunger/vite-repro#2

I also observed some type definition problems and a mismatch warning with the lwc version you're using which you can fix by updating to 8.7.0:

WARNING: current engine is v8.1.3, but template was compiled with v8.7.0

The type definitions are probably on me, since the plugin pulls its own version of vite. I'll look into fixing this, but otherwise I could run your project using both start and make.

Let me know if updating to 8.7.0 is not an option, as I'll need to look into making the rollup plugin a peer dependency.

thanks for the quick reply! i will try this on our main project later today...

this is starting to get into electron shenanigans, but it seems like when i run npm run make the lwc plugin is running over typescript code when it seems to be expecting that to have already been transformed into js. ie, errors like this:

An unhandled rejection has occurred inside Forge:
RollupError: [lwc:vite-plugin] [plugin lwc:vite-plugin] src/modules/demo/app/app.ts (4:10): SyntaxError: LWC1007: /Users/dan/code/vite-repro/src/modules/demo/app/app.ts: Unexpected token (4:10)

  2 |
  3 | export default class App extends LightningElement {
> 4 |     myProp: string;
    |           ^

i'm also trying this out with the lightning-base-components library to test packaged lwcs and running into issues with that as well.

errors like this when i run npm start:

11:26:11 AM [vite] Pre-transform error: Failed to resolve import "lightning/button" from "src/modules/demo/app/app.html". Does the file exist?
11:26:12 AM [vite] Internal server error: Failed to resolve import "lightning/button" from "src/modules/demo/app/app.html". Does the file exist?
  Plugin: vite:import-analysis
  File: /Users/dan/code/vite-repro/src/modules/demo/app/app.html:3:31
  1  |  import _implicitStylesheets from "./app.css";
  2  |  import _implicitScopedStylesheets from "./app.scoped.css?scoped=true";
  3  |  import _lightningButton from "lightning/button";
     |                                ^

repro repo updated with this example as well.

@danjunger looks like you forgot to add it to the lwc.config.json: danjunger/vite-repro#3

Wondering if we could catch this and provide a suggestion in the logs.

@danjunger just pushed a fix for build 0.3.4: danjunger/vite-repro#4

Also fixed the type conflicts by making vite a peer dependency.

Let me know if it works!

@cardoso 0.3.4 looks to be working in my initial testing. will report back if i run into other problems. thanks again for your efforts!

Woohoo! Thanks @danjunger . Looking forward to your feedback. 🙏