@oddsquad/vite-plugin-lit 0.2.3 → 0.4.0
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.
- package/CHANGELOG.md +112 -0
- package/LICENSE +28 -0
- package/README.md +157 -0
- package/bin.mjs +154 -0
- package/client.d.ts +61 -0
- package/dist/client/assets/browser-agent-rpc-BXhoSh1z-CdtPhBL-.js +69 -0
- package/dist/client/assets/browser-agent-rpc-BXhoSh1z-CdtPhBL-.js.map +1 -0
- package/dist/client/assets/flow-DK8vmxvN.js +745 -0
- package/dist/client/assets/flow-DK8vmxvN.js.map +1 -0
- package/dist/client/assets/index-DVe6M4HV.js +10614 -0
- package/dist/client/assets/index-DVe6M4HV.js.map +1 -0
- package/{panel → dist/client}/index.html +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/index.js.map +1 -1
- package/lib/color-scheme.d.ts.map +1 -1
- package/lib/color-scheme.js +17 -21
- package/lib/color-scheme.js.map +1 -1
- package/lib/devframe/definition.d.ts +45 -0
- package/lib/devframe/definition.d.ts.map +1 -0
- package/lib/devframe/definition.js +547 -0
- package/lib/devframe/definition.js.map +1 -0
- package/lib/devframe/icon.d.ts +8 -0
- package/lib/devframe/icon.d.ts.map +1 -0
- package/lib/devframe/icon.js +21 -0
- package/lib/devframe/icon.js.map +1 -0
- package/lib/devframe/paths.d.ts +12 -0
- package/lib/devframe/paths.d.ts.map +1 -0
- package/lib/devframe/paths.js +38 -0
- package/lib/devframe/paths.js.map +1 -0
- package/lib/devframe/protocol.d.ts +218 -0
- package/lib/devframe/protocol.d.ts.map +1 -0
- package/lib/devframe/protocol.js +77 -0
- package/lib/devframe/protocol.js.map +1 -0
- package/lib/devframe/source.d.ts +49 -0
- package/lib/devframe/source.d.ts.map +1 -0
- package/lib/devframe/source.js +23 -0
- package/lib/devframe/source.js.map +1 -0
- package/lib/devframe/vite.d.ts +116 -0
- package/lib/devframe/vite.d.ts.map +1 -0
- package/lib/devframe/vite.js +292 -0
- package/lib/devframe/vite.js.map +1 -0
- package/lib/http.d.ts +29 -0
- package/lib/http.d.ts.map +1 -0
- package/lib/http.js +35 -0
- package/lib/http.js.map +1 -0
- package/lib/icons.d.ts +2 -0
- package/lib/icons.d.ts.map +1 -1
- package/lib/icons.js +10 -4
- package/lib/icons.js.map +1 -1
- package/lib/options.d.ts +131 -0
- package/lib/options.d.ts.map +1 -0
- package/lib/options.js +128 -0
- package/lib/options.js.map +1 -0
- package/lib/plugin.d.ts +6 -137
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +280 -677
- package/lib/plugin.js.map +1 -1
- package/lib/plugins/css-literals.d.ts +15 -0
- package/lib/plugins/css-literals.d.ts.map +1 -0
- package/lib/plugins/css-literals.js +154 -0
- package/lib/plugins/css-literals.js.map +1 -0
- package/lib/plugins/css-queries.d.ts +20 -0
- package/lib/plugins/css-queries.d.ts.map +1 -0
- package/lib/plugins/css-queries.js +139 -0
- package/lib/plugins/css-queries.js.map +1 -0
- package/lib/plugins/open-in-editor.d.ts +16 -0
- package/lib/plugins/open-in-editor.d.ts.map +1 -0
- package/lib/plugins/open-in-editor.js +91 -0
- package/lib/plugins/open-in-editor.js.map +1 -0
- package/lib/plugins/shared.d.ts +13 -0
- package/lib/plugins/shared.d.ts.map +1 -0
- package/lib/plugins/shared.js +23 -0
- package/lib/plugins/shared.js.map +1 -0
- package/lib/plugins/timeline-virtual.d.ts +19 -0
- package/lib/plugins/timeline-virtual.d.ts.map +1 -0
- package/lib/plugins/timeline-virtual.js +53 -0
- package/lib/plugins/timeline-virtual.js.map +1 -0
- package/lib/runtime/css.d.ts +2 -2
- package/lib/runtime/css.d.ts.map +1 -1
- package/lib/runtime/css.js +41 -34
- package/lib/runtime/css.js.map +1 -1
- package/lib/runtime/edge-panel.d.ts.map +1 -1
- package/lib/runtime/edge-panel.js +82 -91
- package/lib/runtime/edge-panel.js.map +1 -1
- package/lib/runtime/fonts.d.ts.map +1 -1
- package/lib/runtime/fonts.js +1 -1
- package/lib/runtime/fonts.js.map +1 -1
- package/lib/runtime/indicator.d.ts.map +1 -1
- package/lib/runtime/indicator.js +71 -74
- package/lib/runtime/indicator.js.map +1 -1
- package/lib/runtime/inspector/collect.d.ts.map +1 -1
- package/lib/runtime/inspector/collect.js +83 -90
- package/lib/runtime/inspector/collect.js.map +1 -1
- package/lib/runtime/inspector/highlight.d.ts +16 -0
- package/lib/runtime/inspector/highlight.d.ts.map +1 -0
- package/lib/runtime/inspector/highlight.js +66 -0
- package/lib/runtime/inspector/highlight.js.map +1 -0
- package/lib/runtime/inspector/install.d.ts.map +1 -1
- package/lib/runtime/inspector/install.js +230 -205
- package/lib/runtime/inspector/install.js.map +1 -1
- package/lib/runtime/inspector/serialize.d.ts.map +1 -1
- package/lib/runtime/inspector/serialize.js +86 -107
- package/lib/runtime/inspector/serialize.js.map +1 -1
- package/lib/runtime/intern.d.ts.map +1 -1
- package/lib/runtime/intern.js +31 -29
- package/lib/runtime/intern.js.map +1 -1
- package/lib/runtime/overrides.d.ts.map +1 -1
- package/lib/runtime/overrides.js +14 -13
- package/lib/runtime/overrides.js.map +1 -1
- package/lib/runtime/patch.d.ts +8 -0
- package/lib/runtime/patch.d.ts.map +1 -1
- package/lib/runtime/patch.js +321 -282
- package/lib/runtime/patch.js.map +1 -1
- package/lib/runtime/source-meta.d.ts.map +1 -1
- package/lib/runtime/source-meta.js +1 -1
- package/lib/runtime/source-meta.js.map +1 -1
- package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
- package/lib/runtime/source-overlay/editors.js +27 -27
- package/lib/runtime/source-overlay/editors.js.map +1 -1
- package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
- package/lib/runtime/source-overlay/mask-path.js +15 -15
- package/lib/runtime/source-overlay/mask-path.js.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.js +359 -355
- package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
- package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
- package/lib/runtime/source-overlay/source-host.js +64 -71
- package/lib/runtime/source-overlay/source-host.js.map +1 -1
- package/lib/runtime/source-overlay/template.d.ts.map +1 -1
- package/lib/runtime/source-overlay/template.js +3 -3
- package/lib/runtime/source-overlay/template.js.map +1 -1
- package/lib/runtime/source-overlay.d.ts.map +1 -1
- package/lib/runtime/source-overlay.js +5 -2
- package/lib/runtime/source-overlay.js.map +1 -1
- package/lib/runtime/timeline/clock.d.ts.map +1 -1
- package/lib/runtime/timeline/clock.js +2 -2
- package/lib/runtime/timeline/clock.js.map +1 -1
- package/lib/runtime/timeline/flash.d.ts +39 -0
- package/lib/runtime/timeline/flash.d.ts.map +1 -0
- package/lib/runtime/timeline/flash.js +169 -0
- package/lib/runtime/timeline/flash.js.map +1 -0
- package/lib/runtime/timeline/identity.d.ts.map +1 -1
- package/lib/runtime/timeline/identity.js +27 -27
- package/lib/runtime/timeline/identity.js.map +1 -1
- package/lib/runtime/timeline/input.d.ts.map +1 -1
- package/lib/runtime/timeline/input.js +54 -67
- package/lib/runtime/timeline/input.js.map +1 -1
- package/lib/runtime/timeline/install.d.ts.map +1 -1
- package/lib/runtime/timeline/install.js +47 -33
- package/lib/runtime/timeline/install.js.map +1 -1
- package/lib/runtime/timeline/lifecycle.d.ts +8 -0
- package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
- package/lib/runtime/timeline/lifecycle.js +149 -133
- package/lib/runtime/timeline/lifecycle.js.map +1 -1
- package/lib/runtime/timeline/public-api.d.ts +2 -2
- package/lib/runtime/timeline/public-api.d.ts.map +1 -1
- package/lib/runtime/timeline/public-api.js +11 -11
- package/lib/runtime/timeline/public-api.js.map +1 -1
- package/lib/runtime/timeline/render.d.ts +15 -6
- package/lib/runtime/timeline/render.d.ts.map +1 -1
- package/lib/runtime/timeline/render.js +212 -78
- package/lib/runtime/timeline/render.js.map +1 -1
- package/lib/runtime/timeline/transport.d.ts.map +1 -1
- package/lib/runtime/timeline/transport.js +39 -43
- package/lib/runtime/timeline/transport.js.map +1 -1
- package/lib/segmented-tabs.d.ts +3 -1
- package/lib/segmented-tabs.d.ts.map +1 -1
- package/lib/segmented-tabs.js +136 -107
- package/lib/segmented-tabs.js.map +1 -1
- package/lib/snapshot.d.ts +28 -0
- package/lib/snapshot.d.ts.map +1 -0
- package/lib/snapshot.js +57 -0
- package/lib/snapshot.js.map +1 -0
- package/lib/source-meta.d.ts.map +1 -1
- package/lib/source-meta.js +176 -162
- package/lib/source-meta.js.map +1 -1
- package/lib/timeline/derive.d.ts +152 -0
- package/lib/timeline/derive.d.ts.map +1 -0
- package/lib/timeline/derive.js +242 -0
- package/lib/timeline/derive.js.map +1 -0
- package/lib/tokens.d.ts.map +1 -1
- package/lib/tokens.js +17 -18
- package/lib/tokens.js.map +1 -1
- package/lib/transform.d.ts.map +1 -1
- package/lib/transform.js +62 -57
- package/lib/transform.js.map +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/wrap-table.d.ts.map +1 -1
- package/lib/wrap-table.js +19 -17
- package/lib/wrap-table.js.map +1 -1
- package/package.json +80 -13
- package/types/hmr-incompatibility.d.ts +59 -0
- package/types/hmr-incompatibility.d.ts.map +1 -0
- package/types/hmr-incompatibility.js +30 -0
- package/types/hmr-incompatibility.js.map +1 -0
- package/types/in-page.d.ts +49 -0
- package/types/in-page.d.ts.map +1 -0
- package/types/in-page.js +33 -0
- package/types/in-page.js.map +1 -0
- package/types/inspector.d.ts.map +1 -1
- package/types/inspector.js.map +1 -1
- package/types/snapshot.d.ts +44 -0
- package/types/snapshot.d.ts.map +1 -0
- package/types/snapshot.js +7 -0
- package/types/snapshot.js.map +1 -0
- package/types/timeline.d.ts +23 -1
- package/types/timeline.d.ts.map +1 -1
- package/types/timeline.js +2 -0
- package/types/timeline.js.map +1 -1
- package/lib/timeline-plugin.d.ts +0 -72
- package/lib/timeline-plugin.d.ts.map +0 -1
- package/lib/timeline-plugin.js +0 -376
- package/lib/timeline-plugin.js.map +0 -1
- package/panel/components-view.d.ts +0 -60
- package/panel/components-view.d.ts.map +0 -1
- package/panel/components-view.js +0 -587
- package/panel/components-view.js.map +0 -1
- package/panel/devtools-settings.d.ts +0 -41
- package/panel/devtools-settings.d.ts.map +0 -1
- package/panel/devtools-settings.js +0 -463
- package/panel/devtools-settings.js.map +0 -1
- package/panel/lit-devtools-panel.d.ts +0 -37
- package/panel/lit-devtools-panel.d.ts.map +0 -1
- package/panel/lit-devtools-panel.js +0 -185
- package/panel/lit-devtools-panel.js.map +0 -1
- package/panel/timeline-event-list.d.ts +0 -43
- package/panel/timeline-event-list.d.ts.map +0 -1
- package/panel/timeline-event-list.js +0 -416
- package/panel/timeline-event-list.js.map +0 -1
- package/panel/timeline-layers.d.ts +0 -25
- package/panel/timeline-layers.d.ts.map +0 -1
- package/panel/timeline-layers.js +0 -96
- package/panel/timeline-layers.js.map +0 -1
- package/panel/timeline-view.d.ts +0 -38
- package/panel/timeline-view.d.ts.map +0 -1
- package/panel/timeline-view.js +0 -234
- package/panel/timeline-view.js.map +0 -1
package/lib/plugin.js
CHANGED
|
@@ -3,688 +3,291 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { loadEnv } from 'vite';
|
|
6
|
+
import {resolve as resolvePath} from 'node:path';
|
|
7
|
+
import {loadEnv} from 'vite';
|
|
10
8
|
import MagicString from 'magic-string';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/** Parse a numeric env string; `undefined` when unset/non-numeric. */
|
|
30
|
-
const envNum = (v) => {
|
|
31
|
-
if (v === undefined || v === '')
|
|
32
|
-
return undefined;
|
|
33
|
-
const n = Number(v);
|
|
34
|
-
return Number.isNaN(n) ? undefined : n;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Parse a string against a closed set of values; `undefined` (with a warning)
|
|
38
|
-
* when set to something outside it, so a typo falls back to the default
|
|
39
|
-
* instead of silently disabling a feature.
|
|
40
|
-
*/
|
|
41
|
-
const envEnum = (v, allowed, source) => {
|
|
42
|
-
if (v === undefined || v === '')
|
|
43
|
-
return undefined;
|
|
44
|
-
if (allowed.includes(v))
|
|
45
|
-
return v;
|
|
46
|
-
console.warn(`[lit-plugin] ignoring ${source}=${JSON.stringify(v)}; expected one of ` +
|
|
47
|
-
allowed.map((a) => JSON.stringify(a)).join(', '));
|
|
48
|
-
return undefined;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Merge explicit options over env vars over defaults (in that precedence) into
|
|
52
|
-
* the flat shape the plugin hooks consume.
|
|
53
|
-
*/
|
|
54
|
-
export const resolveOptions = (options, env) => {
|
|
55
|
-
const hmr = options.hmr;
|
|
56
|
-
const hmrObj = typeof hmr === 'object' ? hmr : undefined;
|
|
57
|
-
const hmrEnabled = (typeof hmr === 'boolean' ? hmr : hmrObj?.enabled) ??
|
|
58
|
-
envBool(env[`${ENV_PREFIX}_HMR`]) ??
|
|
59
|
-
true;
|
|
60
|
-
const reconnect = hmrObj?.reconnect ?? envBool(env[`${ENV_PREFIX}_HMR_RECONNECT`]) ?? false;
|
|
61
|
-
const onIncompatible = hmrObj?.onIncompatible ??
|
|
62
|
-
env[`${ENV_PREFIX}_HMR_ON_INCOMPATIBLE`] ??
|
|
63
|
-
'reload';
|
|
64
|
-
const ind = hmrObj?.indicator;
|
|
65
|
-
const indObj = typeof ind === 'object' ? ind : undefined;
|
|
66
|
-
const indEnabled = (typeof ind === 'boolean' ? ind : indObj?.enabled) ??
|
|
67
|
-
envBool(env[`${ENV_PREFIX}_HMR_INDICATOR`]) ??
|
|
68
|
-
true;
|
|
69
|
-
const indCount = indObj?.count ?? envBool(env[`${ENV_PREFIX}_HMR_INDICATOR_COUNT`]) ?? false;
|
|
70
|
-
// The indicator is meaningless without HMR, so it follows the master toggle.
|
|
71
|
-
const indicator = hmrEnabled && indEnabled ? { count: indCount } : false;
|
|
72
|
-
const so = options.sourceOverlay;
|
|
73
|
-
const soExplicit = typeof so === 'boolean' ? so : so === undefined ? undefined : true;
|
|
74
|
-
const soEnabled = soExplicit ?? envBool(env[`${ENV_PREFIX}_SOURCE_OVERLAY`]) ?? false;
|
|
75
|
-
let sourceOverlay = false;
|
|
76
|
-
if (soEnabled) {
|
|
77
|
-
const base = typeof so === 'object' ? { ...so } : {};
|
|
78
|
-
base.key ??= env[`${ENV_PREFIX}_SOURCE_OVERLAY_KEY`] || undefined;
|
|
79
|
-
base.editor ??= env[`${ENV_PREFIX}_SOURCE_OVERLAY_EDITOR`] || undefined;
|
|
80
|
-
base.throttleMs ??= envNum(env[`${ENV_PREFIX}_SOURCE_OVERLAY_THROTTLE_MS`]);
|
|
81
|
-
sourceOverlay = base;
|
|
82
|
-
}
|
|
83
|
-
const timeline = options.timeline ?? envBool(env[`${ENV_PREFIX}_TIMELINE`]) ?? false;
|
|
84
|
-
const cssSheetBuild = envEnum(options.cssSheetBuild, CSS_SHEET_BUILD_MODES, 'cssSheetBuild') ??
|
|
85
|
-
envEnum(env[`${ENV_PREFIX}_CSS_SHEET_BUILD`], CSS_SHEET_BUILD_MODES, `${ENV_PREFIX}_CSS_SHEET_BUILD`) ??
|
|
86
|
-
'auto';
|
|
87
|
-
return {
|
|
88
|
-
hmrEnabled,
|
|
89
|
-
reconnect,
|
|
90
|
-
onIncompatible,
|
|
91
|
-
indicator,
|
|
92
|
-
sourceOverlay,
|
|
93
|
-
timeline,
|
|
94
|
-
cssSheetBuild,
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* Flattens resolved options into the JSON-serializable shape the panel's
|
|
99
|
-
* Settings tab consumes (callback options like `exclude`/`onSelect` dropped;
|
|
100
|
-
* a custom editor object reported as `"custom"`). Default key/editor/throttle
|
|
101
|
-
* are applied here so the panel shows the effective values the runtime uses.
|
|
102
|
-
*/
|
|
103
|
-
const toFeatureSettings = (r) => {
|
|
104
|
-
const so = r.sourceOverlay;
|
|
105
|
-
const editor = so === false ? undefined : so.editor;
|
|
106
|
-
return {
|
|
107
|
-
hmr: {
|
|
108
|
-
enabled: r.hmrEnabled,
|
|
109
|
-
reconnect: r.reconnect,
|
|
110
|
-
onIncompatible: r.onIncompatible,
|
|
111
|
-
indicatorEnabled: r.indicator !== false,
|
|
112
|
-
indicatorCount: r.indicator !== false && r.indicator.count,
|
|
113
|
-
},
|
|
114
|
-
sourceOverlay: {
|
|
115
|
-
enabled: so !== false,
|
|
116
|
-
key: (so === false ? undefined : so.key) ?? 's',
|
|
117
|
-
editor: typeof editor === 'string' ? editor : editor ? 'custom' : 'vscode',
|
|
118
|
-
throttleMs: (so === false ? undefined : so.throttleMs) ?? 50,
|
|
119
|
-
},
|
|
120
|
-
timeline: r.timeline,
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
/**
|
|
124
|
-
* Resolves a runtime module to an absolute fs path (served via `/@fs/`), so
|
|
125
|
-
* the plugin works from any served root. Falls back from the built `.js` to
|
|
126
|
-
* the `.ts` source when running un-built (e.g. under vitest).
|
|
127
|
-
*/
|
|
128
|
-
const resolveRuntimeModule = (name) => {
|
|
129
|
-
for (const ext of ['js', 'ts']) {
|
|
130
|
-
const url = new URL(`./runtime/${name}.${ext}`, import.meta.url);
|
|
131
|
-
if (existsSync(url)) {
|
|
132
|
-
return fileURLToPath(url).replace(/\\/g, '/');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
throw new Error(`[lit-plugin] runtime module not found: ${name}`);
|
|
136
|
-
};
|
|
137
|
-
const JS_FILE_RE = /\.[cm]?[jt]sx?$/;
|
|
138
|
-
const OPEN_IN_EDITOR_PATH = '/__lit-open-in-editor';
|
|
139
|
-
/** Reject requests whose `Origin` is a different host than the dev server, so
|
|
140
|
-
* a page the developer happens to visit can't drive these local-only
|
|
141
|
-
* endpoints. Same-origin requests (no `Origin`, or matching `Host`) pass. */
|
|
142
|
-
const isSameOrigin = (headers) => {
|
|
143
|
-
const { origin, host } = headers;
|
|
144
|
-
if (origin === undefined || origin === 'null')
|
|
145
|
-
return true;
|
|
146
|
-
try {
|
|
147
|
-
return new URL(origin).host === host;
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
export const createOpenInEditorMiddleware = (allowedRoots) => {
|
|
154
|
-
// First entry is the primary root: relative `file` params resolve against
|
|
155
|
-
// it. Every entry grants open access to files beneath it.
|
|
156
|
-
const roots = allowedRoots.map((r) => resolvePath(r));
|
|
157
|
-
return (req, res, next) => {
|
|
158
|
-
if (req.url === undefined) {
|
|
159
|
-
next();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (!isSameOrigin(req.headers ?? {})) {
|
|
163
|
-
res.statusCode = 403;
|
|
164
|
-
res.end('forbidden');
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const query = req.url.includes('?')
|
|
168
|
-
? req.url.slice(req.url.indexOf('?') + 1)
|
|
169
|
-
: '';
|
|
170
|
-
const params = new URLSearchParams(query);
|
|
171
|
-
const file = params.get('file');
|
|
172
|
-
if (file === null) {
|
|
173
|
-
res.statusCode = 400;
|
|
174
|
-
res.end('missing file parameter');
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
// Confine the open to the allowed roots: resolve the requested path and
|
|
178
|
-
// reject anything that escapes all of them (path traversal, absolute
|
|
179
|
-
// paths to arbitrary files). `launch-editor` spawns the user's editor on
|
|
180
|
-
// this path, so an unvalidated `file` is a local-file-open /
|
|
181
|
-
// arg-injection vector.
|
|
182
|
-
const resolved = resolvePath(roots[0] ?? process.cwd(), file);
|
|
183
|
-
const allowed = roots.some((root) => resolved === root || resolved.startsWith(root + sep));
|
|
184
|
-
if (!allowed) {
|
|
185
|
-
res.statusCode = 403;
|
|
186
|
-
res.end('file outside allowed roots');
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
if (!existsSync(resolved)) {
|
|
190
|
-
res.statusCode = 404;
|
|
191
|
-
res.end('file not found');
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
// Coerce to integers so a crafted `line`/`column` can't smuggle extra
|
|
195
|
-
// shell-visible content through the `file:line:column` ref.
|
|
196
|
-
const line = String(Math.max(1, Number.parseInt(params.get('line') ?? '1', 10) || 1));
|
|
197
|
-
const column = String(Math.max(1, Number.parseInt(params.get('column') ?? '1', 10) || 1));
|
|
198
|
-
const fileRef = `${resolved}:${line}:${column}`;
|
|
199
|
-
import('launch-editor')
|
|
200
|
-
.then((mod) => {
|
|
201
|
-
const launch = (mod.default ?? mod);
|
|
202
|
-
// `launch-editor` invokes the callback only on failure — synchronously
|
|
203
|
-
// when it can't guess an editor, later if the spawn errors. Reply `ok`
|
|
204
|
-
// right after launching; the guard keeps a sync failure's 500 first
|
|
205
|
-
// and drops a late async failure (the response is long gone).
|
|
206
|
-
let finished = false;
|
|
207
|
-
const finish = (statusCode, msg) => {
|
|
208
|
-
if (finished)
|
|
209
|
-
return;
|
|
210
|
-
finished = true;
|
|
211
|
-
res.statusCode = statusCode;
|
|
212
|
-
res.end(msg);
|
|
213
|
-
};
|
|
214
|
-
launch(fileRef, (_fileName, errorMessage) => {
|
|
215
|
-
if (errorMessage !== null) {
|
|
216
|
-
finish(500, errorMessage);
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
finish(200, 'ok');
|
|
220
|
-
})
|
|
221
|
-
.catch(next);
|
|
222
|
-
};
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* `import href from './x.css?hmr-url'` — `?url` semantics with working HMR.
|
|
226
|
-
* The string is a real stylesheet URL (dev-served CSS file; hashed `.css`
|
|
227
|
-
* asset on build) for shadow-root `<link>` hrefs and `@import url()`s. In
|
|
228
|
-
* dev, each HMR re-execution yields a freshly cache-busted href, so the
|
|
229
|
-
* browser refetches the changed stylesheet; in build the `?url` asset URL
|
|
230
|
-
* passes through unchanged.
|
|
231
|
-
*/
|
|
232
|
-
const CSS_URL_QUERY_RE = /^([^?]+\.css)\?(?:[^&]*&)*hmr-url(?:&.*)?$/;
|
|
233
|
-
const CSS_URL_VIRTUAL_PREFIX = '\0lit-plugin:hmr-url:';
|
|
234
|
-
/**
|
|
235
|
-
* `import sheet from './x.css?css-sheet'` — a constructed, shareable
|
|
236
|
-
* `CSSStyleSheet` backed by the `.css` asset that hot-swaps in place. Adopt it
|
|
237
|
-
* from any number of components (`static styles = [sheet]`); a source edit
|
|
238
|
-
* re-fetches and `replaceSync()`s it, updating every shadow root that adopted
|
|
239
|
-
* it without re-rendering a component or reloading the page.
|
|
240
|
-
*
|
|
241
|
-
* This is the `urlSheet()` helper plus its irreducible HMR wiring, lifted into
|
|
242
|
-
* a plugin-generated module: the `import.meta.hot.accept` lives here (where
|
|
243
|
-
* Vite's static analysis sees the literal specifier), so callers write a bare
|
|
244
|
-
* import and never touch `import.meta.hot` themselves.
|
|
245
|
-
*
|
|
246
|
-
* Under `vite build` the generated module can instead inline the css text (see
|
|
247
|
-
* `cssSheetBuild`) — a library's consumers bundle its JS only, so a
|
|
248
|
-
* fetch-backed sheet would 404 on the `.css` asset that never reached their
|
|
249
|
-
* build.
|
|
250
|
-
*/
|
|
251
|
-
const CSS_SHEET_QUERY_RE = /^([^?]+\.css)\?(?:[^&]*&)*css-sheet(?:&.*)?$/;
|
|
252
|
-
const CSS_SHEET_VIRTUAL_PREFIX = '\0lit-plugin:css-sheet:';
|
|
253
|
-
// The virtual id must not end in `.css`, or Vite's CSS plugins (which match
|
|
254
|
-
// the id's extension regardless of `\0`) would compile the wrapper as CSS.
|
|
255
|
-
const CSS_VIRTUAL_SUFFIX = '.js';
|
|
256
|
-
/**
|
|
257
|
-
* Import-query support, served in dev and build alike (source code using
|
|
258
|
-
* `?hmr-url`/`?css-sheet` must keep working under `vite build`, where the HMR
|
|
259
|
-
* plugin doesn't apply). Exported for the baseline e2e run, which needs the
|
|
260
|
-
* queries working without the HMR plugin.
|
|
261
|
-
*
|
|
262
|
-
* `getCssSheetBuild` is a getter, not a value: `litPlugin()` re-resolves its
|
|
263
|
-
* options against the loaded env in a `config` hook, which runs after the
|
|
264
|
-
* plugin array is built. Standalone (no getter) it behaves like the `'auto'`
|
|
265
|
-
* default.
|
|
266
|
-
*/
|
|
267
|
-
export const litCssQueries = (getCssSheetBuild = () => 'auto') => {
|
|
268
|
-
let isBuild = false;
|
|
269
|
-
let isLib = false;
|
|
270
|
-
return {
|
|
271
|
-
name: 'lit-css-query',
|
|
272
|
-
// Vite's core resolver claims `./x.css?hmr-url` for the CSS pipeline
|
|
273
|
-
// before normal plugins get a look, so resolve ahead of it.
|
|
274
|
-
enforce: 'pre',
|
|
275
|
-
configResolved(config) {
|
|
276
|
-
isBuild = config.command === 'build';
|
|
277
|
-
isLib = config.build.lib !== false && config.build.lib !== undefined;
|
|
278
|
-
},
|
|
279
|
-
async resolveId(id, importer) {
|
|
280
|
-
const prefix = CSS_URL_QUERY_RE.test(id)
|
|
281
|
-
? CSS_URL_VIRTUAL_PREFIX
|
|
282
|
-
: CSS_SHEET_QUERY_RE.test(id)
|
|
283
|
-
? CSS_SHEET_VIRTUAL_PREFIX
|
|
284
|
-
: null;
|
|
285
|
-
if (prefix === null) {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
const file = id.slice(0, id.indexOf('?'));
|
|
289
|
-
const resolved = await this.resolve(file, importer);
|
|
290
|
-
if (resolved === null) {
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
return prefix + resolved.id + CSS_VIRTUAL_SUFFIX;
|
|
294
|
-
},
|
|
295
|
-
load(id) {
|
|
296
|
-
const helperPath = resolveRuntimeModule('css');
|
|
297
|
-
if (id.startsWith(CSS_URL_VIRTUAL_PREFIX)) {
|
|
298
|
-
const file = id.slice(CSS_URL_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length);
|
|
299
|
-
return {
|
|
300
|
-
code: `import url from ${JSON.stringify(`${file}?url`)};\n` +
|
|
301
|
-
`import {devCacheBust} from ${JSON.stringify(helperPath)};\n` +
|
|
302
|
-
`export default devCacheBust(url);\n`,
|
|
303
|
-
moduleType: 'js',
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
if (id.startsWith(CSS_SHEET_VIRTUAL_PREFIX)) {
|
|
307
|
-
const file = id.slice(CSS_SHEET_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length);
|
|
308
|
-
const mode = getCssSheetBuild();
|
|
309
|
-
const inlineQuery = !isBuild || mode === 'url' || (mode === 'auto' && !isLib)
|
|
310
|
-
? null
|
|
311
|
-
: mode === 'inline-raw'
|
|
312
|
-
? '?raw'
|
|
313
|
-
: '?inline';
|
|
314
|
-
if (inlineQuery !== null) {
|
|
315
|
-
// Build only, so no `import.meta.hot` block. The sheet is still
|
|
316
|
-
// constructed once per virtual module, so adopters share it exactly
|
|
317
|
-
// as they do in the fetch-backed form.
|
|
318
|
-
return {
|
|
319
|
-
code: `import css from ${JSON.stringify(`${file}${inlineQuery}`)};\n` +
|
|
320
|
-
`const sheet = new CSSStyleSheet();\n` +
|
|
321
|
-
`sheet.replaceSync(css);\n` +
|
|
322
|
-
`export default sheet;\n`,
|
|
323
|
-
moduleType: 'js',
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
// The accept specifier must be byte-identical to the import above —
|
|
327
|
-
// Vite resolves accepted HMR deps by static analysis. Generating both
|
|
328
|
-
// here is exactly what frees the caller from writing it. The swap is
|
|
329
|
-
// self-accepted at this boundary, so it never propagates to adopters.
|
|
330
|
-
const urlSpecifier = JSON.stringify(`${file}?url`);
|
|
331
|
-
return {
|
|
332
|
-
code: `import url from ${urlSpecifier};\n` +
|
|
333
|
-
`import {urlSheet} from ${JSON.stringify(helperPath)};\n` +
|
|
334
|
-
`const {sheet, onHotUpdate} = urlSheet(url);\n` +
|
|
335
|
-
`export default sheet;\n` +
|
|
336
|
-
`if (import.meta.hot) {\n` +
|
|
337
|
-
` import.meta.hot.accept(${urlSpecifier}, onHotUpdate);\n` +
|
|
338
|
-
`}\n`,
|
|
339
|
-
moduleType: 'js',
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
return null;
|
|
343
|
-
},
|
|
344
|
-
};
|
|
345
|
-
};
|
|
346
|
-
/**
|
|
347
|
-
* A `css` tagged template literal with no interpolations and no escape
|
|
348
|
-
* sequences — the only kind we can hand to a CSS parser as-is. Literals
|
|
349
|
-
* with `${…}` holes or backslashes simply don't match and stay untouched.
|
|
350
|
-
* The lookbehind keeps `unsafeCSS`/`myCss`-style tags from matching.
|
|
351
|
-
*/
|
|
352
|
-
const CSS_LITERAL_RE = /(?<![\w$.])css`((?:[^`\\$]|\$(?!\{))*)`/g;
|
|
353
|
-
/**
|
|
354
|
-
* Runs Vite's configured Lightning CSS over `css` tagged template literals
|
|
355
|
-
* in user modules, which the CSS pipeline itself never sees (they're plain
|
|
356
|
-
* JS strings to it). Inert unless `css.transformer` is `'lightningcss'`;
|
|
357
|
-
* options come from `css.lightningcss`, so component styles get the same
|
|
358
|
-
* treatment (targets, drafts, …) as `.css` files. Applies in dev and build.
|
|
359
|
-
*/
|
|
360
|
-
const litCssLiterals = () => {
|
|
361
|
-
let lightningcss = null;
|
|
362
|
-
let options;
|
|
363
|
-
let minify = false;
|
|
364
|
-
return {
|
|
365
|
-
name: 'lit-css-literals',
|
|
366
|
-
async configResolved(config) {
|
|
367
|
-
if (config.css.transformer !== 'lightningcss') {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
// The transformer setting guarantees the dependency: Vite itself
|
|
371
|
-
// can't process .css files without it.
|
|
372
|
-
lightningcss = await import('lightningcss');
|
|
373
|
-
// cssModules makes no sense for a literal; everything else carries
|
|
374
|
-
// over.
|
|
375
|
-
const { cssModules: _cssModules, ...rest } = config.css.lightningcss ?? {};
|
|
376
|
-
options = rest;
|
|
377
|
-
minify = config.command === 'build';
|
|
378
|
-
},
|
|
379
|
-
transform(code, id) {
|
|
380
|
-
if (lightningcss === null) {
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
if (id.startsWith('\0') || id.includes('/node_modules/')) {
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
const [file] = id.split('?', 2);
|
|
387
|
-
if (!JS_FILE_RE.test(file) || !code.includes('css`')) {
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
const ms = new MagicString(code);
|
|
391
|
-
let changed = false;
|
|
392
|
-
for (const m of code.matchAll(CSS_LITERAL_RE)) {
|
|
393
|
-
const literal = m[1];
|
|
394
|
-
if (literal.trim() === '') {
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
let out;
|
|
398
|
-
try {
|
|
399
|
-
const result = lightningcss.transform({
|
|
400
|
-
...options,
|
|
401
|
-
filename: file,
|
|
402
|
-
code: Buffer.from(literal),
|
|
403
|
-
minify,
|
|
404
|
-
});
|
|
405
|
-
out = Buffer.from(result.code).toString();
|
|
406
|
-
}
|
|
407
|
-
catch (e) {
|
|
408
|
-
this.warn(`[lit-plugin] skipping css literal Lightning CSS couldn't parse: ${e.message}`);
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
// Re-escape for the template literal the output goes back into.
|
|
412
|
-
out = out.replace(/[\\`$]/g, '\\$&');
|
|
413
|
-
if (out !== literal) {
|
|
414
|
-
const start = m.index + 'css`'.length;
|
|
415
|
-
ms.overwrite(start, start + literal.length, out);
|
|
416
|
-
changed = true;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (!changed) {
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
return { code: ms.toString(), map: ms.generateMap({ hires: true }) };
|
|
423
|
-
},
|
|
424
|
-
};
|
|
425
|
-
};
|
|
9
|
+
import {injectSourceMeta} from './source-meta.js';
|
|
10
|
+
import {INSTALL_ID, VIRTUAL_PREFIX, transformLitModule} from './transform.js';
|
|
11
|
+
import {WRAP_TABLE} from './wrap-table.js';
|
|
12
|
+
import {createLitDevframePlugin} from './devframe/vite.js';
|
|
13
|
+
import {PACKAGE_VERSION} from './devframe/paths.js';
|
|
14
|
+
import {ENV_PREFIX, resolveOptions, toFeatureSettings} from './options.js';
|
|
15
|
+
import {
|
|
16
|
+
OPEN_IN_EDITOR_PATH,
|
|
17
|
+
createOpenInEditorMiddleware,
|
|
18
|
+
} from './plugins/open-in-editor.js';
|
|
19
|
+
import {litCssQueries} from './plugins/css-queries.js';
|
|
20
|
+
import {litTimelineVirtual} from './plugins/timeline-virtual.js';
|
|
21
|
+
import {litCssLiterals} from './plugins/css-literals.js';
|
|
22
|
+
import {resolveRuntimeModule, JS_FILE_RE} from './plugins/shared.js';
|
|
23
|
+
export {createOpenInEditorMiddleware} from './plugins/open-in-editor.js';
|
|
24
|
+
export {litCssQueries} from './plugins/css-queries.js';
|
|
25
|
+
export {litTimelineVirtual} from './plugins/timeline-virtual.js';
|
|
26
|
+
export {resolveOptions} from './options.js';
|
|
426
27
|
/**
|
|
427
28
|
* Vite plugin set providing HMR, CSS helpers, and Lightning CSS processing
|
|
428
29
|
* for Lit projects.
|
|
429
30
|
*/
|
|
430
31
|
export const litPlugin = (options = {}) => {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
name: 'lit-plugin',
|
|
530
|
-
apply: 'serve',
|
|
531
|
-
config: () => {
|
|
532
|
-
// Options are already resolved against the loaded env by
|
|
533
|
-
// `lit-plugin-options`, which runs first.
|
|
534
|
-
if (!resolved.hmrEnabled) {
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
// The injected runtime imports are invisible to the dep scanner. The
|
|
538
|
-
// lit family stays prebundle-eligible on purpose: the wrapper modules'
|
|
539
|
-
// bare imports then resolve to the same URL every other importer gets —
|
|
540
|
-
// single lit instance, single template cache.
|
|
541
|
-
return { optimizeDeps: { exclude: ['@lit-labs/vite-plugin-lit'] } };
|
|
542
|
-
},
|
|
543
|
-
resolveId(id) {
|
|
544
|
-
// Public timeline API virtual module.
|
|
545
|
-
if (id === 'virtual:lit-plugin/timeline') {
|
|
546
|
-
return '\0virtual:lit-plugin/timeline';
|
|
547
|
-
}
|
|
548
|
-
// Resolve the browser CSS helpers and indicator runtime to the copy
|
|
549
|
-
// shipped next to this plugin, so they work even when the package
|
|
550
|
-
// isn't reachable through node resolution from the served root (and
|
|
551
|
-
// stay out of prebundling).
|
|
552
|
-
if (id === '@lit-labs/vite-plugin-lit/css.js') {
|
|
553
|
-
return resolveRuntimeModule('css');
|
|
554
|
-
}
|
|
555
|
-
if (id === '@lit-labs/vite-plugin-lit/indicator.js') {
|
|
556
|
-
return resolveRuntimeModule('indicator');
|
|
557
|
-
}
|
|
558
|
-
if (id === '@lit-labs/vite-plugin-lit/source-overlay.js') {
|
|
559
|
-
return resolveRuntimeModule('source-overlay');
|
|
560
|
-
}
|
|
561
|
-
if (resolved.hmrEnabled && id.startsWith(VIRTUAL_PREFIX)) {
|
|
562
|
-
return id;
|
|
563
|
-
}
|
|
564
|
-
return null;
|
|
565
|
-
},
|
|
566
|
-
load(id) {
|
|
567
|
-
// Public timeline API — re-export the runtime module when timeline is
|
|
568
|
-
// enabled, otherwise a no-op stub so imports don't throw in prod builds.
|
|
569
|
-
if (id === '\0virtual:lit-plugin/timeline') {
|
|
570
|
-
if (!resolved.timeline) {
|
|
571
|
-
return {
|
|
572
|
-
code: 'export const addTimelineEvent = () => {};\n' +
|
|
573
|
-
'export const addTimelineLayer = () => {};\n',
|
|
574
|
-
moduleType: 'js',
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
const apiPath = resolveRuntimeModule('timeline/public-api');
|
|
578
|
-
return {
|
|
579
|
-
code: `export * from ${JSON.stringify(apiPath)};\n`,
|
|
580
|
-
moduleType: 'js',
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
if (!resolved.hmrEnabled || !id.startsWith(VIRTUAL_PREFIX)) {
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
if (id === INSTALL_ID) {
|
|
587
|
-
const patchPath = resolveRuntimeModule('patch');
|
|
588
|
-
const runtimeOptions = {
|
|
589
|
-
reconnect: resolved.reconnect,
|
|
590
|
-
onIncompatible: resolved.onIncompatible,
|
|
591
|
-
};
|
|
592
|
-
return {
|
|
593
|
-
code: `import {install} from ${JSON.stringify(patchPath)};\n` +
|
|
594
|
-
`install(${JSON.stringify(runtimeOptions)});\n`,
|
|
595
|
-
moduleType: 'js',
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
const spec = id.slice(VIRTUAL_PREFIX.length);
|
|
599
|
-
const wrappedTags = WRAP_TABLE.get(spec);
|
|
600
|
-
if (wrappedTags === undefined) {
|
|
601
|
-
return null;
|
|
602
|
-
}
|
|
603
|
-
const internPath = resolveRuntimeModule('intern');
|
|
604
|
-
// Browser-native ESM: explicit local exports shadow `export *` names
|
|
605
|
-
// (spec-guaranteed), so everything except the wrapped tags passes
|
|
606
|
-
// through unchanged.
|
|
607
|
-
const lines = [
|
|
608
|
-
`import * as __lit from ${JSON.stringify(spec)};`,
|
|
609
|
-
`import {wrapTag} from ${JSON.stringify(internPath)};`,
|
|
610
|
-
`export * from ${JSON.stringify(spec)};`,
|
|
611
|
-
];
|
|
612
|
-
for (const { exportName, ns } of wrappedTags) {
|
|
613
|
-
lines.push(`export const ${exportName} = wrapTag(__lit.${exportName}, ${JSON.stringify(ns)});`);
|
|
614
|
-
}
|
|
615
|
-
return { code: lines.join('\n') + '\n', moduleType: 'js' };
|
|
616
|
-
},
|
|
617
|
-
async transform(code, id, transformOptions) {
|
|
618
|
-
if (!resolved.hmrEnabled) {
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
if (transformOptions?.ssr) {
|
|
622
|
-
return null;
|
|
623
|
-
}
|
|
624
|
-
if (id.startsWith('\0') || id.includes('/node_modules/')) {
|
|
625
|
-
return null;
|
|
626
|
-
}
|
|
627
|
-
const [file] = id.split('?', 2);
|
|
628
|
-
// Allow inline scripts extracted from HTML (`?html-proxy`).
|
|
629
|
-
if (!JS_FILE_RE.test(file) && !id.includes('?html-proxy')) {
|
|
630
|
-
return null;
|
|
631
|
-
}
|
|
632
|
-
return transformLitModule(code);
|
|
633
|
-
},
|
|
634
|
-
transformIndexHtml() {
|
|
635
|
-
const tags = [];
|
|
636
|
-
const indicator = resolved.indicator;
|
|
637
|
-
if (indicator) {
|
|
638
|
-
const indicatorUrl = `/@fs/` + resolveRuntimeModule('indicator');
|
|
639
|
-
tags.push({
|
|
640
|
-
tag: 'script',
|
|
641
|
-
attrs: { type: 'module', src: indicatorUrl },
|
|
642
|
-
injectTo: 'body',
|
|
643
|
-
}, {
|
|
644
|
-
tag: 'lit-devtools-hmr-indicator',
|
|
645
|
-
attrs: indicator.count ? { count: '' } : undefined,
|
|
646
|
-
children: '',
|
|
647
|
-
injectTo: 'body',
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
if (resolved.timeline) {
|
|
651
|
-
const installUrl = `/@fs/` + resolveRuntimeModule('timeline/install');
|
|
652
|
-
tags.push({
|
|
653
|
-
tag: 'script',
|
|
654
|
-
attrs: { type: 'module', src: installUrl },
|
|
655
|
-
injectTo: 'body',
|
|
656
|
-
});
|
|
657
|
-
// Components inspector runtime — answers the panel's tree/details
|
|
658
|
-
// requests. Paired with the timeline panel, which hosts its tab.
|
|
659
|
-
const inspectorUrl = `/@fs/` + resolveRuntimeModule('inspector/install');
|
|
660
|
-
tags.push({
|
|
661
|
-
tag: 'script',
|
|
662
|
-
attrs: { type: 'module', src: inspectorUrl },
|
|
663
|
-
injectTo: 'body',
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
return tags.length > 0 ? tags : undefined;
|
|
32
|
+
// Resolved from explicit options first, env vars second, defaults last. The
|
|
33
|
+
// `lit-plugin-options` `config` hook below re-resolves with the loaded env
|
|
34
|
+
// once Vite hands us the mode; this initial pass covers code paths that run
|
|
35
|
+
// before (or without) it.
|
|
36
|
+
let resolved = resolveOptions(options, {});
|
|
37
|
+
let root = '';
|
|
38
|
+
// Env resolution lives in its own always-applied plugin: `?css-sheet` is a
|
|
39
|
+
// build-time feature too, and the HMR plugin (`apply: 'serve'`) never gets a
|
|
40
|
+
// `config` hook under `vite build`. `enforce: 'pre'` and first position put
|
|
41
|
+
// it ahead of every other hook that reads `resolved`.
|
|
42
|
+
const optionsPlugin = {
|
|
43
|
+
name: 'lit-plugin-options',
|
|
44
|
+
enforce: 'pre',
|
|
45
|
+
config(viteConfig, {mode}) {
|
|
46
|
+
// `loadEnv` reads `.env*` files from the env dir (root by default) and
|
|
47
|
+
// merges in matching `process.env` keys, filtered to the `LIT_PLUGIN`
|
|
48
|
+
// prefix. Explicit options still win (handled in resolveOptions).
|
|
49
|
+
const envDir = viteConfig.envDir
|
|
50
|
+
? resolvePath(viteConfig.envDir)
|
|
51
|
+
: viteConfig.root
|
|
52
|
+
? resolvePath(viteConfig.root)
|
|
53
|
+
: process.cwd();
|
|
54
|
+
resolved = resolveOptions(options, loadEnv(mode, envDir, ENV_PREFIX));
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const sourceOverlayPlugin = {
|
|
58
|
+
name: 'lit-source-overlay',
|
|
59
|
+
apply: 'serve',
|
|
60
|
+
// Run before Vite's esbuild TS transform so source-meta line numbers are
|
|
61
|
+
// measured against the author's raw source (and the `@customElement … class`
|
|
62
|
+
// forms are still intact), not against transpiled output.
|
|
63
|
+
enforce: 'pre',
|
|
64
|
+
configResolved(config) {
|
|
65
|
+
root = config.root;
|
|
66
|
+
},
|
|
67
|
+
resolveId(id) {
|
|
68
|
+
if (id === '@oddsquad/vite-plugin-lit/source-overlay.js') {
|
|
69
|
+
return resolveRuntimeModule('source-overlay');
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
},
|
|
73
|
+
configureServer(server) {
|
|
74
|
+
if (!resolved.sourceOverlay) return;
|
|
75
|
+
// Allow opens from everything vite itself is willing to serve
|
|
76
|
+
// (`server.fs.allow` defaults to the workspace root), not just
|
|
77
|
+
// `config.root` — in monorepos, component sources regularly live in
|
|
78
|
+
// sibling packages outside the served app's root.
|
|
79
|
+
const fsAllow = server.config.server.fs?.allow ?? [];
|
|
80
|
+
server.middlewares.use(
|
|
81
|
+
OPEN_IN_EDITOR_PATH,
|
|
82
|
+
createOpenInEditorMiddleware([root, ...fsAllow])
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
transform(code, id, transformOptions) {
|
|
86
|
+
if (!resolved.sourceOverlay) return null;
|
|
87
|
+
if (transformOptions?.ssr) return null;
|
|
88
|
+
if (
|
|
89
|
+
id.startsWith('\0') ||
|
|
90
|
+
id.includes('__x00__') ||
|
|
91
|
+
id.includes('lit-plugin:') ||
|
|
92
|
+
id.includes('/node_modules/')
|
|
93
|
+
) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const [file] = id.split('?', 2);
|
|
97
|
+
if (!JS_FILE_RE.test(file) && !id.includes('?html-proxy')) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (!code.includes('customElement') && !code.includes('customElements')) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const ms = new MagicString(code);
|
|
104
|
+
const relativeFile = file.startsWith(root + '/')
|
|
105
|
+
? file.slice(root.length + 1)
|
|
106
|
+
: file;
|
|
107
|
+
if (!injectSourceMeta(code, relativeFile, ms)) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return {code: ms.toString(), map: ms.generateMap({hires: true})};
|
|
111
|
+
},
|
|
112
|
+
transformIndexHtml() {
|
|
113
|
+
if (!resolved.sourceOverlay) return;
|
|
114
|
+
const overlayUrl = `/@fs/${resolveRuntimeModule('source-overlay')}`;
|
|
115
|
+
const {
|
|
116
|
+
exclude: _exclude,
|
|
117
|
+
onSelect: _onSelect,
|
|
118
|
+
...overlayInit
|
|
119
|
+
} = resolved.sourceOverlay;
|
|
120
|
+
const initConfig = {
|
|
121
|
+
...overlayInit,
|
|
122
|
+
openInEditorPath: OPEN_IN_EDITOR_PATH,
|
|
123
|
+
};
|
|
124
|
+
return [
|
|
125
|
+
{
|
|
126
|
+
tag: 'script',
|
|
127
|
+
attrs: {type: 'module'},
|
|
128
|
+
children: `import {initSourceOverlay} from ${JSON.stringify(overlayUrl)};\ninitSourceOverlay(${JSON.stringify(initConfig)});\n`,
|
|
129
|
+
injectTo: 'body',
|
|
667
130
|
},
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
131
|
+
];
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
const hmr = {
|
|
135
|
+
name: 'lit-plugin',
|
|
136
|
+
apply: 'serve',
|
|
137
|
+
config: () => {
|
|
138
|
+
// Options are already resolved against the loaded env by
|
|
139
|
+
// `lit-plugin-options`, which runs first.
|
|
140
|
+
if (!resolved.hmrEnabled) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// The injected runtime imports are invisible to the dep scanner. The
|
|
144
|
+
// lit family stays prebundle-eligible on purpose: the wrapper modules'
|
|
145
|
+
// bare imports then resolve to the same URL every other importer gets —
|
|
146
|
+
// single lit instance, single template cache.
|
|
147
|
+
return {optimizeDeps: {exclude: ['@oddsquad/vite-plugin-lit']}};
|
|
148
|
+
},
|
|
149
|
+
resolveId(id) {
|
|
150
|
+
// Resolve the browser CSS helpers and indicator runtime to the copy
|
|
151
|
+
// shipped next to this plugin, so they work even when the package
|
|
152
|
+
// isn't reachable through node resolution from the served root (and
|
|
153
|
+
// stay out of prebundling).
|
|
154
|
+
//
|
|
155
|
+
// These bare specifiers must match the package name in package.json —
|
|
156
|
+
// consumers import them by name (see README "Stylesheets"), and Vite
|
|
157
|
+
// only consults this hook for the exact string. A rename that misses
|
|
158
|
+
// them turns the fallback into silently dead code.
|
|
159
|
+
if (id === '@oddsquad/vite-plugin-lit/css.js') {
|
|
160
|
+
return resolveRuntimeModule('css');
|
|
161
|
+
}
|
|
162
|
+
if (id === '@oddsquad/vite-plugin-lit/indicator.js') {
|
|
163
|
+
return resolveRuntimeModule('indicator');
|
|
164
|
+
}
|
|
165
|
+
if (id === '@oddsquad/vite-plugin-lit/source-overlay.js') {
|
|
166
|
+
return resolveRuntimeModule('source-overlay');
|
|
167
|
+
}
|
|
168
|
+
if (resolved.hmrEnabled && id.startsWith(VIRTUAL_PREFIX)) {
|
|
169
|
+
return id;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
},
|
|
173
|
+
load(id) {
|
|
174
|
+
if (!resolved.hmrEnabled || !id.startsWith(VIRTUAL_PREFIX)) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (id === INSTALL_ID) {
|
|
178
|
+
const patchPath = resolveRuntimeModule('patch');
|
|
179
|
+
const runtimeOptions = {
|
|
180
|
+
reconnect: resolved.reconnect,
|
|
181
|
+
onIncompatible: resolved.onIncompatible,
|
|
182
|
+
};
|
|
183
|
+
return {
|
|
184
|
+
code:
|
|
185
|
+
`import {install} from ${JSON.stringify(patchPath)};\n` +
|
|
186
|
+
`install(${JSON.stringify(runtimeOptions)});\n`,
|
|
187
|
+
moduleType: 'js',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const spec = id.slice(VIRTUAL_PREFIX.length);
|
|
191
|
+
const wrappedTags = WRAP_TABLE.get(spec);
|
|
192
|
+
if (wrappedTags === undefined) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const internPath = resolveRuntimeModule('intern');
|
|
196
|
+
// Browser-native ESM: explicit local exports shadow `export *` names
|
|
197
|
+
// (spec-guaranteed), so everything except the wrapped tags passes
|
|
198
|
+
// through unchanged.
|
|
199
|
+
const lines = [
|
|
200
|
+
`import * as __lit from ${JSON.stringify(spec)};`,
|
|
201
|
+
`import {wrapTag} from ${JSON.stringify(internPath)};`,
|
|
202
|
+
`export * from ${JSON.stringify(spec)};`,
|
|
203
|
+
];
|
|
204
|
+
for (const {exportName, ns} of wrappedTags) {
|
|
205
|
+
lines.push(
|
|
206
|
+
`export const ${exportName} = wrapTag(__lit.${exportName}, ${JSON.stringify(ns)});`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
return {code: lines.join('\n') + '\n', moduleType: 'js'};
|
|
210
|
+
},
|
|
211
|
+
async transform(code, id, transformOptions) {
|
|
212
|
+
if (!resolved.hmrEnabled) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (transformOptions?.ssr) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
if (id.startsWith('\0') || id.includes('/node_modules/')) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const [file] = id.split('?', 2);
|
|
222
|
+
// Allow inline scripts extracted from HTML (`?html-proxy`).
|
|
223
|
+
if (!JS_FILE_RE.test(file) && !id.includes('?html-proxy')) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
return transformLitModule(code);
|
|
227
|
+
},
|
|
228
|
+
transformIndexHtml() {
|
|
229
|
+
const tags = [];
|
|
230
|
+
const indicator = resolved.indicator;
|
|
231
|
+
if (indicator) {
|
|
232
|
+
const indicatorUrl = `/@fs/` + resolveRuntimeModule('indicator');
|
|
233
|
+
tags.push(
|
|
234
|
+
{
|
|
235
|
+
tag: 'script',
|
|
236
|
+
attrs: {type: 'module', src: indicatorUrl},
|
|
237
|
+
injectTo: 'body',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
tag: 'lit-devtools-hmr-indicator',
|
|
241
|
+
attrs: indicator.count ? {count: ''} : undefined,
|
|
242
|
+
children: '',
|
|
243
|
+
injectTo: 'body',
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (resolved.timeline) {
|
|
248
|
+
const installUrl = `/@fs/` + resolveRuntimeModule('timeline/install');
|
|
249
|
+
tags.push({
|
|
250
|
+
tag: 'script',
|
|
251
|
+
attrs: {type: 'module', src: installUrl},
|
|
252
|
+
injectTo: 'body',
|
|
253
|
+
});
|
|
254
|
+
// Components inspector runtime — answers the panel's tree/details
|
|
255
|
+
// requests. Paired with the timeline panel, which hosts its tab.
|
|
256
|
+
const inspectorUrl =
|
|
257
|
+
`/@fs/` + resolveRuntimeModule('inspector/install');
|
|
258
|
+
tags.push({
|
|
259
|
+
tag: 'script',
|
|
260
|
+
attrs: {type: 'module', src: inspectorUrl},
|
|
261
|
+
injectTo: 'body',
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return tags.length > 0 ? tags : undefined;
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
// The source-overlay plugin is always present; its hooks no-op when the
|
|
268
|
+
// feature is disabled (which env may decide), so inclusion can't be gated
|
|
269
|
+
// on the synchronously-known options here.
|
|
270
|
+
const plugins = [
|
|
271
|
+
optionsPlugin,
|
|
272
|
+
// Getter, not a snapshot: `resolved` is re-resolved against the loaded env
|
|
273
|
+
// in `optionsPlugin`'s `config` hook, which runs after this array is built.
|
|
274
|
+
litCssQueries(() => resolved.cssSheetBuild),
|
|
275
|
+
litTimelineVirtual(() => resolved.timeline),
|
|
276
|
+
litCssLiterals(),
|
|
277
|
+
sourceOverlayPlugin,
|
|
278
|
+
hmr,
|
|
279
|
+
];
|
|
280
|
+
if (resolved.timeline) {
|
|
281
|
+
// `features` is a getter, not a snapshot: `resolved` is re-resolved
|
|
282
|
+
// against the loaded env in `optionsPlugin`'s `config` hook, which runs
|
|
283
|
+
// after this array is built.
|
|
284
|
+
plugins.push(
|
|
285
|
+
createLitDevframePlugin({
|
|
286
|
+
version: PACKAGE_VERSION,
|
|
287
|
+
features: () => toFeatureSettings(resolved),
|
|
288
|
+
})
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
return plugins;
|
|
689
292
|
};
|
|
690
|
-
//# sourceMappingURL=plugin.js.map
|
|
293
|
+
//# sourceMappingURL=plugin.js.map
|