Skip to content

Commit 80a0084

Browse files
authored
feat: hmr (#61)
* feat: hmr * fix: simplify hmr * feat: add hmr to plugin * chore: improve hmr in csr-with-base-components * chore: move tabs to a separate component * chore: changeset * chore: bump 4.1.0 * chore: update examples
1 parent 1c2a0e2 commit 80a0084

File tree

24 files changed

+313
-410
lines changed

24 files changed

+313
-410
lines changed

examples/csr-with-base-components/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
<link href="https://cdn.jsdelivr.net/npm/@salesforce-ux/[email protected]/assets/styles/salesforce-lightning-design-system.min.css" rel="stylesheet">
99
</head>
1010
<body>
11-
<script type="module" src="/src/main.js"></script>
11+
<script type="module" src="/src/main.ts"></script>
1212
</body>
1313
</html>

examples/csr-with-base-components/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
"lwc": "^8.16.1",
1818
"typescript": "^5.8.2",
1919
"vite": "^6.2.1",
20-
"vite-plugin-lwc": "^4.0.2"
20+
"vite-plugin-lwc": "^4.1.0"
2121
}
2222
}

examples/csr-with-base-components/src/main.js examples/csr-with-base-components/src/main.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ import "@lwc/synthetic-shadow";
22
import { createElement } from "lwc";
33
import App from "c/app";
44

5+
document.body.querySelector("c-app")?.remove();
6+
57
const elm = createElement("c-app", { is: App });
68
document.body.appendChild(elm);
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
<template>
22
<lightning-layout multiple-rows="true">
33
<lightning-layout-item padding="around-small" size="12">
4-
<c-header title="Vite + LWC" sub-title="csr with base components"></c-header>
4+
<c-header></c-header>
55
</lightning-layout-item>
66
<lightning-layout-item padding="around-small" size="12">
7-
<lightning-tabset variant="scoped">
8-
<lightning-tab label="Counter">
9-
<c-counter label="Counter"></c-counter>
10-
</lightning-tab>
11-
<lightning-tab label="Tab 2">
12-
Tab 2
13-
</lightning-tab>
14-
</lightning-tabset>
7+
<c-tabs></c-tabs>
158
</lightning-layout-item>
169
</lightning-layout>
1710
</template>
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { LightningElement, api } from "lwc";
22

33
export default class Header extends LightningElement {
4-
@api title = "Title";
5-
@api subTitle = "Subtitle"
4+
@api title = "Vite + LWC";
5+
@api subTitle = "csr with base components"
66
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<lightning-tabset variant="scoped">
3+
<lightning-tab label="Counter">
4+
<c-counter></c-counter>
5+
</lightning-tab>
6+
<lightning-tab label="Tab 1">
7+
Tab 1
8+
</lightning-tab>
9+
</lightning-tabset>
10+
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { LightningElement } from "lwc";
2+
3+
export default class Tabs extends LightningElement {
4+
connectedCallback(): void {
5+
console.log("Tabs component connected");
6+
}
7+
}

examples/csr/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
"lwc": "^8.16.1",
1616
"typescript": "^5.8.2",
1717
"vite": "^6.2.1",
18-
"vite-plugin-lwc": "^4.0.2"
18+
"vite-plugin-lwc": "^4.1.0"
1919
}
2020
}

examples/csr/src/main.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { createElement } from "lwc";
22
import App from "c/app";
3+
4+
document.body.querySelector("c-app")?.remove();
5+
36
const elm = createElement("c-app", { is: App });
47
document.body.appendChild(elm);

examples/csr/src/modules/c/app/app.css

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
will-change: filter;
55
transition: filter 300ms;
66
}
7+
78
.logo:hover {
89
filter: drop-shadow(0 0 2em #646cffaa);
910
}
11+
1012
.logo.lwc:hover {
11-
filter: drop-shadow(0 0 2em #42b883aa);
13+
filter: drop-shadow(0 0 2em #1798c1);
1214
}

examples/csr/src/modules/c/app/app.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
<img src="/lwc.svg" class="logo lwc" alt="LWC logo" />
88
</a>
99
</div>
10-
<c-hello-world msg="Vite + LWC"></c-hello-world>
10+
<c-hello-world msg="Vite + LWC!"></c-hello-world>
1111
</template>

examples/csr/src/modules/c/app/app.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { LightningElement } from "lwc";
22

33
export default class App extends LightningElement {
4-
4+
connectedCallback(): void {
5+
console.log("App component connected");
6+
}
57
}

examples/csr/src/modules/c/helloWorld/helloWorld.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
<h1>{msg}</h1>
33

44
<div class="card">
5-
<button type="button" onclick={handleClick}>count is {count}</button>
5+
<button type="button" onclick={handleClick}>count is: {count}</button>
66
<p>
77
Edit <code>modules/c/helloWorld/HelloWorld.html</code> to test HMR
88
</p>
99
</div>
1010

1111
<p>
12-
Check out <a href="https://lwc.dev/guide/install#via-rollup" target="_blank">create-lwc</a>, the official LWC + Vite starter
12+
Check out <a href="https://lwc.dev/guide/install#via-rollup" target="_blank">create-lwc</a>, the official LWC + Rollup starter
1313
</p>
1414
<p>
1515
Learn more about IDE Support for LWC in the&nbsp;<a href="https://lwc.dev/guide/install#tools" target="_blank">LWC Installation Guide</a>.
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { LightningElement, api } from "lwc";
22

33
export default class HelloWorld extends LightningElement {
4-
@api msg = "Hello, World!";
4+
@api msg = "Hello, World!!";
55

6-
count = 0;
6+
count = 4;
77

88
handleClick() {
9-
this.count++;
9+
this.count += 2;
1010
}
1111
}

examples/ssr/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424
"@types/express": "^5.0.0",
2525
"cross-env": "^7.0.3",
2626
"lwc": "^8.16.1",
27-
"vite-plugin-lwc": "^4.0.2"
27+
"vite-plugin-lwc": "^4.1.0"
2828
}
2929
}

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
"packageManager": "[email protected]",
77
"scripts": {
88
"build": "pnpm -r run build",
9+
"bump": "pnpm changeset version",
910
"dev": "pnpm -r --filter='./packages/*' run dev",
1011
"test": "vitest",
1112
"prepare": "npx simple-git-hooks",
1213
"lint": "eslint .",
1314
"example:csr": "pnpm -r --filter='./examples/csr' run dev",
15+
"example:csr-with-base-components": "pnpm -r --filter='./examples/csr-with-base-components' run dev",
1416
"example:ssr": "pnpm -r --filter='./examples/ssr' run dev",
1517
"typecheck": "pnpm -r typecheck"
1618
},

packages/vite-plugin-lwc/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 4.0.0
22

3+
## 4.1.0
4+
5+
### Minor Changes
6+
7+
- 4184aa3: Support HMR
8+
39
## 4.0.2
410

511
### Patch Changes

packages/vite-plugin-lwc/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vite-plugin-lwc",
3-
"version": "4.0.2",
3+
"version": "4.1.0",
44
"license": "MIT",
55
"author": "Matheus Cardoso <[email protected]>",
66
"maintainers": [
@@ -11,7 +11,7 @@
1111
}
1212
],
1313
"keywords": [
14-
"vite",
14+
"vite-plugin",
1515
"lwc",
1616
"lightning",
1717
"web",

packages/vite-plugin-lwc/src/hmr.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { Plugin } from "vite";
2+
3+
4+
export default function lwcHmrPlugin(): Plugin {
5+
6+
return {
7+
name: "lwc:hmr",
8+
enforce: "post",
9+
apply: "serve",
10+
transform(code, id, options) {
11+
12+
if (options?.ssr) {
13+
return;
14+
}
15+
16+
if (!id) {
17+
return;
18+
}
19+
20+
if (!code.includes("export default __lwc_component_class_internal")) {
21+
return;
22+
}
23+
24+
return code + `
25+
if (import.meta.hot) {
26+
const { swapComponent, isComponentConstructor } = await import('lwc');
27+
import.meta.hot.accept((jsModule) => {
28+
if (!jsModule) {
29+
import.meta.hot?.invalidate("new module is undefined");
30+
return;
31+
}
32+
33+
if (!isComponentConstructor(jsModule.default)) {
34+
import.meta.hot?.invalidate("not a component constructor");
35+
return;
36+
}
37+
38+
const success = swapComponent(__lwc_component_class_internal, jsModule.default);
39+
40+
if (!success) {
41+
import.meta.hot?.invalidate("swapComponent returned false")
42+
return;
43+
}
44+
})
45+
}`;
46+
},
47+
};
48+
}

packages/vite-plugin-lwc/src/index.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import patch from "./patch.ts";
2-
import lwc, { type ViteLwcOptions } from "./lwc.ts";
2+
import lwc from "./lwc.ts";
33
import alias from "./alias.ts";
44
import type { Plugin } from "vite";
5+
import hmr from "./hmr.ts";
6+
import type { ViteLwcOptions } from "./types.ts";
7+
import { normalizeOptions } from "./options.ts";
58

6-
export default (options: ViteLwcOptions = {}): Plugin[] => [
9+
export default (options: ViteLwcOptions = {}): Plugin[] => {
10+
options = normalizeOptions(options);
11+
return [
712
patch({
813
"vite:css": (p) => {
914
p.transform = undefined;
@@ -22,4 +27,6 @@ export default (options: ViteLwcOptions = {}): Plugin[] => [
2227
enforce: "post",
2328
apply: "serve",
2429
},
25-
];
30+
hmr()
31+
]
32+
};

packages/vite-plugin-lwc/src/lwc.ts

+4-19
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
import { createFilter, type FilterPattern, type Plugin, type Rollup } from "vite";
1+
import { createFilter, type Plugin, type Rollup } from "vite";
22
import lwc, { type RollupLwcOptions } from "@lwc/rollup-plugin";
33
import path from "node:path";
4-
5-
export interface ViteLwcOptions extends RollupLwcOptions {
6-
include?: FilterPattern;
7-
exclude?: FilterPattern;
8-
}
9-
10-
interface Options extends ViteLwcOptions {
11-
[key: string]: unknown;
12-
}
4+
import type { ViteLwcOptions } from "./types";
135

146
function createRollupPlugin(options: RollupLwcOptions) {
157
const plugin = lwc(options);
@@ -28,8 +20,8 @@ function createRollupPlugin(options: RollupLwcOptions) {
2820
};
2921
}
3022

31-
export default function lwcVite(rawConfig: ViteLwcOptions): Plugin {
32-
const config = createConfig(rawConfig);
23+
export default function lwcVite(config: ViteLwcOptions): Plugin {
24+
3325
const csr = createRollupPlugin(config);
3426
const ssr = createRollupPlugin({ ...config, targetSSR: true });
3527

@@ -123,13 +115,6 @@ export default function lwcVite(rawConfig: ViteLwcOptions): Plugin {
123115
};
124116
}
125117

126-
function createConfig(rawConfig: ViteLwcOptions): Options {
127-
const config = rawConfig as Options;
128-
config.rootDir ??= ".";
129-
config['defaultModules'] ??= [];
130-
return config;
131-
}
132-
133118
function getError(
134119
error: unknown,
135120
id?: string,
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { ViteLwcOptions } from "./types";
2+
3+
4+
export function normalizeOptions(rawConfig: ViteLwcOptions): ViteLwcOptions {
5+
const config = rawConfig;
6+
config.rootDir ??= ".";
7+
config.defaultModules ??= [];
8+
return config;
9+
}

packages/vite-plugin-lwc/src/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { FilterPattern } from "vite";
2+
import type { RollupLwcOptions } from "@lwc/rollup-plugin";
3+
4+
export interface ViteLwcOptions extends RollupLwcOptions {
5+
include?: FilterPattern;
6+
exclude?: FilterPattern;
7+
}

0 commit comments

Comments
 (0)