@oddsquad/vite-plugin-lit 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,20 +3,6 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  */
6
- /**
7
- * Browser helpers for referencing CSS files from shadow roots via Vite's
8
- * `?url` imports.
9
- *
10
- * A `?url` import yields a real stylesheet URL — the dev server serves the
11
- * file as CSS, and `vite build` emits it as a hashed `.css` asset. That
12
- * makes it the right base for `<link>` hrefs and `@import url()`s inside
13
- * shadow roots. The one gap is dev HMR: the imported URL string is identical
14
- * across module re-executions, so the browser would keep the stale
15
- * stylesheet. These helpers close that gap.
16
- *
17
- * This module is dependency-free and must stay safe to load in any
18
- * environment.
19
- */
20
6
  /**
21
7
  * Appends a cache-busting query to a `?url`-imported CSS file URL in dev.
22
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../../../packages/labs/vite-plugin-lit/src/lib/runtime/css.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAG1C,CAAC;AAsBF;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;;;;OASG;IACH,KAAK,EAAE,aAAa,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG,QA2BtC,CAAC"}
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../../../packages/labs/vite-plugin-lit/src/lib/runtime/css.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAE1C,CAAC;AAqBF;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;;;;OASG;IACH,KAAK,EAAE,aAAa,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG,QA2BtC,CAAC"}
@@ -17,6 +17,15 @@
17
17
  * This module is dependency-free and must stay safe to load in any
18
18
  * environment.
19
19
  */
20
+ /**
21
+ * Vite's dev flag. Accessed as a direct member expression (`import.meta.env.DEV`)
22
+ * so the bundler can statically replace it per key. Aliasing the whole object
23
+ * (`const env = import.meta.env`) instead defeats that replacement and makes
24
+ * Vite inline the ENTIRE serialized `import.meta.env` — every env var — into the
25
+ * consumer bundle. Optional chaining keeps this safe where `import.meta.env` is
26
+ * absent (non-Vite runtimes).
27
+ */
28
+ const isDev = () => import.meta.env?.DEV === true;
20
29
  /**
21
30
  * Appends a cache-busting query to a `?url`-imported CSS file URL in dev.
22
31
  *
@@ -37,8 +46,7 @@
37
46
  * ```
38
47
  */
39
48
  export const devCacheBust = (url) => {
40
- const env = import.meta.env;
41
- return env?.DEV ? `${url}?t=${Date.now()}` : url;
49
+ return isDev() ? `${url}?t=${Date.now()}` : url;
42
50
  };
43
51
  /**
44
52
  * In dev, turns a `?url`-imported CSS path into one that fetches the
@@ -53,8 +61,7 @@ export const devCacheBust = (url) => {
53
61
  * it carries `?t=…`).
54
62
  */
55
63
  const devDirect = (url) => {
56
- const env = import.meta.env;
57
- if (!env?.DEV) {
64
+ if (!isDev()) {
58
65
  return url;
59
66
  }
60
67
  return `${url}${url.includes('?') ? '&' : '?'}direct`;
@@ -1 +1 @@
1
- {"version":3,"file":"css.js","sourceRoot":"","sources":["../../../../packages/labs/vite-plugin-lit/src/lib/runtime/css.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE;IAClD,MAAM,GAAG,GAAI,MAAM,CAAC,IAAgC,CAAC,GAAG,CAAC;IACzD,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACnD,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IACxC,MAAM,GAAG,GAAI,MAAM,CAAC,IAAgC,CAAC,GAAG,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QACd,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AACxD,CAAC,CAAC;AAkCF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAY,EAAE;IAChD,MAAM,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;IAClC,qEAAqE;IACrE,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,MAAM,GAAG,CAAC,IAAY,EAAiB,EAAE;QAC7C,MAAM,KAAK,GAAG,EAAE,MAAM,CAAC;QACvB,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;aAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACrB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gBACrB,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,CAAC;IACZ,OAAO;QACL,KAAK;QACL,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;YACnB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Browser helpers for referencing CSS files from shadow roots via Vite's\n * `?url` imports.\n *\n * A `?url` import yields a real stylesheet URL — the dev server serves the\n * file as CSS, and `vite build` emits it as a hashed `.css` asset. That\n * makes it the right base for `<link>` hrefs and `@import url()`s inside\n * shadow roots. The one gap is dev HMR: the imported URL string is identical\n * across module re-executions, so the browser would keep the stale\n * stylesheet. These helpers close that gap.\n *\n * This module is dependency-free and must stay safe to load in any\n * environment.\n */\n\n/**\n * Appends a cache-busting query to a `?url`-imported CSS file URL in dev.\n *\n * Call this at *module scope* (not in `render()`, where every render would\n * refetch): each HMR re-execution then yields a fresh href and the browser\n * refetches the changed stylesheet.\n *\n * In production builds the URL is a content-hashed asset, so the input is\n * returned unchanged.\n *\n * @example\n * ```ts\n * import cssUrl from './my-element.css?url';\n * import {devCacheBust} from '@lit-labs/vite-plugin-lit/css.js';\n *\n * const href = devCacheBust(cssUrl); // module scope\n * html`<link rel=\"stylesheet\" href=\"${href}\" />`;\n * ```\n */\nexport const devCacheBust = (url: string): string => {\n const env = (import.meta as {env?: {DEV?: boolean}}).env;\n return env?.DEV ? `${url}?t=${Date.now()}` : url;\n};\n\n/**\n * In dev, turns a `?url`-imported CSS path into one that fetches the\n * *compiled CSS bytes* (`text/css`). Vite serves a `?url` CSS path as a JS\n * module (`__vite__updateStyle(…)`), so a plain `fetch().text()` returns\n * JavaScript; the `direct` query makes it return the stylesheet instead,\n * pipeline-processed the same way the build asset is. In production the URL\n * is already a real `.css` asset, so it's returned unchanged.\n *\n * Joined with `?` or `&` depending on whether the URL already carries a query\n * (a freshly started dev server yields a bare path; after an HMR cache-bust\n * it carries `?t=…`).\n */\nconst devDirect = (url: string): string => {\n const env = (import.meta as {env?: {DEV?: boolean}}).env;\n if (!env?.DEV) {\n return url;\n }\n return `${url}${url.includes('?') ? '&' : '?'}direct`;\n};\n\n/**\n * A shared `CSSStyleSheet` backed by a `?url` CSS asset, plus the callback to\n * hot-swap it in place. Returned by {@link urlSheet}.\n */\nexport interface UrlSheet {\n /**\n * The constructed stylesheet. Adopt it from any number of components\n * (`static styles = [sheet]`); an edit to the source CSS re-fetches and\n * `replaceSync()`s it, updating every shadow root that adopted it without\n * re-rendering a component or reloading the page.\n *\n * It is empty until the first fetch resolves, so expect a brief flash of\n * unstyled content on initial load — the cost of keeping the CSS as a real\n * asset rather than inlining it into the JS bundle.\n */\n sheet: CSSStyleSheet;\n /**\n * Vite HMR accept callback for the `?url` dependency. Wire it up with the\n * *same literal specifier* you imported — Vite resolves accepted deps by\n * static analysis, so the string has to appear in your module:\n *\n * ```ts\n * import.meta.hot?.accept('./utils.css?url', onHotUpdate);\n * ```\n *\n * Typed to match Vite's accept callback (`ModuleNamespace | undefined`) so\n * it drops straight in; the new module's `default` export is the updated\n * `?url` string.\n */\n onHotUpdate: (mod: Record<string, unknown> | undefined) => void;\n}\n\n/**\n * Builds a {@link UrlSheet} from a `?url`-imported CSS asset: a single\n * constructed `CSSStyleSheet`, shareable across shadow roots via\n * `adoptedStyleSheets`, that hot-swaps in place on edits — no component\n * re-render, no full-page reload.\n *\n * `?url` keeps the stylesheet as a standalone, pipeline-processed `.css` file\n * in the build output (unlike `?inline`/`?raw`, which inline it into the JS\n * chunk). The file is read into the sheet at runtime via `fetch()`, with the\n * dev/build path difference handled internally.\n *\n * @example\n * ```ts\n * import {urlSheet} from '@lit-labs/vite-plugin-lit/css.js';\n * import sheetUrl from './utils.css?url';\n *\n * const {sheet, onHotUpdate} = urlSheet(sheetUrl);\n * export default sheet; // `static styles = [sheet]` in components\n *\n * import.meta.hot?.accept('./utils.css?url', onHotUpdate);\n * ```\n */\nexport const urlSheet = (url: string): UrlSheet => {\n const sheet = new CSSStyleSheet();\n // Guards against out-of-order fetch resolution: two rapid edits fire\n // overlapping fetches, and a slower earlier one must not land after (and\n // clobber) a newer one. Only the most recently issued request applies.\n let latest = 0;\n const update = (next: string): Promise<void> => {\n const token = ++latest;\n return fetch(devDirect(next))\n .then((r) => r.text())\n .then((css) => {\n if (token === latest) {\n sheet.replaceSync(css);\n }\n })\n .catch(() => {});\n };\n update(url);\n return {\n sheet,\n onHotUpdate: (mod) => {\n const next = mod?.['default'];\n if (typeof next === 'string') {\n update(next);\n }\n },\n };\n};\n"]}
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../../../../packages/labs/vite-plugin-lit/src/lib/runtime/css.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,GAAY,EAAE,CACzB,MAAM,CAAC,IAAgC,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE;IAClD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAClD,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IACxC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QACb,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AACxD,CAAC,CAAC;AAkCF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAY,EAAE;IAChD,MAAM,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;IAClC,qEAAqE;IACrE,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,MAAM,GAAG,CAAC,IAAY,EAAiB,EAAE;QAC7C,MAAM,KAAK,GAAG,EAAE,MAAM,CAAC;QACvB,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;aAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACrB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gBACrB,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,CAAC;IACZ,OAAO;QACL,KAAK;QACL,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;YACnB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Browser helpers for referencing CSS files from shadow roots via Vite's\n * `?url` imports.\n *\n * A `?url` import yields a real stylesheet URL — the dev server serves the\n * file as CSS, and `vite build` emits it as a hashed `.css` asset. That\n * makes it the right base for `<link>` hrefs and `@import url()`s inside\n * shadow roots. The one gap is dev HMR: the imported URL string is identical\n * across module re-executions, so the browser would keep the stale\n * stylesheet. These helpers close that gap.\n *\n * This module is dependency-free and must stay safe to load in any\n * environment.\n */\n\n/**\n * Vite's dev flag. Accessed as a direct member expression (`import.meta.env.DEV`)\n * so the bundler can statically replace it per key. Aliasing the whole object\n * (`const env = import.meta.env`) instead defeats that replacement and makes\n * Vite inline the ENTIRE serialized `import.meta.env` — every env var — into the\n * consumer bundle. Optional chaining keeps this safe where `import.meta.env` is\n * absent (non-Vite runtimes).\n */\nconst isDev = (): boolean =>\n (import.meta as {env?: {DEV?: boolean}}).env?.DEV === true;\n\n/**\n * Appends a cache-busting query to a `?url`-imported CSS file URL in dev.\n *\n * Call this at *module scope* (not in `render()`, where every render would\n * refetch): each HMR re-execution then yields a fresh href and the browser\n * refetches the changed stylesheet.\n *\n * In production builds the URL is a content-hashed asset, so the input is\n * returned unchanged.\n *\n * @example\n * ```ts\n * import cssUrl from './my-element.css?url';\n * import {devCacheBust} from '@lit-labs/vite-plugin-lit/css.js';\n *\n * const href = devCacheBust(cssUrl); // module scope\n * html`<link rel=\"stylesheet\" href=\"${href}\" />`;\n * ```\n */\nexport const devCacheBust = (url: string): string => {\n return isDev() ? `${url}?t=${Date.now()}` : url;\n};\n\n/**\n * In dev, turns a `?url`-imported CSS path into one that fetches the\n * *compiled CSS bytes* (`text/css`). Vite serves a `?url` CSS path as a JS\n * module (`__vite__updateStyle(…)`), so a plain `fetch().text()` returns\n * JavaScript; the `direct` query makes it return the stylesheet instead,\n * pipeline-processed the same way the build asset is. In production the URL\n * is already a real `.css` asset, so it's returned unchanged.\n *\n * Joined with `?` or `&` depending on whether the URL already carries a query\n * (a freshly started dev server yields a bare path; after an HMR cache-bust\n * it carries `?t=…`).\n */\nconst devDirect = (url: string): string => {\n if (!isDev()) {\n return url;\n }\n return `${url}${url.includes('?') ? '&' : '?'}direct`;\n};\n\n/**\n * A shared `CSSStyleSheet` backed by a `?url` CSS asset, plus the callback to\n * hot-swap it in place. Returned by {@link urlSheet}.\n */\nexport interface UrlSheet {\n /**\n * The constructed stylesheet. Adopt it from any number of components\n * (`static styles = [sheet]`); an edit to the source CSS re-fetches and\n * `replaceSync()`s it, updating every shadow root that adopted it without\n * re-rendering a component or reloading the page.\n *\n * It is empty until the first fetch resolves, so expect a brief flash of\n * unstyled content on initial load — the cost of keeping the CSS as a real\n * asset rather than inlining it into the JS bundle.\n */\n sheet: CSSStyleSheet;\n /**\n * Vite HMR accept callback for the `?url` dependency. Wire it up with the\n * *same literal specifier* you imported — Vite resolves accepted deps by\n * static analysis, so the string has to appear in your module:\n *\n * ```ts\n * import.meta.hot?.accept('./utils.css?url', onHotUpdate);\n * ```\n *\n * Typed to match Vite's accept callback (`ModuleNamespace | undefined`) so\n * it drops straight in; the new module's `default` export is the updated\n * `?url` string.\n */\n onHotUpdate: (mod: Record<string, unknown> | undefined) => void;\n}\n\n/**\n * Builds a {@link UrlSheet} from a `?url`-imported CSS asset: a single\n * constructed `CSSStyleSheet`, shareable across shadow roots via\n * `adoptedStyleSheets`, that hot-swaps in place on edits — no component\n * re-render, no full-page reload.\n *\n * `?url` keeps the stylesheet as a standalone, pipeline-processed `.css` file\n * in the build output (unlike `?inline`/`?raw`, which inline it into the JS\n * chunk). The file is read into the sheet at runtime via `fetch()`, with the\n * dev/build path difference handled internally.\n *\n * @example\n * ```ts\n * import {urlSheet} from '@lit-labs/vite-plugin-lit/css.js';\n * import sheetUrl from './utils.css?url';\n *\n * const {sheet, onHotUpdate} = urlSheet(sheetUrl);\n * export default sheet; // `static styles = [sheet]` in components\n *\n * import.meta.hot?.accept('./utils.css?url', onHotUpdate);\n * ```\n */\nexport const urlSheet = (url: string): UrlSheet => {\n const sheet = new CSSStyleSheet();\n // Guards against out-of-order fetch resolution: two rapid edits fire\n // overlapping fetches, and a slower earlier one must not land after (and\n // clobber) a newer one. Only the most recently issued request applies.\n let latest = 0;\n const update = (next: string): Promise<void> => {\n const token = ++latest;\n return fetch(devDirect(next))\n .then((r) => r.text())\n .then((css) => {\n if (token === latest) {\n sheet.replaceSync(css);\n }\n })\n .catch(() => {});\n };\n update(url);\n return {\n sheet,\n onHotUpdate: (mod) => {\n const next = mod?.['default'];\n if (typeof next === 'string') {\n update(next);\n }\n },\n };\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddsquad/vite-plugin-lit",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Vite plugin providing true HMR for Lit components, plus CSS helpers and a DevTools panel",
5
5
  "license": "BSD-3-Clause",
6
6
  "author": "Oddsquad (based on @lit-labs/vite-hmr by Google LLC)",