vite-plugin-css-position 2.1.1-next.1 → 3.0.0-next.1
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/README.md +44 -13
- package/dist/StylesTarget.types.d.ts +15 -4
- package/dist/StylesTargetReact.d.ts +13 -5
- package/dist/StylesTargetReact.js +1 -1
- package/dist/StylesTargetReact.js.map +1 -1
- package/dist/StylesTargetVue.vue +50 -12
- package/dist/index.d.ts +48 -13
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
[](https://www.npmjs.com/package/vite-plugin-css-position)
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
5
|
A Vite plugin that allows you to control where CSS stylesheets are injected in your React or Vue application. Perfect for scenarios where you need precise control over style placement, especially when working with Shadow DOM.
|
|
9
6
|
|
|
10
7
|
## Features
|
|
@@ -12,7 +9,6 @@ A Vite plugin that allows you to control where CSS stylesheets are injected in y
|
|
|
12
9
|
- **Custom CSS positioning** - Place stylesheets exactly where you need them in your component tree
|
|
13
10
|
- **Shadow DOM support** - Ideal for Shadow DOM implementations where styles need to be scoped
|
|
14
11
|
- **Component-level lazy-loading** - Optionally inject each (code-split) component's CSS only when it loads
|
|
15
|
-
- **Zero dependencies** - No runtime dependencies; the CSS-by-JS injection is built in
|
|
16
12
|
- **Development mode** - Optional hot module replacement support
|
|
17
13
|
|
|
18
14
|
## Installation
|
|
@@ -44,7 +40,7 @@ Add the plugin to your `vite.config.ts`:
|
|
|
44
40
|
import { viteCssPosition } from "vite-plugin-css-position";
|
|
45
41
|
|
|
46
42
|
export default defineConfig({
|
|
47
|
-
plugins: [react(), /* or vue(), */ viteCssPosition()],
|
|
43
|
+
plugins: [react(), /* or vue(), */ viteCssPosition({ cssPerChunk: true })],
|
|
48
44
|
});
|
|
49
45
|
```
|
|
50
46
|
|
|
@@ -90,22 +86,40 @@ The plugin accepts optional configuration:
|
|
|
90
86
|
```typescript
|
|
91
87
|
viteCssPosition({
|
|
92
88
|
enableDev: true,
|
|
93
|
-
|
|
89
|
+
mode: "cssChunks",
|
|
94
90
|
});
|
|
95
91
|
```
|
|
96
92
|
|
|
97
93
|
### Options
|
|
98
94
|
|
|
99
95
|
- **`instanceId`** - A custom identifier for the plugin instance. Useful when you have multiple instances or need to avoid conflicts. Defaults to a random UUID.
|
|
100
|
-
- **`enableDev`** - When `true`, enables CSS injection during development mode. Defaults to `false`. Enable this for HMR support
|
|
101
|
-
- **`
|
|
96
|
+
- **`enableDev`** - When `true`, enables CSS injection during development mode. Defaults to `false`. Enable this for HMR support.
|
|
97
|
+
- **`mode`** - How CSS is delivered and registered. Defaults to `"inject"`. See [Modes](#modes) below.
|
|
98
|
+
- **`cssChunksStrategy`** - Only used when `mode: "cssChunks"`. `"link"` (default) renders `<link rel="stylesheet">`; `"adopt"` fetches the CSS and applies it via `adoptedStyleSheets`. See [Modes](#modes).
|
|
102
99
|
- **`jsAssetsFilterFunction`** - Filter function `(chunk) => boolean` to control which JS output chunk(s) receive the CSS injection code. Useful with multiple entry points.
|
|
100
|
+
- **`cssPerChunk`** _(deprecated)_ - Use `mode` instead. `true` maps to `mode: "injectPerChunk"`, `false`/unset to `mode: "inject"`. Ignored when `mode` is set.
|
|
101
|
+
|
|
102
|
+
### Modes
|
|
103
|
+
|
|
104
|
+
`mode` controls how stylesheets reach the `StylesTarget` position:
|
|
105
|
+
|
|
106
|
+
| `mode` | CSS delivery | Rendered as | Lazy-loading |
|
|
107
|
+
| ---------------------- | ------------------------------------ | ------------------------------- | -------------------------- |
|
|
108
|
+
| `"inject"` _(default)_ | all CSS inlined into the entry JS | `<style>` | no — loaded up front |
|
|
109
|
+
| `"injectPerChunk"` | each chunk's CSS inlined into its JS | `<style>` | yes — per code-split chunk |
|
|
110
|
+
| `"cssChunks"` | Vite's emitted `.css` files are kept | `<link>` / `adoptedStyleSheets` | yes — per code-split chunk |
|
|
103
111
|
|
|
104
|
-
|
|
112
|
+
`"inject"` is the original behavior and fully backward compatible. The per-chunk modes require
|
|
113
|
+
`build.cssCodeSplit` (Vite's default; forced on automatically).
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
**`mode` only affects the production build.** In dev (`enableDev: true`) CSS is always injected
|
|
116
|
+
per-module for HMR.
|
|
117
|
+
|
|
118
|
+
#### Component-level lazy-loading (`injectPerChunk` / `cssChunks`)
|
|
119
|
+
|
|
120
|
+
With a per-chunk mode, styles imported by a dynamically imported component live with that
|
|
121
|
+
component's chunk and only reach the `StylesTarget` position once the component loads — ideal for
|
|
122
|
+
Shadow-DOM micro frontends that should not ship all CSS up front:
|
|
109
123
|
|
|
110
124
|
```tsx
|
|
111
125
|
import { Suspense, lazy } from "react";
|
|
@@ -118,13 +132,30 @@ export function App() {
|
|
|
118
132
|
<div>
|
|
119
133
|
<StylesTarget />
|
|
120
134
|
<Suspense fallback={null}>
|
|
121
|
-
<Chart /> {/* chart.css is
|
|
135
|
+
<Chart /> {/* chart.css is included only once this loads */}
|
|
122
136
|
</Suspense>
|
|
123
137
|
</div>
|
|
124
138
|
);
|
|
125
139
|
}
|
|
126
140
|
```
|
|
127
141
|
|
|
142
|
+
#### `cssChunks` mode — keep Vite's CSS files
|
|
143
|
+
|
|
144
|
+
`mode: "cssChunks"` keeps Vite's normal, cacheable `.css` chunk files instead of inlining CSS into
|
|
145
|
+
JavaScript, and only registers each chunk's CSS **URL**. `StylesTarget` then includes it at its
|
|
146
|
+
position (and the plugin suppresses Vite's default `<head>` injection). Benefits: HTTP-cacheable CSS,
|
|
147
|
+
leaner JS bundles, and CSP-friendliness (no inline styles).
|
|
148
|
+
|
|
149
|
+
The `cssChunksStrategy` option chooses how the CSS is included:
|
|
150
|
+
|
|
151
|
+
- **`"link"`** (default) — renders `<link rel="stylesheet">`. Simplest, but note that a `<link>`
|
|
152
|
+
inside a Shadow DOM is _not_ render-blocking, so a brief flash of unstyled content (FOUC) is
|
|
153
|
+
possible while it loads.
|
|
154
|
+
- **`"adopt"`** — fetches the CSS file and applies it via
|
|
155
|
+
[`adoptedStyleSheets`](https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets).
|
|
156
|
+
No FOUC, deduplicated across multiple shadow roots, and CSP-ideal. Requires `fetch` and a modern
|
|
157
|
+
browser (Chrome 73+ / Firefox 101+ / Safari 16.4+);
|
|
158
|
+
|
|
128
159
|
## Development
|
|
129
160
|
|
|
130
161
|
```bash
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/** A registered stylesheet — either inlined CSS (`inject*` modes) or a CSS file URL (`cssChunks` mode). */
|
|
2
|
+
export type StyleEntry = {
|
|
3
|
+
type?: "style";
|
|
4
|
+
css: string;
|
|
5
|
+
attributes: Record<string, string>;
|
|
6
|
+
} | {
|
|
7
|
+
type: "link";
|
|
8
|
+
href: string;
|
|
9
|
+
attributes: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
export type StylesMap = Map<string, StyleEntry>;
|
|
1
12
|
export interface StylesTargetProps {
|
|
2
|
-
onChange?: (stylesMap:
|
|
3
|
-
css: string;
|
|
4
|
-
attributes: Record<string, string>;
|
|
5
|
-
}>) => void;
|
|
13
|
+
onChange?: (stylesMap: StylesMap) => void;
|
|
6
14
|
}
|
|
15
|
+
export declare function isLinkEntry(entry: StyleEntry): entry is Extract<StyleEntry, {
|
|
16
|
+
type: "link";
|
|
17
|
+
}>;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/StylesTarget.types.d.ts
|
|
4
|
+
/** A registered stylesheet — either inlined CSS (`inject*` modes) or a CSS file URL (`cssChunks` mode). */
|
|
5
|
+
type StyleEntry = {
|
|
6
|
+
type?: "style";
|
|
7
|
+
css: string;
|
|
8
|
+
attributes: Record<string, string>;
|
|
9
|
+
} | {
|
|
10
|
+
type: "link";
|
|
11
|
+
href: string;
|
|
12
|
+
attributes: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
type StylesMap = Map<string, StyleEntry>;
|
|
4
15
|
interface StylesTargetProps {
|
|
5
|
-
onChange?: (stylesMap:
|
|
6
|
-
css: string;
|
|
7
|
-
attributes: Record<string, string>;
|
|
8
|
-
}>) => void;
|
|
16
|
+
onChange?: (stylesMap: StylesMap) => void;
|
|
9
17
|
}
|
|
10
18
|
//#endregion
|
|
11
19
|
//#region src/StylesTargetReact.d.ts
|
|
12
|
-
declare const StylesTarget: (props: StylesTargetProps) =>
|
|
20
|
+
declare const StylesTarget: (props: StylesTargetProps) => react_jsx_runtime0.JSX.Element;
|
|
13
21
|
//#endregion
|
|
14
22
|
export { StylesTarget as default };
|
|
15
23
|
//# sourceMappingURL=StylesTargetReact.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createElement as e,useEffect as t,useState as
|
|
1
|
+
import{createElement as e,useEffect as t,useRef as n,useState as r}from"react";import{Fragment as i,jsx as a,jsxs as o}from"react/jsx-runtime";function s(e){return e.type===`link`}const c=__VITE_CSS_POS_GLOBAL_VAR_NAME__,l=__VITE_CSS_POS_EVENT_NAME__,u=__VITE_CSS_POS_LINK_STRATEGY__,d=()=>window[c];var f=c=>{let[f,p]=r(d()||new Map),[m,h]=r(0),g=n(null),_=n(new Map);t(()=>{let e=()=>{let e=d()||new Map;p(e),h(e=>e+1),c.onChange?.(e)};return window.addEventListener(l,e),e(),()=>{window.removeEventListener(l,e)}},[c.onChange]);let v=Array.from(f?.entries()||[]);return t(()=>{if(u!==`adopt`)return;let e=g.current;if(!e)return;let t=e.getRootNode();if(!(`adoptedStyleSheets`in t))return;let n=!1,r=_.current,i=v.filter(([,e])=>s(e)).map(([,e])=>e.href);return Promise.all(i.map(async e=>{if(r.has(e))return;let t=new CSSStyleSheet;t.replaceSync(await(await fetch(e)).text()),r.set(e,t)})).then(()=>{if(n)return;let e=i.map(e=>r.get(e)).filter(Boolean),a=t.adoptedStyleSheets,o=e.filter(e=>!a.includes(e));o.length&&(t.adoptedStyleSheets=[...a,...o])}),()=>{n=!0}},[m]),o(i,{children:[v.map(([t,n])=>s(n)?u===`adopt`?null:a(`link`,{rel:`stylesheet`,href:n.href,...n.attributes},t):e(`style`,{...n.attributes,key:`${t}-${m}`},n.css)),u===`adopt`?a(`span`,{ref:g,style:{display:`none`},"aria-hidden":`true`}):null]})};export{f as default};
|
|
2
2
|
//# sourceMappingURL=StylesTargetReact.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StylesTargetReact.js","names":[],"sources":["../src/StylesTargetReact.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { StylesTargetProps } from \"./StylesTarget.types\";\n\ndeclare const __VITE_CSS_POS_GLOBAL_VAR_NAME__: string;\ndeclare const __VITE_CSS_POS_EVENT_NAME__: string;\n\nconst globalVarName = __VITE_CSS_POS_GLOBAL_VAR_NAME__;\nconst eventName = __VITE_CSS_POS_EVENT_NAME__;\n\nconst getCurrent = () => (window as any)[globalVarName];\n\nconst StylesTarget = (props: StylesTargetProps) => {\n const [stylesMap, setStylesMap] = useState
|
|
1
|
+
{"version":3,"file":"StylesTargetReact.js","names":[],"sources":["../src/StylesTarget.types.ts","../src/StylesTargetReact.tsx"],"sourcesContent":["/** A registered stylesheet — either inlined CSS (`inject*` modes) or a CSS file URL (`cssChunks` mode). */\nexport type StyleEntry =\n | { type?: \"style\"; css: string; attributes: Record<string, string> }\n | { type: \"link\"; href: string; attributes: Record<string, string> };\n\nexport type StylesMap = Map<string, StyleEntry>;\n\nexport interface StylesTargetProps {\n onChange?: (stylesMap: StylesMap) => void;\n}\n\nexport function isLinkEntry(entry: StyleEntry): entry is Extract<StyleEntry, { type: \"link\" }> {\n return entry.type === \"link\";\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { StyleEntry, StylesMap, StylesTargetProps } from \"./StylesTarget.types\";\nimport { isLinkEntry } from \"./StylesTarget.types\";\n\ndeclare const __VITE_CSS_POS_GLOBAL_VAR_NAME__: string;\ndeclare const __VITE_CSS_POS_EVENT_NAME__: string;\ndeclare const __VITE_CSS_POS_LINK_STRATEGY__: \"link\" | \"adopt\";\n\nconst globalVarName = __VITE_CSS_POS_GLOBAL_VAR_NAME__;\nconst eventName = __VITE_CSS_POS_EVENT_NAME__;\nconst linkStrategy = __VITE_CSS_POS_LINK_STRATEGY__;\n\nconst getCurrent = (): StylesMap | undefined => (window as any)[globalVarName];\n\ntype LinkEntry = Extract<StyleEntry, { type: \"link\" }>;\n\nconst StylesTarget = (props: StylesTargetProps) => {\n const [stylesMap, setStylesMap] = useState<StylesMap>(getCurrent() || new Map());\n const [version, setVersion] = useState(0);\n\n const anchorRef = useRef<HTMLSpanElement>(null);\n // Cache constructed sheets per href so the same file is parsed once.\n const adoptedRef = useRef<Map<string, CSSStyleSheet>>(new Map());\n\n useEffect(() => {\n const updateListener = () => {\n const newValues = getCurrent() || new Map();\n setStylesMap(newValues);\n setVersion((v) => v + 1);\n props.onChange?.(newValues);\n };\n window.addEventListener(eventName, updateListener);\n updateListener();\n return () => {\n window.removeEventListener(eventName, updateListener);\n };\n }, [props.onChange]);\n\n const entries = Array.from(stylesMap?.entries() || []);\n\n // `cssChunks` + \"adopt\": fetch each CSS file and apply it to the containing\n // (shadow) root via adoptedStyleSheets — no FOUC, deduped across roots.\n useEffect(() => {\n if (linkStrategy !== \"adopt\") return;\n const anchor = anchorRef.current;\n if (!anchor) return;\n const root = anchor.getRootNode() as ShadowRoot;\n if (!(\"adoptedStyleSheets\" in root)) return;\n\n let cancelled = false;\n const cache = adoptedRef.current;\n const hrefs = entries.filter(([, e]) => isLinkEntry(e)).map(([, e]) => (e as LinkEntry).href);\n\n void Promise.all(\n hrefs.map(async (href) => {\n if (cache.has(href)) return;\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(await (await fetch(href)).text());\n cache.set(href, sheet);\n })\n ).then(() => {\n if (cancelled) return;\n const desired = hrefs.map((h) => cache.get(h)).filter(Boolean) as CSSStyleSheet[];\n const existing = root.adoptedStyleSheets;\n const toAdd = desired.filter((s) => !existing.includes(s));\n if (toAdd.length) root.adoptedStyleSheets = [...existing, ...toAdd];\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [version]);\n\n return (\n <>\n {entries.map(([key, entry]) => {\n if (isLinkEntry(entry)) {\n if (linkStrategy === \"adopt\") return null;\n return <link key={key} rel=\"stylesheet\" href={entry.href} {...entry.attributes} />;\n }\n return (\n <style {...entry.attributes} key={`${key}-${version}`}>\n {entry.css}\n </style>\n );\n })}\n {linkStrategy === \"adopt\" ? (\n <span ref={anchorRef} style={{ display: \"none\" }} aria-hidden=\"true\" />\n ) : null}\n </>\n );\n};\n\nexport default StylesTarget;\n"],"mappings":"+IAWA,SAAgB,EAAY,EAAmE,CAC7F,OAAO,EAAM,OAAS,OCJxB,MAAM,EAAgB,iCAChB,EAAY,4BACZ,EAAe,+BAEf,MAA2C,OAAe,GAkFhE,IAAA,EA9EsB,GAA6B,CACjD,GAAM,CAAC,EAAW,GAAgB,EAAoB,GAAY,EAAI,IAAI,IAAM,CAC1E,CAAC,EAAS,GAAc,EAAS,EAAE,CAEnC,EAAY,EAAwB,KAAK,CAEzC,EAAa,EAAmC,IAAI,IAAM,CAEhE,MAAgB,CACd,IAAM,MAAuB,CAC3B,IAAM,EAAY,GAAY,EAAI,IAAI,IACtC,EAAa,EAAU,CACvB,EAAY,GAAM,EAAI,EAAE,CACxB,EAAM,WAAW,EAAU,EAI7B,OAFA,OAAO,iBAAiB,EAAW,EAAe,CAClD,GAAgB,KACH,CACX,OAAO,oBAAoB,EAAW,EAAe,GAEtD,CAAC,EAAM,SAAS,CAAC,CAEpB,IAAM,EAAU,MAAM,KAAK,GAAW,SAAS,EAAI,EAAE,CAAC,CAoCtD,OAhCA,MAAgB,CACd,GAAI,IAAiB,QAAS,OAC9B,IAAM,EAAS,EAAU,QACzB,GAAI,CAAC,EAAQ,OACb,IAAM,EAAO,EAAO,aAAa,CACjC,GAAI,EAAE,uBAAwB,GAAO,OAErC,IAAI,EAAY,GACV,EAAQ,EAAW,QACnB,EAAQ,EAAQ,QAAQ,EAAG,KAAO,EAAY,EAAE,CAAC,CAAC,KAAK,EAAG,KAAQ,EAAgB,KAAK,CAiB7F,OAfK,QAAQ,IACX,EAAM,IAAI,KAAO,IAAS,CACxB,GAAI,EAAM,IAAI,EAAK,CAAE,OACrB,IAAM,EAAQ,IAAI,cAClB,EAAM,YAAY,MAAO,MAAM,MAAM,EAAK,EAAE,MAAM,CAAC,CACnD,EAAM,IAAI,EAAM,EAAM,EACtB,CACH,CAAC,SAAW,CACX,GAAI,EAAW,OACf,IAAM,EAAU,EAAM,IAAK,GAAM,EAAM,IAAI,EAAE,CAAC,CAAC,OAAO,QAAQ,CACxD,EAAW,EAAK,mBAChB,EAAQ,EAAQ,OAAQ,GAAM,CAAC,EAAS,SAAS,EAAE,CAAC,CACtD,EAAM,SAAQ,EAAK,mBAAqB,CAAC,GAAG,EAAU,GAAG,EAAM,GACnE,KAEW,CACX,EAAY,KAGb,CAAC,EAAQ,CAAC,CAGX,EAAA,EAAA,CAAA,SAAA,CACG,EAAQ,KAAK,CAAC,EAAK,KACd,EAAY,EAAM,CAChB,IAAiB,QAAgB,KAC9B,EAAC,OAAA,CAAe,IAAI,aAAa,KAAM,EAAM,KAAM,GAAI,EAAM,YAAlD,EAAgE,CAGlF,EAAC,QAAA,CAAM,GAAI,EAAM,WAAY,IAAK,GAAG,EAAI,GAAG,KACzC,EAAM,IACD,CAEV,CACD,IAAiB,QAChB,EAAC,OAAA,CAAK,IAAK,EAAW,MAAO,CAAE,QAAS,OAAQ,CAAE,cAAY,QAAS,CACrE,KAAA,CAAA,CACH"}
|
package/dist/StylesTargetVue.vue
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { defineComponent, ref, h, onMounted, onUnmounted } from "vue";
|
|
3
|
-
import type { StylesTargetProps } from "./StylesTarget.types";
|
|
2
|
+
import { defineComponent, ref, h, onMounted, onUnmounted, watch } from "vue";
|
|
3
|
+
import type { StyleEntry, StylesMap, StylesTargetProps } from "./StylesTarget.types";
|
|
4
|
+
import { isLinkEntry } from "./StylesTarget.types";
|
|
4
5
|
|
|
5
6
|
declare const __VITE_CSS_POS_GLOBAL_VAR_NAME__: string;
|
|
6
7
|
declare const __VITE_CSS_POS_EVENT_NAME__: string;
|
|
8
|
+
declare const __VITE_CSS_POS_LINK_STRATEGY__: "link" | "adopt";
|
|
7
9
|
|
|
8
10
|
const globalVarName = __VITE_CSS_POS_GLOBAL_VAR_NAME__;
|
|
9
11
|
const eventName = __VITE_CSS_POS_EVENT_NAME__;
|
|
12
|
+
const linkStrategy = __VITE_CSS_POS_LINK_STRATEGY__;
|
|
10
13
|
|
|
11
|
-
const getCurrent = () => (window as any)[globalVarName];
|
|
14
|
+
const getCurrent = (): StylesMap | undefined => (window as any)[globalVarName];
|
|
15
|
+
|
|
16
|
+
type LinkEntry = Extract<StyleEntry, { type: "link" }>;
|
|
12
17
|
|
|
13
18
|
export default defineComponent({
|
|
14
19
|
name: "StylesTarget",
|
|
@@ -19,33 +24,66 @@ export default defineComponent({
|
|
|
19
24
|
},
|
|
20
25
|
},
|
|
21
26
|
setup(props) {
|
|
22
|
-
const stylesMap = ref<
|
|
23
|
-
getCurrent() || new Map()
|
|
24
|
-
);
|
|
27
|
+
const stylesMap = ref<StylesMap>(getCurrent() || new Map());
|
|
25
28
|
const version = ref(0);
|
|
29
|
+
const anchor = ref<HTMLSpanElement | null>(null);
|
|
30
|
+
// Cache constructed sheets per href so the same file is parsed once.
|
|
31
|
+
const adopted = new Map<string, CSSStyleSheet>();
|
|
26
32
|
|
|
27
|
-
const updateListener = (
|
|
33
|
+
const updateListener = () => {
|
|
28
34
|
const newValues = getCurrent() || new Map();
|
|
29
35
|
stylesMap.value = newValues;
|
|
30
36
|
version.value++;
|
|
31
37
|
(props.onChange as StylesTargetProps["onChange"])?.(newValues);
|
|
32
38
|
};
|
|
33
39
|
|
|
40
|
+
// `cssChunks` + "adopt": fetch each CSS file and apply it to the containing
|
|
41
|
+
// (shadow) root via adoptedStyleSheets — no FOUC, deduped across roots.
|
|
42
|
+
const applyAdopted = () => {
|
|
43
|
+
if (linkStrategy !== "adopt") return;
|
|
44
|
+
const el = anchor.value;
|
|
45
|
+
if (!el) return;
|
|
46
|
+
const root = el.getRootNode() as ShadowRoot;
|
|
47
|
+
if (!("adoptedStyleSheets" in root)) return;
|
|
48
|
+
const hrefs = Array.from(stylesMap.value?.values() || [])
|
|
49
|
+
.filter(isLinkEntry)
|
|
50
|
+
.map((e: LinkEntry) => e.href);
|
|
51
|
+
void Promise.all(
|
|
52
|
+
hrefs.map(async (href) => {
|
|
53
|
+
if (adopted.has(href)) return;
|
|
54
|
+
const sheet = new CSSStyleSheet();
|
|
55
|
+
sheet.replaceSync(await (await fetch(href)).text());
|
|
56
|
+
adopted.set(href, sheet);
|
|
57
|
+
})
|
|
58
|
+
).then(() => {
|
|
59
|
+
const desired = hrefs.map((h) => adopted.get(h)).filter(Boolean) as CSSStyleSheet[];
|
|
60
|
+
const existing = root.adoptedStyleSheets;
|
|
61
|
+
const toAdd = desired.filter((s) => !existing.includes(s));
|
|
62
|
+
if (toAdd.length) root.adoptedStyleSheets = [...existing, ...toAdd];
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
34
66
|
onMounted(() => {
|
|
35
67
|
window.addEventListener(eventName, updateListener);
|
|
36
|
-
updateListener(
|
|
68
|
+
updateListener();
|
|
37
69
|
});
|
|
38
|
-
|
|
39
70
|
onUnmounted(() => {
|
|
40
71
|
window.removeEventListener(eventName, updateListener);
|
|
41
72
|
});
|
|
73
|
+
watch(version, () => applyAdopted(), { flush: "post" });
|
|
42
74
|
|
|
43
75
|
return () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
76
|
+
const nodes = Array.from(stylesMap.value?.entries() || []).map(([key, entry]) => {
|
|
77
|
+
if (isLinkEntry(entry)) {
|
|
78
|
+
if (linkStrategy === "adopt") return null;
|
|
79
|
+
return h("link", { key, rel: "stylesheet", href: entry.href, ...entry.attributes });
|
|
80
|
+
}
|
|
47
81
|
return h("style", { key: `${key}-${version.value}`, ...entry.attributes }, entry.css);
|
|
48
82
|
});
|
|
83
|
+
if (linkStrategy === "adopt") {
|
|
84
|
+
nodes.push(h("span", { ref: anchor, style: "display:none", "aria-hidden": "true" }));
|
|
85
|
+
}
|
|
86
|
+
return nodes;
|
|
49
87
|
};
|
|
50
88
|
},
|
|
51
89
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -2,21 +2,12 @@ import { Plugin, Rollup } from "vite";
|
|
|
2
2
|
|
|
3
3
|
//#region src/viteCustomCssPosition.d.ts
|
|
4
4
|
type JsAssetsFilterFunction = (chunk: Rollup.OutputChunk) => boolean;
|
|
5
|
-
|
|
5
|
+
/** How `StylesTarget` includes CSS files in `cssChunks` mode. */
|
|
6
|
+
type CssChunksStrategy = "link" | "adopt";
|
|
7
|
+
/** Options shared by every mode. */
|
|
8
|
+
interface BaseCssPositionOptions {
|
|
6
9
|
instanceId?: string;
|
|
7
10
|
enableDev?: boolean;
|
|
8
|
-
/**
|
|
9
|
-
* Inject each (including lazily loaded) chunk's CSS relative to that chunk
|
|
10
|
-
* instead of bundling all CSS into the entry. Enables component-level granular
|
|
11
|
-
* lazy-loading of stylesheets: a code-split component's styles are only injected
|
|
12
|
-
* when the component is actually loaded.
|
|
13
|
-
*
|
|
14
|
-
* `false` (default) keeps the previous behavior (all CSS in the entry, loaded
|
|
15
|
-
* up front) and is fully backward compatible.
|
|
16
|
-
*
|
|
17
|
-
* @default false
|
|
18
|
-
*/
|
|
19
|
-
lazy?: boolean;
|
|
20
11
|
/**
|
|
21
12
|
* Filter function to determine which JS file(s) should receive the CSS injection code.
|
|
22
13
|
* Useful when building multiple entry points and you want CSS only in specific entries.
|
|
@@ -25,6 +16,50 @@ interface ViteCustomCssPositionOptions {
|
|
|
25
16
|
*/
|
|
26
17
|
jsAssetsFilterFunction?: JsAssetsFilterFunction;
|
|
27
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Mode-specific options. A discriminated union so that `cssChunksStrategy` is
|
|
21
|
+
* only assignable when `mode: "cssChunks"`, and the deprecated `cssPerChunk` is
|
|
22
|
+
* only assignable for the inline-inject modes.
|
|
23
|
+
*/
|
|
24
|
+
type ModeCssPositionOptions = {
|
|
25
|
+
/**
|
|
26
|
+
* How CSS is delivered and registered:
|
|
27
|
+
* - `"inject"` (default): all CSS is concatenated and inlined into the entry
|
|
28
|
+
* JS, registered as `<style>`. The previous default behavior.
|
|
29
|
+
* - `"injectPerChunk"`: each chunk's CSS is inlined into its JS, registered
|
|
30
|
+
* as `<style>` — component-level granular lazy-loading via inlined styles.
|
|
31
|
+
*
|
|
32
|
+
* @default "inject"
|
|
33
|
+
*/
|
|
34
|
+
mode?: "inject" | "injectPerChunk";
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use `mode` instead. `true` maps to `mode: "injectPerChunk"`,
|
|
37
|
+
* `false`/unset to `mode: "inject"`. Ignored when `mode` is set.
|
|
38
|
+
*/
|
|
39
|
+
cssPerChunk?: boolean;
|
|
40
|
+
/** Only valid with `mode: "cssChunks"`. */
|
|
41
|
+
cssChunksStrategy?: never;
|
|
42
|
+
} | {
|
|
43
|
+
/**
|
|
44
|
+
* `"cssChunks"`: Vite's emitted `.css` chunk files are kept; each chunk only
|
|
45
|
+
* registers its CSS file URL, and `StylesTarget` links/adopts it at its
|
|
46
|
+
* position. Closest to standard Vite (cacheable files, lean JS, CSP-friendly).
|
|
47
|
+
*/
|
|
48
|
+
mode: "cssChunks";
|
|
49
|
+
/**
|
|
50
|
+
* How `StylesTarget` includes the CSS file:
|
|
51
|
+
* - `"link"` (default): render `<link rel="stylesheet">`. Simple; may FOUC in
|
|
52
|
+
* Shadow DOM (link is not render-blocking there).
|
|
53
|
+
* - `"adopt"`: fetch the CSS and apply it via `adoptedStyleSheets`. No FOUC,
|
|
54
|
+
* CSP-ideal, dedup across roots; requires `fetch` + modern browsers (2023+).
|
|
55
|
+
*
|
|
56
|
+
* @default "link"
|
|
57
|
+
*/
|
|
58
|
+
cssChunksStrategy?: CssChunksStrategy;
|
|
59
|
+
/** Not applicable in `cssChunks` mode. */
|
|
60
|
+
cssPerChunk?: never;
|
|
61
|
+
};
|
|
62
|
+
type ViteCustomCssPositionOptions = BaseCssPositionOptions & ModeCssPositionOptions;
|
|
28
63
|
declare function viteCustomCssPosition(options?: ViteCustomCssPositionOptions): Plugin | Plugin[];
|
|
29
64
|
//#endregion
|
|
30
65
|
export { type ViteCustomCssPositionOptions, viteCustomCssPosition as viteCssPosition, viteCustomCssPosition as viteReactCssPosition };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{hash as e,randomUUID as t}from"crypto";function
|
|
1
|
+
import{hash as e,randomUUID as t}from"crypto";import{posix as n}from"node:path";function r(e){return e.viteMetadata?.importedCss}function i(e){console.warn(`\x1b[33m \n${e} \x1b[39m`)}function a(t,n,r,i){let a=JSON.stringify(i||{});return`(()=>{${`const css = ${r};const id = ${`"${i?.[`data-vite-dev-id`]??e(`sha1`,r).substring(0,12)}"`};const attributes = JSON.parse('${a}');window.${t} = window.${t} || new Map();window.${t}.set(id, {type:"style", css, attributes});window.dispatchEvent( new Event('${n}') );`}})();`}function o(e,t,n){return`(()=>{const items=${JSON.stringify(n.map(e=>[e.id,e.rel]))};window.${e}=window.${e}||new Map();for(const [id,rel] of items){window.${e}.set(id,{type:"link",href:new URL(rel,import.meta.url).href,attributes:{}});}window.dispatchEvent(new Event('${t}'));})();`}function s(e,t,n){return`(() => {
|
|
2
2
|
if(window.${e} && window.${e}.has('${n}')) {
|
|
3
3
|
window.${e}.delete('${n}');
|
|
4
4
|
window.dispatchEvent( new Event('${t}') );
|
|
5
5
|
}
|
|
6
|
-
})()`}const
|
|
7
|
-
`+
|
|
8
|
-
`+
|
|
6
|
+
})()`}const c={};function l(e,t){let n=e[t];if(n!==void 0&&n.source){let e=n.source;c[t]=e instanceof Uint8Array?new TextDecoder().decode(e):`${e}`}return c[t]??``}function u(e,t){return t.reduce((t,n)=>{let r=l(e,n);return delete e[n],t+r},``)}function d(e){return e.type==`chunk`&&e.fileName.match(/.[cm]?js(?:\?.+)?$/)!=null}function f(e){return e.isEntry&&!e.fileName.includes(`polyfill`)}function p(e,t){if(typeof t!=`function`){let t=Object.keys(e).filter(t=>{let n=e[t];return n!==void 0&&d(n)&&f(n)}),n=t[t.length-1];return n===void 0?[]:(t.length>1&&i(`[vite-plugin-css-position] identified "${n}" as one of multiple "entry" output files to put the CSS injection code. If this is not the intended file, use the "jsAssetsFilterFunction" option to specify the desired output file.`),[n])}return Object.entries(e).filter(([,e])=>d(e)&&t(e)).map(([e])=>e)}function m(e,t){let n={},i=p(e,typeof t==`function`?t:()=>!0);if(i.length===0)throw Error(`Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.`);for(let t of i){let i=e[t];if(i===void 0||i.type===`asset`)continue;let a=r(i);if(!a||a.size===0)continue;let o=n[t]||[];o.push(...a.values()),n[t]=o}return n}function h(e,t,n){let r=e.replace(/\/\*\s*empty css\s*\*\//g,``);return e=n?``:r,e+=t,e+=n?r:``,e}function g(e,t){for(let n in e){let r=e[n];if(r===void 0||r.type!==`chunk`)continue;let i=r.viteMetadata;i&&i.importedCss.size>0&&i.importedCss.forEach(e=>{t.includes(e)||(i.importedCss=new Set)})}}function _(e,t){let n=RegExp(`<link rel=".*"[^>]*?href=".*/?${t}"[^>]*?>`);return e.replace(n,``)}function v(e){return/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/.test(e)}function y(e,t,n){for(let[r,i]of Object.entries(t)){let t=u(e,i),a=t.length>0?n(t):``,o=e[r];o.code=h(o.code,a,!0)}}const b=new Map;let x=``;function S(e,t,n,r){let i=p(e,r);if(i.length==0)throw Error(`Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.`);let a=u(e,t),o=a.length>0?n(a):``;for(let t of i){let n=e[t];n.facadeModuleId!=null&&n.isEntry&&o!=``&&(n.facadeModuleId!=x&&b.clear(),x=n.facadeModuleId,b.set(n.facadeModuleId,o)),o==``&&n.isEntry&&n.facadeModuleId!=null&&typeof b.get(n.facadeModuleId)==`string`&&(o=b.get(n.facadeModuleId)),n.code=h(n.code,o,!0)}}function C(e){return e.startsWith(`.`)?e:`./`+e}function w(t,r,i,a){for(let[s,c]of Object.entries(r)){let r=t[s],l=n.dirname(r.fileName),u=o(i,a,c.map(t=>({id:e(`sha1`,t).substring(0,12),rel:C(n.relative(l,t))})));r.code=h(r.code,u,!0)}}function T(e){let t=e.match(/m\.f=\[([^\]]*)\]/);if(!t||t[1]===void 0)return e;let n=[...t[1].matchAll(/"((?:[^"\\]|\\.)*)"/g)].map(e=>e[1]),r=new Set;return n.forEach((e,t)=>{e!==void 0&&e.endsWith(`.css`)&&r.add(t)}),r.size===0?e:e.replace(/__vite__mapDeps\(\[([^\]]*)\]\)/g,(e,t)=>`__vite__mapDeps([${t.split(`,`).map(e=>e.trim()).filter(e=>e!==``&&!r.has(Number(e))).join(`,`)}])`)}function E(e){let{globalVarName:t,eventName:n,mode:r,jsAssetsFilterFunction:o}=e,c=r===`injectPerChunk`||r===`cssChunks`,l,u=[{apply:`build`,enforce:`post`,name:`vite-plugin-css-position-injection`,config(e,t){t.command===`build`&&c&&(e.build??={},e.build.cssCodeSplit===!1&&i(`[vite-plugin-css-position] Override of 'build.cssCodeSplit' to true; it must be true when mode is '${r}'.`),e.build.cssCodeSplit=!0)},configResolved(e){l=e},generateBundle(e,s){if(l.build.ssr)return;let c=Object.keys(s).filter(e=>{let t=s[e];return t!==void 0&&t.type==`asset`&&t.fileName.endsWith(`.css`)}),u=[];if(r===`cssChunks`)w(s,m(s,o),t,n);else{let e=e=>a(t,n,JSON.stringify(e.trim()));r===`injectPerChunk`?(y(s,m(s,o),e),u=c.filter(e=>!!s[e]),u.length>0&&i(`[vite-plugin-css-position] Some CSS assets were not included in any known JS: ${u.join(`,`)}`)):S(s,c,e,o),g(s,u)}let d=Object.keys(s).filter(e=>e.endsWith(`.html`));for(let e of d){let t=s[e],n=t.source instanceof Uint8Array?new TextDecoder().decode(t.source):`${t.source}`;c.forEach(e=>{u.includes(e)||(n=_(n,e),t.source=n)})}}}];return r===`cssChunks`&&u.push({apply:`build`,enforce:`post`,name:`vite-plugin-css-position-preload-strip`,generateBundle:{order:`post`,handler(e,t){for(let e of Object.keys(t)){let n=t[e];n!==void 0&&n.type===`chunk`&&(n.code=T(n.code))}}}}),e.enableDev&&(i(`[vite-plugin-css-position] Experimental dev mode activated!`),u.push({name:`vite-plugin-css-position-injection-dev`,apply:`serve`,enforce:`post`,transform(e,r){if(!v(r))return;let i=s(t,n,r),o=a(t,n,`__vite__css`,{type:`text/css`,"data-vite-dev-id":r}),c=e.replace(`__vite__updateStyle(__vite__id, __vite__css)`,`;
|
|
7
|
+
`+i+`;
|
|
8
|
+
`+o);return c=c.replace(`__vite__removeStyle(__vite__id)`,i),{code:c,map:null}}})),u}function D(e){return e?.mode?(e.cssPerChunk!==void 0&&console.warn(`[vite-plugin-css-position] Both 'mode' and the deprecated 'cssPerChunk' are set; 'mode' wins.`),e.mode):e?.cssPerChunk?`injectPerChunk`:`inject`}function O(e){let n=e?.instanceId||t().replace(/-/g,``).slice(0,4),r=`__vcssp_c_${n}`,i=`__vcssp_e_${n}`,a=e?.cssChunksStrategy??`link`;return[{name:`vite-plugin-custom-css-position`,config(e){return{...e,define:{...e.define,__VITE_CSS_POS_GLOBAL_VAR_NAME__:JSON.stringify(r),__VITE_CSS_POS_EVENT_NAME__:JSON.stringify(i),__VITE_CSS_POS_LINK_STRATEGY__:JSON.stringify(a)}}}},...E({globalVarName:r,eventName:i,enableDev:e?.enableDev??!1,mode:D(e),jsAssetsFilterFunction:e?.jsAssetsFilterFunction})]}export{O as viteCssPosition,O as viteReactCssPosition};
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["cssSourceCache: Record<string, string>","chunksWithCss: Record<string, string[]>","config: ResolvedConfig","plugins: Plugin[]","unusedCssAssets: string[]"],"sources":["../src/cssInjection.ts","../src/viteCustomCssPosition.ts"],"sourcesContent":["/**\n * CSS-by-JS injection core, vendored and trimmed from\n * `vite-plugin-css-injected-by-js` (v3.5.2) by Marco Prontera.\n *\n * Original: https://github.com/marco-prontera/vite-plugin-css-injected-by-js\n * Licensed under the MIT License — Copyright (c) 2023 Marco Prontera.\n *\n * This is a focused port: instead of creating `<style>` elements directly, the\n * generated injection code stores the CSS into a global Map and dispatches an\n * event, which the `StylesTarget` component reacts to in order to render the\n * styles at a custom position (e.g. inside a Shadow DOM). Unlike the original it\n * does NOT run a nested Vite build to produce the injection code; the snippet is\n * built directly and wrapped in an IIFE.\n */\nimport { hash } from \"crypto\";\nimport type { Plugin, ResolvedConfig, Rollup } from \"vite\";\n\nexport interface CssInjectionOptions {\n /** Name of the global variable holding the styles Map. */\n globalVarName: string;\n /** Name of the window event dispatched on style updates. */\n eventName: string;\n /** Enable the experimental dev-mode (HMR) transform. */\n enableDev: boolean;\n /**\n * Inject CSS relative to each JS chunk (incl. lazily loaded ones) instead of\n * concatenating everything into the entry chunk. Enables component-level\n * granular lazy-loading of stylesheets.\n */\n relative: boolean;\n /** Filter which JS chunks receive the CSS injection code. */\n jsAssetsFilterFunction?: ((chunk: Rollup.OutputChunk) => boolean) | undefined;\n}\n\n// CSS is injected before the rest of the chunk's code (parity with the original\n// plugin's default `topExecutionPriority: true`).\nconst TOP_EXECUTION_PRIORITY = true;\n\n// `viteMetadata.importedCss` is a Vite augmentation of Rollup's chunk type that\n// isn't surfaced through Vite's re-exported `Rollup` namespace; access it via a\n// local typed view.\ntype ChunkWithCssMeta = Rollup.OutputChunk & {\n viteMetadata?: { importedCss: Set<string> };\n};\n\nfunction importedCssOf(chunk: Rollup.OutputChunk): Set<string> | undefined {\n return (chunk as ChunkWithCssMeta).viteMetadata?.importedCss;\n}\n\nfunction warnLog(msg: string): void {\n console.warn(`\\x1b[33m \\n${msg} \\x1b[39m`);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Injection code generation */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Build the runtime snippet that registers the given CSS in the global Map and\n * notifies listeners. Wrapped in an IIFE so the local `const`s don't leak into\n * (or collide within) the chunk scope it is appended to.\n *\n * @param cssCodeExpr A JS expression evaluating to the CSS string. In build mode\n * this is a JSON string literal; in dev mode it's the `__vite__css` variable.\n * @param attributes Attributes to attach to the rendered `<style>` (dev only).\n */\nfunction buildInjectionCode(\n globalVarName: string,\n eventName: string,\n cssCodeExpr: string,\n attributes?: Record<string, string>\n): string {\n const attributesString = JSON.stringify(attributes || {});\n const id = `\"${\n attributes?.[\"data-vite-dev-id\"] ?? hash(\"sha1\", cssCodeExpr).substring(0, 12)\n }\"`;\n const body =\n `const css = ${cssCodeExpr};const id = ${id};const attributes = JSON.parse('${attributesString}');` +\n `window.${globalVarName} = window.${globalVarName} || new Map();` +\n `window.${globalVarName}.set(id, {css, attributes});` +\n `window.dispatchEvent( new Event('${eventName}') );`;\n return `(()=>{${body}})();`;\n}\n\n/** Code executed (dev mode) to remove a previously injected style on HMR update. */\nfunction buildRemoveStyleCode(globalVarName: string, eventName: string, id: string): string {\n return `(() => {\n if(window.${globalVarName} && window.${globalVarName}.has('${id}')) {\n window.${globalVarName}.delete('${id}');\n window.dispatchEvent( new Event('${eventName}') );\n }\n })()`;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Bundle helpers (ported from vite-plugin-css-injected-by-js utils) */\n/* -------------------------------------------------------------------------- */\n\n// The cache must be global since the execution context differs per entry.\nconst cssSourceCache: Record<string, string> = {};\n\nfunction extractCss(bundle: Rollup.OutputBundle, cssName: string): string {\n const cssAsset = bundle[cssName] as Rollup.OutputAsset | undefined;\n if (cssAsset !== undefined && cssAsset.source) {\n const cssSource = cssAsset.source;\n cssSourceCache[cssName] =\n cssSource instanceof Uint8Array ? new TextDecoder().decode(cssSource) : `${cssSource}`;\n }\n return cssSourceCache[cssName] ?? \"\";\n}\n\nfunction concatCssAndDeleteFromBundle(bundle: Rollup.OutputBundle, cssAssets: string[]): string {\n return cssAssets.reduce((previous, cssName) => {\n const cssSource = extractCss(bundle, cssName);\n delete bundle[cssName];\n return previous + cssSource;\n }, \"\");\n}\n\nfunction isJsOutputChunk(chunk: Rollup.OutputAsset | Rollup.OutputChunk): chunk is Rollup.OutputChunk {\n return chunk.type == \"chunk\" && chunk.fileName.match(/.[cm]?js(?:\\?.+)?$/) != null;\n}\n\nfunction defaultJsAssetsFilter(chunk: Rollup.OutputChunk): boolean {\n return chunk.isEntry && !chunk.fileName.includes(\"polyfill\");\n}\n\nfunction getJsTargetBundleKeys(\n bundle: Rollup.OutputBundle,\n jsAssetsFilterFunction?: (chunk: Rollup.OutputChunk) => boolean\n): string[] {\n if (typeof jsAssetsFilterFunction != \"function\") {\n const jsAssets = Object.keys(bundle).filter((i) => {\n const asset = bundle[i];\n return asset !== undefined && isJsOutputChunk(asset) && defaultJsAssetsFilter(asset);\n });\n const jsTargetFileName = jsAssets[jsAssets.length - 1];\n if (jsTargetFileName === undefined) {\n return [];\n }\n if (jsAssets.length > 1) {\n warnLog(\n `[vite-plugin-css-position] identified \"${jsTargetFileName}\" as one of multiple \"entry\" output files to put the CSS injection code. ` +\n 'If this is not the intended file, use the \"jsAssetsFilterFunction\" option to specify the desired output file.'\n );\n }\n return [jsTargetFileName];\n }\n return Object.entries(bundle)\n .filter(([, chunk]) => isJsOutputChunk(chunk) && jsAssetsFilterFunction(chunk))\n .map(([key]) => key);\n}\n\nfunction buildJsCssMap(\n bundle: Rollup.OutputBundle,\n jsAssetsFilterFunction?: (chunk: Rollup.OutputChunk) => boolean\n): Record<string, string[]> {\n const chunksWithCss: Record<string, string[]> = {};\n const bundleKeys = getJsTargetBundleKeys(\n bundle,\n typeof jsAssetsFilterFunction == \"function\" ? jsAssetsFilterFunction : () => true\n );\n if (bundleKeys.length === 0) {\n throw new Error(\n \"Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.\"\n );\n }\n for (const key of bundleKeys) {\n const chunk = bundle[key];\n if (chunk === undefined || chunk.type === \"asset\") {\n continue;\n }\n const importedCss = importedCssOf(chunk);\n if (!importedCss || importedCss.size === 0) {\n continue;\n }\n const chunkStyles = chunksWithCss[key] || [];\n chunkStyles.push(...importedCss.values());\n chunksWithCss[key] = chunkStyles;\n }\n return chunksWithCss;\n}\n\nfunction buildOutputChunkWithCssInjectionCode(\n jsAssetCode: string,\n cssInjectionCode: string,\n topExecutionPriorityFlag: boolean\n): string {\n const appCode = jsAssetCode.replace(/\\/\\*\\s*empty css\\s*\\*\\//g, \"\");\n jsAssetCode = topExecutionPriorityFlag ? \"\" : appCode;\n jsAssetCode += cssInjectionCode;\n jsAssetCode += !topExecutionPriorityFlag ? \"\" : appCode;\n return jsAssetCode;\n}\n\nfunction clearImportedCssViteMetadataFromBundle(\n bundle: Rollup.OutputBundle,\n unusedCssAssets: string[]\n): void {\n // Required to exclude removed files from manifest.json\n for (const key in bundle) {\n const chunk = bundle[key];\n if (chunk === undefined || chunk.type !== \"chunk\") {\n continue;\n }\n const meta = (chunk as ChunkWithCssMeta).viteMetadata;\n if (meta && meta.importedCss.size > 0) {\n meta.importedCss.forEach((importedCssFileName: string) => {\n if (!unusedCssAssets.includes(importedCssFileName)) {\n meta.importedCss = new Set();\n }\n });\n }\n }\n}\n\nfunction removeLinkStyleSheets(html: string, cssFileName: string): string {\n const removeCSS = new RegExp(`<link rel=\".*\"[^>]*?href=\".*/?${cssFileName}\"[^>]*?>`);\n return html.replace(removeCSS, \"\");\n}\n\nfunction isCSSRequest(request: string): boolean {\n const CSS_LANGS_RE = /\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/;\n return CSS_LANGS_RE.test(request);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Injection modes */\n/* -------------------------------------------------------------------------- */\n\nfunction relativeCssInjection(\n bundle: Rollup.OutputBundle,\n assetsWithCss: Record<string, string[]>,\n makeInjection: (css: string) => string\n): void {\n for (const [jsAssetName, cssAssets] of Object.entries(assetsWithCss)) {\n const assetCss = concatCssAndDeleteFromBundle(bundle, cssAssets);\n const cssInjectionCode = assetCss.length > 0 ? makeInjection(assetCss) : \"\";\n const jsAsset = bundle[jsAssetName] as Rollup.OutputChunk;\n jsAsset.code = buildOutputChunkWithCssInjectionCode(\n jsAsset.code,\n cssInjectionCode,\n TOP_EXECUTION_PRIORITY\n );\n }\n}\n\n// Reuse CSS across sequential builds for the same entry (e.g. multiple formats).\nconst globalCSSCodeEntryCache = new Map<string, string>();\nlet previousFacadeModuleId = \"\";\n\nfunction globalCssInjection(\n bundle: Rollup.OutputBundle,\n cssAssets: string[],\n makeInjection: (css: string) => string,\n jsAssetsFilterFunction: ((chunk: Rollup.OutputChunk) => boolean) | undefined\n): void {\n const jsTargetBundleKeys = getJsTargetBundleKeys(bundle, jsAssetsFilterFunction);\n if (jsTargetBundleKeys.length == 0) {\n throw new Error(\n \"Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.\"\n );\n }\n const allCssCode = concatCssAndDeleteFromBundle(bundle, cssAssets);\n let cssInjectionCode = allCssCode.length > 0 ? makeInjection(allCssCode) : \"\";\n\n for (const jsTargetKey of jsTargetBundleKeys) {\n const jsAsset = bundle[jsTargetKey] as Rollup.OutputChunk;\n if (jsAsset.facadeModuleId != null && jsAsset.isEntry && cssInjectionCode != \"\") {\n if (jsAsset.facadeModuleId != previousFacadeModuleId) {\n globalCSSCodeEntryCache.clear();\n }\n previousFacadeModuleId = jsAsset.facadeModuleId;\n globalCSSCodeEntryCache.set(jsAsset.facadeModuleId, cssInjectionCode);\n }\n if (\n cssInjectionCode == \"\" &&\n jsAsset.isEntry &&\n jsAsset.facadeModuleId != null &&\n typeof globalCSSCodeEntryCache.get(jsAsset.facadeModuleId) == \"string\"\n ) {\n cssInjectionCode = globalCSSCodeEntryCache.get(jsAsset.facadeModuleId) as string;\n }\n jsAsset.code = buildOutputChunkWithCssInjectionCode(\n jsAsset.code,\n cssInjectionCode,\n TOP_EXECUTION_PRIORITY\n );\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Plugin factory */\n/* -------------------------------------------------------------------------- */\n\nexport function cssInjectionPlugins(options: CssInjectionOptions): Plugin[] {\n const { globalVarName, eventName, relative, jsAssetsFilterFunction } = options;\n let config: ResolvedConfig;\n\n const plugins: Plugin[] = [\n {\n apply: \"build\",\n enforce: \"post\",\n name: \"vite-plugin-css-position-injection\",\n config(c, env) {\n if (env.command === \"build\" && relative) {\n c.build ??= {};\n if (c.build.cssCodeSplit === false) {\n warnLog(\n \"[vite-plugin-css-position] Override of 'build.cssCodeSplit' to true; it must be true when 'lazy' is enabled.\"\n );\n }\n c.build.cssCodeSplit = true;\n }\n },\n configResolved(resolved) {\n config = resolved;\n },\n generateBundle(_opts, bundle) {\n if (config.build.ssr) {\n return;\n }\n const makeInjection = (css: string) =>\n buildInjectionCode(globalVarName, eventName, JSON.stringify(css.trim()));\n\n const cssAssets = Object.keys(bundle).filter((i) => {\n const asset = bundle[i];\n return asset !== undefined && asset.type == \"asset\" && asset.fileName.endsWith(\".css\");\n });\n let unusedCssAssets: string[] = [];\n\n if (relative) {\n const assetsWithCss = buildJsCssMap(bundle, jsAssetsFilterFunction);\n relativeCssInjection(bundle, assetsWithCss, makeInjection);\n unusedCssAssets = cssAssets.filter((cssAsset) => !!bundle[cssAsset]);\n if (unusedCssAssets.length > 0) {\n warnLog(\n `[vite-plugin-css-position] Some CSS assets were not included in any known JS: ${unusedCssAssets.join(\",\")}`\n );\n }\n } else {\n globalCssInjection(bundle, cssAssets, makeInjection, jsAssetsFilterFunction);\n }\n\n clearImportedCssViteMetadataFromBundle(bundle, unusedCssAssets);\n\n const htmlFiles = Object.keys(bundle).filter((i) => i.endsWith(\".html\"));\n for (const name of htmlFiles) {\n const htmlChunk = bundle[name] as Rollup.OutputAsset;\n let replacedHtml =\n htmlChunk.source instanceof Uint8Array\n ? new TextDecoder().decode(htmlChunk.source)\n : `${htmlChunk.source}`;\n cssAssets.forEach((cssName) => {\n if (!unusedCssAssets.includes(cssName)) {\n replacedHtml = removeLinkStyleSheets(replacedHtml, cssName);\n htmlChunk.source = replacedHtml;\n }\n });\n }\n },\n },\n ];\n\n if (options.enableDev) {\n warnLog(\"[vite-plugin-css-position] Experimental dev mode activated!\");\n plugins.push({\n name: \"vite-plugin-css-position-injection-dev\",\n apply: \"serve\",\n enforce: \"post\",\n transform(src, id) {\n if (!isCSSRequest(id)) {\n return;\n }\n const removeStyleCode = buildRemoveStyleCode(globalVarName, eventName, id);\n const injectCode = buildInjectionCode(globalVarName, eventName, \"__vite__css\", {\n type: \"text/css\",\n \"data-vite-dev-id\": id,\n });\n // removeStyleCode runs first since the inject snippet doesn't handle the\n // dev update case on its own.\n let injectionCode = src.replace(\n \"__vite__updateStyle(__vite__id, __vite__css)\",\n \";\\n\" + removeStyleCode + \";\\n\" + injectCode\n );\n injectionCode = injectionCode.replace(\"__vite__removeStyle(__vite__id)\", removeStyleCode);\n return { code: injectionCode, map: null };\n },\n });\n }\n\n return plugins;\n}\n","import type { Plugin, Rollup } from \"vite\";\nimport { randomUUID } from \"crypto\";\nimport { cssInjectionPlugins } from \"./cssInjection\";\n\ntype JsAssetsFilterFunction = (chunk: Rollup.OutputChunk) => boolean;\n\nexport interface ViteCustomCssPositionOptions {\n instanceId?: string;\n enableDev?: boolean;\n /**\n * Inject each (including lazily loaded) chunk's CSS relative to that chunk\n * instead of bundling all CSS into the entry. Enables component-level granular\n * lazy-loading of stylesheets: a code-split component's styles are only injected\n * when the component is actually loaded.\n *\n * `false` (default) keeps the previous behavior (all CSS in the entry, loaded\n * up front) and is fully backward compatible.\n *\n * @default false\n */\n lazy?: boolean;\n /**\n * Filter function to determine which JS file(s) should receive the CSS injection code.\n * Useful when building multiple entry points and you want CSS only in specific entries.\n * @param chunk - The output chunk being processed\n * @returns true if CSS should be injected into this chunk\n */\n jsAssetsFilterFunction?: JsAssetsFilterFunction;\n}\n\nexport default function viteCustomCssPosition(\n options?: ViteCustomCssPositionOptions\n): Plugin | Plugin[] {\n const instanceId = options?.instanceId || randomUUID().replace(/-/g, \"\");\n\n const globalVarName = `__vite_c_css_pos_initial_${instanceId}`;\n const eventName = `__vite_c_css_pos_update_${instanceId}`;\n\n const cssPlugins = cssInjectionPlugins({\n globalVarName,\n eventName,\n enableDev: options?.enableDev ?? false,\n relative: options?.lazy ?? false,\n jsAssetsFilterFunction: options?.jsAssetsFilterFunction,\n });\n\n return [\n {\n name: \"vite-plugin-custom-css-position\",\n config(c) {\n return {\n ...c,\n define: {\n ...c.define,\n __VITE_CSS_POS_GLOBAL_VAR_NAME__: JSON.stringify(globalVarName),\n __VITE_CSS_POS_EVENT_NAME__: JSON.stringify(eventName),\n },\n };\n },\n },\n ...cssPlugins,\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["cssSourceCache: Record<string, string>","chunksWithCss: Record<string, string[]>","config: ResolvedConfig","plugins: Plugin[]","unusedCssAssets: string[]","linkStrategy: CssChunksStrategy"],"sources":["../src/cssInjection.ts","../src/viteCustomCssPosition.ts"],"sourcesContent":["/**\n * CSS-by-JS injection core, vendored and trimmed from\n * `vite-plugin-css-injected-by-js` (v3.5.2) by Marco Prontera.\n *\n * Original: https://github.com/marco-prontera/vite-plugin-css-injected-by-js\n * Licensed under the MIT License — Copyright (c) 2023 Marco Prontera.\n *\n * This is a focused port: instead of creating `<style>` elements directly, the\n * generated injection code stores the CSS into a global Map and dispatches an\n * event, which the `StylesTarget` component reacts to in order to render the\n * styles at a custom position (e.g. inside a Shadow DOM). Unlike the original it\n * does NOT run a nested Vite build to produce the injection code; the snippet is\n * built directly and wrapped in an IIFE.\n *\n * Beyond the original's CSS-in-JS modes (`inject`/`injectPerChunk`), this module\n * adds a `cssChunks` mode that keeps Vite's emitted `.css` chunk files and only\n * registers their URLs per chunk, so `StylesTarget` can link/adopt them at its\n * position instead of inlining the CSS.\n */\nimport { hash } from \"crypto\";\nimport { posix } from \"node:path\";\nimport type { Plugin, ResolvedConfig, Rollup } from \"vite\";\n\n/**\n * - `inject`: concatenate all CSS into the entry chunk JS, registered as `<style>`.\n * - `injectPerChunk`: inline each chunk's CSS into its JS, registered as `<style>`.\n * - `cssChunks`: keep emitted `.css` files; register their URLs per chunk so they\n * can be linked/adopted at the `StylesTarget` position.\n */\nexport type InjectionMode = \"inject\" | \"injectPerChunk\" | \"cssChunks\";\n\nexport interface CssInjectionOptions {\n /** Name of the global variable holding the styles Map. */\n globalVarName: string;\n /** Name of the window event dispatched on style updates. */\n eventName: string;\n /** Enable the experimental dev-mode (HMR) transform. */\n enableDev: boolean;\n /** How CSS is delivered and registered. See {@link InjectionMode}. */\n mode: InjectionMode;\n /** Filter which JS chunks receive the CSS injection code. */\n jsAssetsFilterFunction?: ((chunk: Rollup.OutputChunk) => boolean) | undefined;\n}\n\n// CSS is injected before the rest of the chunk's code (parity with the original\n// plugin's default `topExecutionPriority: true`).\nconst TOP_EXECUTION_PRIORITY = true;\n\n// `viteMetadata.importedCss` is a Vite augmentation of Rollup's chunk type that\n// isn't surfaced through Vite's re-exported `Rollup` namespace; access it via a\n// local typed view.\ntype ChunkWithCssMeta = Rollup.OutputChunk & {\n viteMetadata?: { importedCss: Set<string> };\n};\n\nfunction importedCssOf(chunk: Rollup.OutputChunk): Set<string> | undefined {\n return (chunk as ChunkWithCssMeta).viteMetadata?.importedCss;\n}\n\nfunction warnLog(msg: string): void {\n console.warn(`\\x1b[33m \\n${msg} \\x1b[39m`);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Injection code generation */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Build the runtime snippet that registers the given CSS in the global Map and\n * notifies listeners. Wrapped in an IIFE so the local `const`s don't leak into\n * (or collide within) the chunk scope it is appended to.\n *\n * @param cssCodeExpr A JS expression evaluating to the CSS string. In build mode\n * this is a JSON string literal; in dev mode it's the `__vite__css` variable.\n * @param attributes Attributes to attach to the rendered `<style>` (dev only).\n */\nfunction buildInjectionCode(\n globalVarName: string,\n eventName: string,\n cssCodeExpr: string,\n attributes?: Record<string, string>\n): string {\n const attributesString = JSON.stringify(attributes || {});\n const id = `\"${\n attributes?.[\"data-vite-dev-id\"] ?? hash(\"sha1\", cssCodeExpr).substring(0, 12)\n }\"`;\n const body =\n `const css = ${cssCodeExpr};const id = ${id};const attributes = JSON.parse('${attributesString}');` +\n `window.${globalVarName} = window.${globalVarName} || new Map();` +\n `window.${globalVarName}.set(id, {type:\"style\", css, attributes});` +\n `window.dispatchEvent( new Event('${eventName}') );`;\n return `(()=>{${body}})();`;\n}\n\n/**\n * Build the runtime snippet (cssChunks mode) that registers emitted CSS file\n * URLs in the global Map. URLs are resolved relative to the chunk via\n * `import.meta.url`, which is base-agnostic (works for relative and absolute base).\n */\nfunction buildLinkRegistrationCode(\n globalVarName: string,\n eventName: string,\n items: Array<{ id: string; rel: string }>\n): string {\n const data = JSON.stringify(items.map((it) => [it.id, it.rel]));\n return (\n `(()=>{const items=${data};` +\n `window.${globalVarName}=window.${globalVarName}||new Map();` +\n `for(const [id,rel] of items){` +\n `window.${globalVarName}.set(id,{type:\"link\",href:new URL(rel,import.meta.url).href,attributes:{}});}` +\n `window.dispatchEvent(new Event('${eventName}'));})();`\n );\n}\n\n/** Code executed (dev mode) to remove a previously injected style on HMR update. */\nfunction buildRemoveStyleCode(globalVarName: string, eventName: string, id: string): string {\n return `(() => {\n if(window.${globalVarName} && window.${globalVarName}.has('${id}')) {\n window.${globalVarName}.delete('${id}');\n window.dispatchEvent( new Event('${eventName}') );\n }\n })()`;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Bundle helpers (ported from vite-plugin-css-injected-by-js utils) */\n/* -------------------------------------------------------------------------- */\n\n// The cache must be global since the execution context differs per entry.\nconst cssSourceCache: Record<string, string> = {};\n\nfunction extractCss(bundle: Rollup.OutputBundle, cssName: string): string {\n const cssAsset = bundle[cssName] as Rollup.OutputAsset | undefined;\n if (cssAsset !== undefined && cssAsset.source) {\n const cssSource = cssAsset.source;\n cssSourceCache[cssName] =\n cssSource instanceof Uint8Array ? new TextDecoder().decode(cssSource) : `${cssSource}`;\n }\n return cssSourceCache[cssName] ?? \"\";\n}\n\nfunction concatCssAndDeleteFromBundle(bundle: Rollup.OutputBundle, cssAssets: string[]): string {\n return cssAssets.reduce((previous, cssName) => {\n const cssSource = extractCss(bundle, cssName);\n delete bundle[cssName];\n return previous + cssSource;\n }, \"\");\n}\n\nfunction isJsOutputChunk(chunk: Rollup.OutputAsset | Rollup.OutputChunk): chunk is Rollup.OutputChunk {\n return chunk.type == \"chunk\" && chunk.fileName.match(/.[cm]?js(?:\\?.+)?$/) != null;\n}\n\nfunction defaultJsAssetsFilter(chunk: Rollup.OutputChunk): boolean {\n return chunk.isEntry && !chunk.fileName.includes(\"polyfill\");\n}\n\nfunction getJsTargetBundleKeys(\n bundle: Rollup.OutputBundle,\n jsAssetsFilterFunction?: (chunk: Rollup.OutputChunk) => boolean\n): string[] {\n if (typeof jsAssetsFilterFunction != \"function\") {\n const jsAssets = Object.keys(bundle).filter((i) => {\n const asset = bundle[i];\n return asset !== undefined && isJsOutputChunk(asset) && defaultJsAssetsFilter(asset);\n });\n const jsTargetFileName = jsAssets[jsAssets.length - 1];\n if (jsTargetFileName === undefined) {\n return [];\n }\n if (jsAssets.length > 1) {\n warnLog(\n `[vite-plugin-css-position] identified \"${jsTargetFileName}\" as one of multiple \"entry\" output files to put the CSS injection code. ` +\n 'If this is not the intended file, use the \"jsAssetsFilterFunction\" option to specify the desired output file.'\n );\n }\n return [jsTargetFileName];\n }\n return Object.entries(bundle)\n .filter(([, chunk]) => isJsOutputChunk(chunk) && jsAssetsFilterFunction(chunk))\n .map(([key]) => key);\n}\n\nfunction buildJsCssMap(\n bundle: Rollup.OutputBundle,\n jsAssetsFilterFunction?: (chunk: Rollup.OutputChunk) => boolean\n): Record<string, string[]> {\n const chunksWithCss: Record<string, string[]> = {};\n const bundleKeys = getJsTargetBundleKeys(\n bundle,\n typeof jsAssetsFilterFunction == \"function\" ? jsAssetsFilterFunction : () => true\n );\n if (bundleKeys.length === 0) {\n throw new Error(\n \"Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.\"\n );\n }\n for (const key of bundleKeys) {\n const chunk = bundle[key];\n if (chunk === undefined || chunk.type === \"asset\") {\n continue;\n }\n const importedCss = importedCssOf(chunk);\n if (!importedCss || importedCss.size === 0) {\n continue;\n }\n const chunkStyles = chunksWithCss[key] || [];\n chunkStyles.push(...importedCss.values());\n chunksWithCss[key] = chunkStyles;\n }\n return chunksWithCss;\n}\n\nfunction buildOutputChunkWithCssInjectionCode(\n jsAssetCode: string,\n cssInjectionCode: string,\n topExecutionPriorityFlag: boolean\n): string {\n const appCode = jsAssetCode.replace(/\\/\\*\\s*empty css\\s*\\*\\//g, \"\");\n jsAssetCode = topExecutionPriorityFlag ? \"\" : appCode;\n jsAssetCode += cssInjectionCode;\n jsAssetCode += !topExecutionPriorityFlag ? \"\" : appCode;\n return jsAssetCode;\n}\n\nfunction clearImportedCssViteMetadataFromBundle(\n bundle: Rollup.OutputBundle,\n unusedCssAssets: string[]\n): void {\n // Required to exclude removed files from manifest.json\n for (const key in bundle) {\n const chunk = bundle[key];\n if (chunk === undefined || chunk.type !== \"chunk\") {\n continue;\n }\n const meta = (chunk as ChunkWithCssMeta).viteMetadata;\n if (meta && meta.importedCss.size > 0) {\n meta.importedCss.forEach((importedCssFileName: string) => {\n if (!unusedCssAssets.includes(importedCssFileName)) {\n meta.importedCss = new Set();\n }\n });\n }\n }\n}\n\nfunction removeLinkStyleSheets(html: string, cssFileName: string): string {\n const removeCSS = new RegExp(`<link rel=\".*\"[^>]*?href=\".*/?${cssFileName}\"[^>]*?>`);\n return html.replace(removeCSS, \"\");\n}\n\nfunction isCSSRequest(request: string): boolean {\n const CSS_LANGS_RE = /\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/;\n return CSS_LANGS_RE.test(request);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Injection modes */\n/* -------------------------------------------------------------------------- */\n\nfunction relativeCssInjection(\n bundle: Rollup.OutputBundle,\n assetsWithCss: Record<string, string[]>,\n makeInjection: (css: string) => string\n): void {\n for (const [jsAssetName, cssAssets] of Object.entries(assetsWithCss)) {\n const assetCss = concatCssAndDeleteFromBundle(bundle, cssAssets);\n const cssInjectionCode = assetCss.length > 0 ? makeInjection(assetCss) : \"\";\n const jsAsset = bundle[jsAssetName] as Rollup.OutputChunk;\n jsAsset.code = buildOutputChunkWithCssInjectionCode(\n jsAsset.code,\n cssInjectionCode,\n TOP_EXECUTION_PRIORITY\n );\n }\n}\n\n// Reuse CSS across sequential builds for the same entry (e.g. multiple formats).\nconst globalCSSCodeEntryCache = new Map<string, string>();\nlet previousFacadeModuleId = \"\";\n\nfunction globalCssInjection(\n bundle: Rollup.OutputBundle,\n cssAssets: string[],\n makeInjection: (css: string) => string,\n jsAssetsFilterFunction: ((chunk: Rollup.OutputChunk) => boolean) | undefined\n): void {\n const jsTargetBundleKeys = getJsTargetBundleKeys(bundle, jsAssetsFilterFunction);\n if (jsTargetBundleKeys.length == 0) {\n throw new Error(\n \"Unable to locate the JavaScript asset for adding the CSS injection code. It is recommended to review your configurations.\"\n );\n }\n const allCssCode = concatCssAndDeleteFromBundle(bundle, cssAssets);\n let cssInjectionCode = allCssCode.length > 0 ? makeInjection(allCssCode) : \"\";\n\n for (const jsTargetKey of jsTargetBundleKeys) {\n const jsAsset = bundle[jsTargetKey] as Rollup.OutputChunk;\n if (jsAsset.facadeModuleId != null && jsAsset.isEntry && cssInjectionCode != \"\") {\n if (jsAsset.facadeModuleId != previousFacadeModuleId) {\n globalCSSCodeEntryCache.clear();\n }\n previousFacadeModuleId = jsAsset.facadeModuleId;\n globalCSSCodeEntryCache.set(jsAsset.facadeModuleId, cssInjectionCode);\n }\n if (\n cssInjectionCode == \"\" &&\n jsAsset.isEntry &&\n jsAsset.facadeModuleId != null &&\n typeof globalCSSCodeEntryCache.get(jsAsset.facadeModuleId) == \"string\"\n ) {\n cssInjectionCode = globalCSSCodeEntryCache.get(jsAsset.facadeModuleId) as string;\n }\n jsAsset.code = buildOutputChunkWithCssInjectionCode(\n jsAsset.code,\n cssInjectionCode,\n TOP_EXECUTION_PRIORITY\n );\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* cssChunks mode */\n/* -------------------------------------------------------------------------- */\n\nfunction ensureRelative(p: string): string {\n return p.startsWith(\".\") ? p : \"./\" + p;\n}\n\n/**\n * Per chunk, append a snippet that registers the chunk's emitted CSS file URLs.\n * CSS assets are NOT deleted from the bundle — they stay as cacheable files.\n */\nfunction cssChunksInjection(\n bundle: Rollup.OutputBundle,\n assetsWithCss: Record<string, string[]>,\n globalVarName: string,\n eventName: string\n): void {\n for (const [jsAssetName, cssAssets] of Object.entries(assetsWithCss)) {\n const jsAsset = bundle[jsAssetName] as Rollup.OutputChunk;\n const chunkDir = posix.dirname(jsAsset.fileName);\n const items = cssAssets.map((css) => ({\n id: hash(\"sha1\", css).substring(0, 12),\n rel: ensureRelative(posix.relative(chunkDir, css)),\n }));\n const code = buildLinkRegistrationCode(globalVarName, eventName, items);\n jsAsset.code = buildOutputChunkWithCssInjectionCode(jsAsset.code, code, TOP_EXECUTION_PRIORITY);\n }\n}\n\n/**\n * Remove `.css` entries from a chunk's Vite preload dependency calls so Vite's\n * `__vitePreload` runtime helper never injects them into `document.head` (we link\n * them at the StylesTarget position instead). Drops the CSS indices from each\n * `__vite__mapDeps([...])` call while leaving the (now dead) filename in the\n * shared `m.f=[...]` array — avoids fragile re-indexing.\n */\nfunction stripCssPreloadDeps(code: string): string {\n const arrMatch = code.match(/m\\.f=\\[([^\\]]*)\\]/);\n if (!arrMatch || arrMatch[1] === undefined) {\n return code;\n }\n const entries = [...arrMatch[1].matchAll(/\"((?:[^\"\\\\]|\\\\.)*)\"/g)].map((m) => m[1]);\n const cssIndices = new Set<number>();\n entries.forEach((entry, i) => {\n if (entry !== undefined && entry.endsWith(\".css\")) {\n cssIndices.add(i);\n }\n });\n if (cssIndices.size === 0) {\n return code;\n }\n return code.replace(/__vite__mapDeps\\(\\[([^\\]]*)\\]\\)/g, (_full, inner: string) => {\n const kept = inner\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\" && !cssIndices.has(Number(s)));\n return `__vite__mapDeps([${kept.join(\",\")}])`;\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Plugin factory */\n/* -------------------------------------------------------------------------- */\n\nexport function cssInjectionPlugins(options: CssInjectionOptions): Plugin[] {\n const { globalVarName, eventName, mode, jsAssetsFilterFunction } = options;\n // Both per-chunk modes need Vite to emit one CSS file per chunk.\n const perChunk = mode === \"injectPerChunk\" || mode === \"cssChunks\";\n let config: ResolvedConfig;\n\n const plugins: Plugin[] = [\n {\n apply: \"build\",\n enforce: \"post\",\n name: \"vite-plugin-css-position-injection\",\n config(c, env) {\n if (env.command === \"build\" && perChunk) {\n c.build ??= {};\n if (c.build.cssCodeSplit === false) {\n warnLog(\n `[vite-plugin-css-position] Override of 'build.cssCodeSplit' to true; it must be true when mode is '${mode}'.`\n );\n }\n c.build.cssCodeSplit = true;\n }\n },\n configResolved(resolved) {\n config = resolved;\n },\n generateBundle(_opts, bundle) {\n if (config.build.ssr) {\n return;\n }\n\n const cssAssets = Object.keys(bundle).filter((i) => {\n const asset = bundle[i];\n return asset !== undefined && asset.type == \"asset\" && asset.fileName.endsWith(\".css\");\n });\n let unusedCssAssets: string[] = [];\n\n if (mode === \"cssChunks\") {\n // Keep emitted CSS files; register their URLs per chunk. The preload\n // mapDeps stripping happens in a separate order:\"post\" hook below,\n // because Vite resolves the __VITE_PRELOAD__ marker after this hook.\n const assetsWithCss = buildJsCssMap(bundle, jsAssetsFilterFunction);\n cssChunksInjection(bundle, assetsWithCss, globalVarName, eventName);\n // CSS assets and viteMetadata are intentionally kept (manifest stays valid).\n } else {\n const makeInjection = (css: string) =>\n buildInjectionCode(globalVarName, eventName, JSON.stringify(css.trim()));\n if (mode === \"injectPerChunk\") {\n const assetsWithCss = buildJsCssMap(bundle, jsAssetsFilterFunction);\n relativeCssInjection(bundle, assetsWithCss, makeInjection);\n unusedCssAssets = cssAssets.filter((cssAsset) => !!bundle[cssAsset]);\n if (unusedCssAssets.length > 0) {\n warnLog(\n `[vite-plugin-css-position] Some CSS assets were not included in any known JS: ${unusedCssAssets.join(\",\")}`\n );\n }\n } else {\n globalCssInjection(bundle, cssAssets, makeInjection, jsAssetsFilterFunction);\n }\n clearImportedCssViteMetadataFromBundle(bundle, unusedCssAssets);\n }\n\n // Remove the CSS <link> tags Vite injected into the HTML head. In\n // cssChunks mode all entry CSS is handled via registration, so strip all.\n const htmlFiles = Object.keys(bundle).filter((i) => i.endsWith(\".html\"));\n for (const name of htmlFiles) {\n const htmlChunk = bundle[name] as Rollup.OutputAsset;\n let replacedHtml =\n htmlChunk.source instanceof Uint8Array\n ? new TextDecoder().decode(htmlChunk.source)\n : `${htmlChunk.source}`;\n cssAssets.forEach((cssName) => {\n if (!unusedCssAssets.includes(cssName)) {\n replacedHtml = removeLinkStyleSheets(replacedHtml, cssName);\n htmlChunk.source = replacedHtml;\n }\n });\n }\n },\n },\n ];\n\n if (mode === \"cssChunks\") {\n // Runs as order:\"post\" so it executes AFTER Vite's build-import-analysis has\n // resolved __VITE_PRELOAD__ into __vite__mapDeps([...]); only then can we\n // drop the .css indices to stop the preload helper injecting them into <head>.\n plugins.push({\n apply: \"build\",\n enforce: \"post\",\n name: \"vite-plugin-css-position-preload-strip\",\n generateBundle: {\n order: \"post\",\n handler(_opts, bundle) {\n for (const key of Object.keys(bundle)) {\n const chunk = bundle[key];\n if (chunk !== undefined && chunk.type === \"chunk\") {\n chunk.code = stripCssPreloadDeps(chunk.code);\n }\n }\n },\n },\n });\n }\n\n if (options.enableDev) {\n warnLog(\"[vite-plugin-css-position] Experimental dev mode activated!\");\n plugins.push({\n name: \"vite-plugin-css-position-injection-dev\",\n apply: \"serve\",\n enforce: \"post\",\n transform(src, id) {\n if (!isCSSRequest(id)) {\n return;\n }\n const removeStyleCode = buildRemoveStyleCode(globalVarName, eventName, id);\n const injectCode = buildInjectionCode(globalVarName, eventName, \"__vite__css\", {\n type: \"text/css\",\n \"data-vite-dev-id\": id,\n });\n // removeStyleCode runs first since the inject snippet doesn't handle the\n // dev update case on its own.\n let injectionCode = src.replace(\n \"__vite__updateStyle(__vite__id, __vite__css)\",\n \";\\n\" + removeStyleCode + \";\\n\" + injectCode\n );\n injectionCode = injectionCode.replace(\"__vite__removeStyle(__vite__id)\", removeStyleCode);\n return { code: injectionCode, map: null };\n },\n });\n }\n\n return plugins;\n}\n","import type { Plugin, Rollup } from \"vite\";\nimport { randomUUID } from \"crypto\";\nimport { cssInjectionPlugins, type InjectionMode } from \"./cssInjection\";\n\ntype JsAssetsFilterFunction = (chunk: Rollup.OutputChunk) => boolean;\n\n/** How `StylesTarget` includes CSS files in `cssChunks` mode. */\nexport type CssChunksStrategy = \"link\" | \"adopt\";\n\n/** Options shared by every mode. */\ninterface BaseCssPositionOptions {\n instanceId?: string;\n enableDev?: boolean;\n /**\n * Filter function to determine which JS file(s) should receive the CSS injection code.\n * Useful when building multiple entry points and you want CSS only in specific entries.\n * @param chunk - The output chunk being processed\n * @returns true if CSS should be injected into this chunk\n */\n jsAssetsFilterFunction?: JsAssetsFilterFunction;\n}\n\n/**\n * Mode-specific options. A discriminated union so that `cssChunksStrategy` is\n * only assignable when `mode: \"cssChunks\"`, and the deprecated `cssPerChunk` is\n * only assignable for the inline-inject modes.\n */\ntype ModeCssPositionOptions =\n | {\n /**\n * How CSS is delivered and registered:\n * - `\"inject\"` (default): all CSS is concatenated and inlined into the entry\n * JS, registered as `<style>`. The previous default behavior.\n * - `\"injectPerChunk\"`: each chunk's CSS is inlined into its JS, registered\n * as `<style>` — component-level granular lazy-loading via inlined styles.\n *\n * @default \"inject\"\n */\n mode?: \"inject\" | \"injectPerChunk\";\n /**\n * @deprecated Use `mode` instead. `true` maps to `mode: \"injectPerChunk\"`,\n * `false`/unset to `mode: \"inject\"`. Ignored when `mode` is set.\n */\n cssPerChunk?: boolean;\n /** Only valid with `mode: \"cssChunks\"`. */\n cssChunksStrategy?: never;\n }\n | {\n /**\n * `\"cssChunks\"`: Vite's emitted `.css` chunk files are kept; each chunk only\n * registers its CSS file URL, and `StylesTarget` links/adopts it at its\n * position. Closest to standard Vite (cacheable files, lean JS, CSP-friendly).\n */\n mode: \"cssChunks\";\n /**\n * How `StylesTarget` includes the CSS file:\n * - `\"link\"` (default): render `<link rel=\"stylesheet\">`. Simple; may FOUC in\n * Shadow DOM (link is not render-blocking there).\n * - `\"adopt\"`: fetch the CSS and apply it via `adoptedStyleSheets`. No FOUC,\n * CSP-ideal, dedup across roots; requires `fetch` + modern browsers (2023+).\n *\n * @default \"link\"\n */\n cssChunksStrategy?: CssChunksStrategy;\n /** Not applicable in `cssChunks` mode. */\n cssPerChunk?: never;\n };\n\nexport type ViteCustomCssPositionOptions = BaseCssPositionOptions & ModeCssPositionOptions;\n\nfunction resolveMode(options?: ViteCustomCssPositionOptions): InjectionMode {\n if (options?.mode) {\n if (options.cssPerChunk !== undefined) {\n console.warn(\n \"[vite-plugin-css-position] Both 'mode' and the deprecated 'cssPerChunk' are set; 'mode' wins.\"\n );\n }\n return options.mode;\n }\n return options?.cssPerChunk ? \"injectPerChunk\" : \"inject\";\n}\n\nexport default function viteCustomCssPosition(\n options?: ViteCustomCssPositionOptions\n): Plugin | Plugin[] {\n const instanceId =\n options?.instanceId || randomUUID().replace(/-/g, \"\").slice(0, 4);\n\n const globalVarName = `__vcssp_c_${instanceId}`;\n const eventName = `__vcssp_e_${instanceId}`;\n const linkStrategy: CssChunksStrategy = options?.cssChunksStrategy ?? \"link\";\n\n const cssPlugins = cssInjectionPlugins({\n globalVarName,\n eventName,\n enableDev: options?.enableDev ?? false,\n mode: resolveMode(options),\n jsAssetsFilterFunction: options?.jsAssetsFilterFunction,\n });\n\n return [\n {\n name: \"vite-plugin-custom-css-position\",\n config(c) {\n return {\n ...c,\n define: {\n ...c.define,\n __VITE_CSS_POS_GLOBAL_VAR_NAME__: JSON.stringify(globalVarName),\n __VITE_CSS_POS_EVENT_NAME__: JSON.stringify(eventName),\n __VITE_CSS_POS_LINK_STRATEGY__: JSON.stringify(linkStrategy),\n },\n };\n },\n },\n ...cssPlugins,\n ];\n}\n"],"mappings":"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"}
|