@oddsquad/vite-plugin-lit 0.0.5 → 0.2.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/lib/plugin.d.ts +57 -1
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +175 -80
- package/lib/plugin.js.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.js +8 -4
- package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
- package/lib/runtime/source-overlay/template.d.ts +1 -1
- package/lib/runtime/source-overlay/template.d.ts.map +1 -1
- package/lib/runtime/source-overlay/template.js +7 -1
- package/lib/runtime/source-overlay/template.js.map +1 -1
- package/lib/source-meta.d.ts.map +1 -1
- package/lib/source-meta.js +86 -21
- package/lib/source-meta.js.map +1 -1
- package/package.json +1 -1
- package/panel/components-view.d.ts.map +1 -1
- package/panel/components-view.js +7 -1
- package/panel/components-view.js.map +1 -1
package/lib/plugin.d.ts
CHANGED
|
@@ -46,6 +46,17 @@ export interface HmrOptions {
|
|
|
46
46
|
*/
|
|
47
47
|
indicator?: boolean | HmrIndicatorOptions;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* What a `?css-sheet` import compiles to under `vite build`.
|
|
51
|
+
*
|
|
52
|
+
* - `'url'`: fetch-backed sheet over the emitted `.css` asset.
|
|
53
|
+
* - `'inline'`: css text embedded in the JS chunk, processed by the css
|
|
54
|
+
* pipeline (`?inline`).
|
|
55
|
+
* - `'inline-raw'`: css text embedded verbatim, skipping the css pipeline
|
|
56
|
+
* (`?raw`).
|
|
57
|
+
* - `'auto'`: `'inline'` when `build.lib` is set, `'url'` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
export type CssSheetBuild = 'auto' | 'url' | 'inline' | 'inline-raw';
|
|
49
60
|
/**
|
|
50
61
|
* Options for the Lit Vite plugin.
|
|
51
62
|
*
|
|
@@ -77,14 +88,59 @@ export interface LitPluginOptions {
|
|
|
77
88
|
* `true` enables all built-in layers with defaults.
|
|
78
89
|
*/
|
|
79
90
|
timeline?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* What a `?css-sheet` import compiles to under `vite build`.
|
|
93
|
+
* - `'url'`: fetch-backed sheet over the emitted `.css` asset
|
|
94
|
+
* - `'inline'`: css text embedded in the JS chunk, processed by the css
|
|
95
|
+
* pipeline (`?inline`)
|
|
96
|
+
* - `'inline-raw'`: css text embedded verbatim, skipping the css pipeline
|
|
97
|
+
* (`?raw`)
|
|
98
|
+
* - `'auto'`: `'inline'` when `build.lib` is set, `'url'` otherwise
|
|
99
|
+
*
|
|
100
|
+
* Dev is always the fetch-backed HMR form regardless of this setting.
|
|
101
|
+
* Defaults to `'auto'`.
|
|
102
|
+
*/
|
|
103
|
+
cssSheetBuild?: CssSheetBuild;
|
|
104
|
+
}
|
|
105
|
+
/** Plugin options after merging explicit options, env vars, and defaults. */
|
|
106
|
+
export interface ResolvedOptions {
|
|
107
|
+
hmrEnabled: boolean;
|
|
108
|
+
reconnect: boolean;
|
|
109
|
+
onIncompatible: 'reload' | 'warn';
|
|
110
|
+
indicator: false | {
|
|
111
|
+
count: boolean;
|
|
112
|
+
};
|
|
113
|
+
sourceOverlay: false | SourceOverlayOptions;
|
|
114
|
+
timeline: boolean;
|
|
115
|
+
cssSheetBuild: CssSheetBuild;
|
|
80
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Merge explicit options over env vars over defaults (in that precedence) into
|
|
119
|
+
* the flat shape the plugin hooks consume.
|
|
120
|
+
*/
|
|
121
|
+
export declare const resolveOptions: (options: LitPluginOptions, env: Record<string, string>) => ResolvedOptions;
|
|
122
|
+
export declare const createOpenInEditorMiddleware: (allowedRoots: readonly string[]) => (req: {
|
|
123
|
+
url?: string;
|
|
124
|
+
headers?: {
|
|
125
|
+
origin?: string;
|
|
126
|
+
host?: string;
|
|
127
|
+
};
|
|
128
|
+
}, res: {
|
|
129
|
+
statusCode: number;
|
|
130
|
+
end: (msg: string) => void;
|
|
131
|
+
}, next: (err?: unknown) => void) => void;
|
|
81
132
|
/**
|
|
82
133
|
* Import-query support, served in dev and build alike (source code using
|
|
83
134
|
* `?hmr-url`/`?css-sheet` must keep working under `vite build`, where the HMR
|
|
84
135
|
* plugin doesn't apply). Exported for the baseline e2e run, which needs the
|
|
85
136
|
* queries working without the HMR plugin.
|
|
137
|
+
*
|
|
138
|
+
* `getCssSheetBuild` is a getter, not a value: `litPlugin()` re-resolves its
|
|
139
|
+
* options against the loaded env in a `config` hook, which runs after the
|
|
140
|
+
* plugin array is built. Standalone (no getter) it behaves like the `'auto'`
|
|
141
|
+
* default.
|
|
86
142
|
*/
|
|
87
|
-
export declare const litCssQueries: () => Plugin;
|
|
143
|
+
export declare const litCssQueries: (getCssSheetBuild?: () => CssSheetBuild) => Plugin;
|
|
88
144
|
/**
|
|
89
145
|
* Vite plugin set providing HMR, CSS helpers, and Lightning CSS processing
|
|
90
146
|
* for Lit projects.
|
package/lib/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAA2B,KAAK,MAAM,EAAC,MAAM,MAAM,CAAC;AAI3D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAKrD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAEnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;IAE/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAA2B,KAAK,MAAM,EAAC,MAAM,MAAM,CAAC;AAI3D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAKrD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAEnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC3C;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,CAAC;AASrE;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;IAE/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,KAAK,GAAG;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,CAAC;IACpC,aAAa,EAAE,KAAK,GAAG,oBAAoB,CAAC;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAuCD;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,SAAS,gBAAgB,EACzB,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC1B,eA4DF,CAAC;AA8DF,eAAO,MAAM,4BAA4B,GACvC,cAAc,SAAS,MAAM,EAAE,MAM7B,KAAK;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,EAC/D,KAAK;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAC,EACrD,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,SAkFhC,CAAC;AAoCF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GACxB,mBAAkB,MAAM,aAA4B,KACnD,MAwFF,CAAC;AAuFF;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,UAAS,gBAAqB,KAAG,MAAM,EA0RhE,CAAC"}
|
package/lib/plugin.js
CHANGED
|
@@ -12,6 +12,12 @@ import { injectSourceMeta } from './source-meta.js';
|
|
|
12
12
|
import { INSTALL_ID, VIRTUAL_PREFIX, transformLitModule } from './transform.js';
|
|
13
13
|
import { WRAP_TABLE } from './wrap-table.js';
|
|
14
14
|
import { litTimelinePlugin } from './timeline-plugin.js';
|
|
15
|
+
const CSS_SHEET_BUILD_MODES = [
|
|
16
|
+
'auto',
|
|
17
|
+
'url',
|
|
18
|
+
'inline',
|
|
19
|
+
'inline-raw',
|
|
20
|
+
];
|
|
15
21
|
/** Env var prefix consumed at config time. */
|
|
16
22
|
const ENV_PREFIX = 'LIT_PLUGIN';
|
|
17
23
|
/** Parse a boolean-ish env string; `undefined` when unset/unrecognized. */
|
|
@@ -27,11 +33,25 @@ const envNum = (v) => {
|
|
|
27
33
|
const n = Number(v);
|
|
28
34
|
return Number.isNaN(n) ? undefined : n;
|
|
29
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
|
+
};
|
|
30
50
|
/**
|
|
31
51
|
* Merge explicit options over env vars over defaults (in that precedence) into
|
|
32
52
|
* the flat shape the plugin hooks consume.
|
|
33
53
|
*/
|
|
34
|
-
const resolveOptions = (options, env) => {
|
|
54
|
+
export const resolveOptions = (options, env) => {
|
|
35
55
|
const hmr = options.hmr;
|
|
36
56
|
const hmrObj = typeof hmr === 'object' ? hmr : undefined;
|
|
37
57
|
const hmrEnabled = (typeof hmr === 'boolean' ? hmr : hmrObj?.enabled) ??
|
|
@@ -61,6 +81,9 @@ const resolveOptions = (options, env) => {
|
|
|
61
81
|
sourceOverlay = base;
|
|
62
82
|
}
|
|
63
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';
|
|
64
87
|
return {
|
|
65
88
|
hmrEnabled,
|
|
66
89
|
reconnect,
|
|
@@ -68,6 +91,7 @@ const resolveOptions = (options, env) => {
|
|
|
68
91
|
indicator,
|
|
69
92
|
sourceOverlay,
|
|
70
93
|
timeline,
|
|
94
|
+
cssSheetBuild,
|
|
71
95
|
};
|
|
72
96
|
};
|
|
73
97
|
/**
|
|
@@ -126,7 +150,10 @@ const isSameOrigin = (headers) => {
|
|
|
126
150
|
return false;
|
|
127
151
|
}
|
|
128
152
|
};
|
|
129
|
-
const createOpenInEditorMiddleware = (
|
|
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));
|
|
130
157
|
return (req, res, next) => {
|
|
131
158
|
if (req.url === undefined) {
|
|
132
159
|
next();
|
|
@@ -147,14 +174,16 @@ const createOpenInEditorMiddleware = (root) => {
|
|
|
147
174
|
res.end('missing file parameter');
|
|
148
175
|
return;
|
|
149
176
|
}
|
|
150
|
-
// Confine the open to the
|
|
151
|
-
// reject anything that escapes
|
|
152
|
-
// arbitrary files). `launch-editor` spawns the user's editor on
|
|
153
|
-
// so an unvalidated `file` is a local-file-open /
|
|
154
|
-
|
|
155
|
-
|
|
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) {
|
|
156
185
|
res.statusCode = 403;
|
|
157
|
-
res.end('file outside
|
|
186
|
+
res.end('file outside allowed roots');
|
|
158
187
|
return;
|
|
159
188
|
}
|
|
160
189
|
if (!existsSync(resolved)) {
|
|
@@ -170,14 +199,24 @@ const createOpenInEditorMiddleware = (root) => {
|
|
|
170
199
|
import('launch-editor')
|
|
171
200
|
.then((mod) => {
|
|
172
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
|
+
};
|
|
173
214
|
launch(fileRef, (_fileName, errorMessage) => {
|
|
174
215
|
if (errorMessage !== null) {
|
|
175
|
-
|
|
176
|
-
res.end(errorMessage);
|
|
177
|
-
return;
|
|
216
|
+
finish(500, errorMessage);
|
|
178
217
|
}
|
|
179
|
-
res.end('ok');
|
|
180
218
|
});
|
|
219
|
+
finish(200, 'ok');
|
|
181
220
|
})
|
|
182
221
|
.catch(next);
|
|
183
222
|
};
|
|
@@ -203,6 +242,11 @@ const CSS_URL_VIRTUAL_PREFIX = '\0lit-plugin:hmr-url:';
|
|
|
203
242
|
* a plugin-generated module: the `import.meta.hot.accept` lives here (where
|
|
204
243
|
* Vite's static analysis sees the literal specifier), so callers write a bare
|
|
205
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.
|
|
206
250
|
*/
|
|
207
251
|
const CSS_SHEET_QUERY_RE = /^([^?]+\.css)\?(?:[^&]*&)*css-sheet(?:&.*)?$/;
|
|
208
252
|
const CSS_SHEET_VIRTUAL_PREFIX = '\0lit-plugin:css-sheet:';
|
|
@@ -214,60 +258,91 @@ const CSS_VIRTUAL_SUFFIX = '.js';
|
|
|
214
258
|
* `?hmr-url`/`?css-sheet` must keep working under `vite build`, where the HMR
|
|
215
259
|
* plugin doesn't apply). Exported for the baseline e2e run, which needs the
|
|
216
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.
|
|
217
266
|
*/
|
|
218
|
-
export const litCssQueries = () =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
+
}
|
|
235
342
|
return null;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
load(id) {
|
|
240
|
-
const helperPath = resolveRuntimeModule('css');
|
|
241
|
-
if (id.startsWith(CSS_URL_VIRTUAL_PREFIX)) {
|
|
242
|
-
const file = id.slice(CSS_URL_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length);
|
|
243
|
-
return {
|
|
244
|
-
code: `import url from ${JSON.stringify(`${file}?url`)};\n` +
|
|
245
|
-
`import {devCacheBust} from ${JSON.stringify(helperPath)};\n` +
|
|
246
|
-
`export default devCacheBust(url);\n`,
|
|
247
|
-
moduleType: 'js',
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
if (id.startsWith(CSS_SHEET_VIRTUAL_PREFIX)) {
|
|
251
|
-
const file = id.slice(CSS_SHEET_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length);
|
|
252
|
-
// The accept specifier must be byte-identical to the import above —
|
|
253
|
-
// Vite resolves accepted HMR deps by static analysis. Generating both
|
|
254
|
-
// here is exactly what frees the caller from writing it. The swap is
|
|
255
|
-
// self-accepted at this boundary, so it never propagates to adopters.
|
|
256
|
-
const urlSpecifier = JSON.stringify(`${file}?url`);
|
|
257
|
-
return {
|
|
258
|
-
code: `import url from ${urlSpecifier};\n` +
|
|
259
|
-
`import {urlSheet} from ${JSON.stringify(helperPath)};\n` +
|
|
260
|
-
`const {sheet, onHotUpdate} = urlSheet(url);\n` +
|
|
261
|
-
`export default sheet;\n` +
|
|
262
|
-
`if (import.meta.hot) {\n` +
|
|
263
|
-
` import.meta.hot.accept(${urlSpecifier}, onHotUpdate);\n` +
|
|
264
|
-
`}\n`,
|
|
265
|
-
moduleType: 'js',
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
return null;
|
|
269
|
-
},
|
|
270
|
-
});
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
};
|
|
271
346
|
/**
|
|
272
347
|
* A `css` tagged template literal with no interpolations and no escape
|
|
273
348
|
* sequences — the only kind we can hand to a CSS parser as-is. Literals
|
|
@@ -354,10 +429,30 @@ const litCssLiterals = () => {
|
|
|
354
429
|
*/
|
|
355
430
|
export const litPlugin = (options = {}) => {
|
|
356
431
|
// Resolved from explicit options first, env vars second, defaults last. The
|
|
357
|
-
// `config` hook re-resolves with the loaded env
|
|
358
|
-
// this initial pass covers code paths that run
|
|
432
|
+
// `lit-plugin-options` `config` hook below re-resolves with the loaded env
|
|
433
|
+
// once Vite hands us the mode; this initial pass covers code paths that run
|
|
434
|
+
// before (or without) it.
|
|
359
435
|
let resolved = resolveOptions(options, {});
|
|
360
436
|
let root = '';
|
|
437
|
+
// Env resolution lives in its own always-applied plugin: `?css-sheet` is a
|
|
438
|
+
// build-time feature too, and the HMR plugin (`apply: 'serve'`) never gets a
|
|
439
|
+
// `config` hook under `vite build`. `enforce: 'pre'` and first position put
|
|
440
|
+
// it ahead of every other hook that reads `resolved`.
|
|
441
|
+
const optionsPlugin = {
|
|
442
|
+
name: 'lit-plugin-options',
|
|
443
|
+
enforce: 'pre',
|
|
444
|
+
config(viteConfig, { mode }) {
|
|
445
|
+
// `loadEnv` reads `.env*` files from the env dir (root by default) and
|
|
446
|
+
// merges in matching `process.env` keys, filtered to the `LIT_PLUGIN`
|
|
447
|
+
// prefix. Explicit options still win (handled in resolveOptions).
|
|
448
|
+
const envDir = viteConfig.envDir
|
|
449
|
+
? resolvePath(viteConfig.envDir)
|
|
450
|
+
: viteConfig.root
|
|
451
|
+
? resolvePath(viteConfig.root)
|
|
452
|
+
: process.cwd();
|
|
453
|
+
resolved = resolveOptions(options, loadEnv(mode, envDir, ENV_PREFIX));
|
|
454
|
+
},
|
|
455
|
+
};
|
|
361
456
|
const sourceOverlayPlugin = {
|
|
362
457
|
name: 'lit-source-overlay',
|
|
363
458
|
apply: 'serve',
|
|
@@ -377,7 +472,12 @@ export const litPlugin = (options = {}) => {
|
|
|
377
472
|
configureServer(server) {
|
|
378
473
|
if (!resolved.sourceOverlay)
|
|
379
474
|
return;
|
|
380
|
-
|
|
475
|
+
// Allow opens from everything vite itself is willing to serve
|
|
476
|
+
// (`server.fs.allow` defaults to the workspace root), not just
|
|
477
|
+
// `config.root` — in monorepos, component sources regularly live in
|
|
478
|
+
// sibling packages outside the served app's root.
|
|
479
|
+
const fsAllow = server.config.server.fs?.allow ?? [];
|
|
480
|
+
server.middlewares.use(OPEN_IN_EDITOR_PATH, createOpenInEditorMiddleware([root, ...fsAllow]));
|
|
381
481
|
},
|
|
382
482
|
transform(code, id, transformOptions) {
|
|
383
483
|
if (!resolved.sourceOverlay)
|
|
@@ -428,17 +528,9 @@ export const litPlugin = (options = {}) => {
|
|
|
428
528
|
const hmr = {
|
|
429
529
|
name: 'lit-plugin',
|
|
430
530
|
apply: 'serve',
|
|
431
|
-
config: (
|
|
432
|
-
//
|
|
433
|
-
// `
|
|
434
|
-
// merges in matching `process.env` keys, filtered to the `LIT_PLUGIN`
|
|
435
|
-
// prefix. Explicit options still win (handled in resolveOptions).
|
|
436
|
-
const envDir = viteConfig.envDir
|
|
437
|
-
? resolvePath(viteConfig.envDir)
|
|
438
|
-
: viteConfig.root
|
|
439
|
-
? resolvePath(viteConfig.root)
|
|
440
|
-
: process.cwd();
|
|
441
|
-
resolved = resolveOptions(options, loadEnv(mode, envDir, ENV_PREFIX));
|
|
531
|
+
config: () => {
|
|
532
|
+
// Options are already resolved against the loaded env by
|
|
533
|
+
// `lit-plugin-options`, which runs first.
|
|
442
534
|
if (!resolved.hmrEnabled) {
|
|
443
535
|
return;
|
|
444
536
|
}
|
|
@@ -578,7 +670,10 @@ export const litPlugin = (options = {}) => {
|
|
|
578
670
|
// feature is disabled (which env may decide), so inclusion can't be gated
|
|
579
671
|
// on the synchronously-known options here.
|
|
580
672
|
const plugins = [
|
|
581
|
-
|
|
673
|
+
optionsPlugin,
|
|
674
|
+
// Getter, not a snapshot: `resolved` is re-resolved against the loaded env
|
|
675
|
+
// in `optionsPlugin`'s `config` hook, which runs after this array is built.
|
|
676
|
+
litCssQueries(() => resolved.cssSheetBuild),
|
|
582
677
|
litCssLiterals(),
|
|
583
678
|
sourceOverlayPlugin,
|
|
584
679
|
hmr,
|