vite-plugin-sri4 4.0.0 → 4.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/LICENSE +21 -0
- package/README.md +96 -6
- package/dist/index.cjs +540 -192
- package/dist/index.js +540 -192
- package/package.json +20 -15
- package/types/index.d.ts +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Zac
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ A Vite plugin to generate Subresource Integrity (SRI) hashes for your assets dur
|
|
|
12
12
|
- [Installation](#installation)
|
|
13
13
|
- [Usage](#usage)
|
|
14
14
|
- [Plugin Options](#plugin-options)
|
|
15
|
+
- [Dynamic Routes](#dynamic-routes)
|
|
16
|
+
- [When SRI Actually Helps](#when-sri-actually-helps)
|
|
17
|
+
- [How It Attaches Hashes](#how-it-attaches-hashes)
|
|
15
18
|
- [Example Project](#example-project)
|
|
16
19
|
- [Best Practices](#best-practices)
|
|
17
20
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -24,10 +27,13 @@ A Vite plugin to generate Subresource Integrity (SRI) hashes for your assets dur
|
|
|
24
27
|
- **Automatic SRI Generation:** Computes SRI hashes for assets (chunks and files) using a configurable algorithm (default is `sha384`).
|
|
25
28
|
- **HTML Injection:** Automatically injects `integrity` and `crossorigin` attributes into `<script>` and `<link>` tags in your HTML.
|
|
26
29
|
- **CORS Support Check:** For external resources, a CORS check is performed to verify access via `Access-Control-Allow-Origin`.
|
|
27
|
-
- **Bypass Domains:** Option to specify domains to bypass SRI injection.
|
|
30
|
+
- **Bypass Domains:** Option to specify domains to bypass SRI injection, plus a `skip-sri` attribute to opt out a single tag.
|
|
31
|
+
- **Public Directory Support:** Assets served verbatim from `publicDir` are hashed from disk, not just bundle outputs.
|
|
32
|
+
- **Zero Dependencies:** No runtime dependencies, and TypeScript definitions are included.
|
|
28
33
|
- **Missing Asset Handling:** Configurable warning suppression for missing assets.
|
|
29
34
|
- **Robust Content Support:** Handles various content types including strings, Buffer, and Uint8Array.
|
|
30
|
-
- **
|
|
35
|
+
- **Dynamic Routes:** Optional import map integrity and an SRI manifest cover `import()`-loaded chunks and SSR builds, which have no build-time HTML tag to rewrite.
|
|
36
|
+
- **Vite Compatibility:** Compatible with Vite 6.4, 7.0 and 8.0 (including the Rolldown-based native build path). `6.4` is the floor because it is the only Vite 6 line still receiving upstream security patches.
|
|
31
37
|
|
|
32
38
|
## Installation
|
|
33
39
|
|
|
@@ -47,14 +53,21 @@ import sri from 'vite-plugin-sri4';
|
|
|
47
53
|
export default defineConfig({
|
|
48
54
|
plugins: [
|
|
49
55
|
sri({
|
|
50
|
-
// Optional.
|
|
56
|
+
// Optional. 'sha256' | 'sha384' | 'sha512'. Defaults to 'sha384'.
|
|
51
57
|
hashAlgorithm: 'sha384',
|
|
58
|
+
// Optional. 'anonymous' | 'use-credentials'. Defaults to 'anonymous'.
|
|
59
|
+
crossorigin: 'anonymous',
|
|
52
60
|
// Optional. Domains to bypass SRI injection.
|
|
53
61
|
bypassDomains: ['example.com'],
|
|
54
62
|
// Optional. Suppress warnings for missing assets.
|
|
55
63
|
ignoreMissingAsset: false,
|
|
56
64
|
// Optional. Log verbosity: 'silent' | 'error' | 'warn' | 'info' | 'debug'. Defaults to 'warn'.
|
|
57
|
-
logLevel: 'warn'
|
|
65
|
+
logLevel: 'warn',
|
|
66
|
+
// Optional. Inject an import map carrying integrity for every JS chunk,
|
|
67
|
+
// covering dynamically imported routes. Defaults to false.
|
|
68
|
+
importmap: false,
|
|
69
|
+
// Optional. Emit dist/sri-manifest.json for SSR to read. Defaults to false.
|
|
70
|
+
manifest: false
|
|
58
71
|
})
|
|
59
72
|
]
|
|
60
73
|
});
|
|
@@ -77,13 +90,90 @@ Output:
|
|
|
77
90
|
## Plugin Options
|
|
78
91
|
|
|
79
92
|
* `hashAlgorithm` (string):
|
|
80
|
-
The hash algorithm used for computing SRI.
|
|
93
|
+
The hash algorithm used for computing SRI. One of `sha256`, `sha384` (default) or `sha512` — the only three the SRI spec defines. Anything else fails at startup rather than producing an attribute browsers silently reject.
|
|
94
|
+
* `crossorigin` (string):
|
|
95
|
+
Value for the injected `crossorigin` attribute: `anonymous` (default) or `use-credentials`. Use the latter for a CDN that requires cookies or HTTP auth. Tags that already declare a `crossorigin` are left alone.
|
|
81
96
|
* `bypassDomains` (Array<string>):
|
|
82
97
|
Array of domain names where SRI injection should be skipped. This allows external resources from specified domains to be excluded from SRI checks (for example, when they may not support CORS).
|
|
83
98
|
* `ignoreMissingAsset` (boolean):
|
|
84
|
-
When true,
|
|
99
|
+
When true, warns instead of failing the build for assets found in neither the bundle nor `publicDir`. Default is `false`, which fails the build rather than shipping a tag with no integrity.
|
|
85
100
|
* `logLevel` (string):
|
|
86
101
|
Log verbosity. One of `silent`, `error`, `warn`, `info`, `debug`. Default is `warn`. Use `debug` to see per-resource decisions during the build.
|
|
102
|
+
* `importmap` (boolean):
|
|
103
|
+
Inject a `<script type="importmap">` containing an `integrity` map for every JS chunk in the build. Default is `false`. See [Dynamic routes](#dynamic-routes).
|
|
104
|
+
* `manifest` (boolean):
|
|
105
|
+
Emit `sri-manifest.json` alongside the build, mapping every non-HTML output file to its SRI hash. Default is `false`. See [Dynamic routes](#dynamic-routes).
|
|
106
|
+
|
|
107
|
+
## Dynamic routes
|
|
108
|
+
|
|
109
|
+
Rewriting HTML tags can only protect resources that have a tag at build time. A route loaded with `import()` has none - Vite's preload helper creates the `<link rel="modulepreload">` at runtime - and an SSR build emits no HTML at all. Two options cover those cases.
|
|
110
|
+
|
|
111
|
+
### `importmap: true` (client-side dynamic imports)
|
|
112
|
+
|
|
113
|
+
Emits an import map whose `integrity` key covers every JS chunk, including chunks only ever reached through `import()`:
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<script type="importmap">{"integrity":{"/assets/about-a1b2c3.js":"sha384-..."}}</script>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The map is injected before the first `<script>` so it applies to every module. Engines without support ignore the `integrity` key rather than failing, so this degrades safely - but check current browser support before relying on it as your only protection.
|
|
120
|
+
|
|
121
|
+
### `manifest: true` (SSR / server-rendered HTML)
|
|
122
|
+
|
|
123
|
+
Emits `sri-manifest.json` mapping output file names to hashes, which a server rendering HTML per request can read:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"assets/index-a1b2c3.js": "sha384-...",
|
|
128
|
+
"assets/index-d4e5f6.css": "sha384-..."
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This is the only mechanism available when the build produces no HTML asset.
|
|
133
|
+
|
|
134
|
+
### Caveat for both
|
|
135
|
+
|
|
136
|
+
Hashes are computed during the build. A plugin that mutates chunk contents after this one (`@vitejs/plugin-legacy`, compression plugins that rewrite in place) would invalidate them, so the plugin re-hashes every file it touched in `writeBundle` and fails the build if anything drifted. You get a build error rather than a page that only breaks in the browser.
|
|
137
|
+
|
|
138
|
+
## When SRI Actually Helps
|
|
139
|
+
|
|
140
|
+
SRI is worth the most when your HTML and your assets have **different trust boundaries** - typically HTML served from your own origin and JS/CSS served from a CDN (`base: 'https://cdn.example.com/'`). If the CDN is compromised or a cache is poisoned, the integrity attribute in your origin-served HTML is what stops the browser from running the tampered file. That is the case this plugin is built for.
|
|
141
|
+
|
|
142
|
+
If everything is served from a single origin, SRI buys much less than it appears to: an attacker who can rewrite `/assets/index-abc123.js` on your server can usually rewrite the `index.html` carrying its hash just as easily. It is not useless - it narrows some deploy and cache-layer mistakes - but for same-origin builds, a Content Security Policy and Vite's default hashed, immutable filenames do more for you than SRI does. Enable it because it is cheap, not because it closes the hole you think it closes.
|
|
143
|
+
|
|
144
|
+
### Skipping a Single Tag
|
|
145
|
+
|
|
146
|
+
`bypassDomains` only reaches external hosts. To exclude one specific element, add `skip-sri` to it. The attribute is stripped from the output:
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<script skip-sri src="/legacy.js"></script>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<!-- built output -->
|
|
154
|
+
<script src="/legacy.js"></script>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## How It Attaches Hashes
|
|
158
|
+
|
|
159
|
+
There are three places a Vite plugin can compute SRI hashes, and they are not equivalent. This one matters more than it looks, so it is worth writing down.
|
|
160
|
+
|
|
161
|
+
**In `transformIndexHtml`.** The obvious choice, and the one that reads best — you get the finished HTML and the bundle on the context. It produces wrong hashes for entry chunks. Vite's import-analysis plugin substitutes `__VITE_PRELOAD__` inside its own `generateBundle`, which runs *after* `transformIndexHtml`, so an entry chunk still reads `import("./route.js"), __VITE_PRELOAD__)` at that point while the written file reads `import("./route.js"), [])`. The hash describes bytes that never ship, and the browser rejects the file with no build error at all.
|
|
162
|
+
|
|
163
|
+
**In a plain `enforce: 'post'` `generateBundle`.** Same problem. Vite places its import-analysis plugin immediately after post user plugins, so a post hook is still one step too early.
|
|
164
|
+
|
|
165
|
+
**Where this plugin does it.** During `configResolved` it moves itself after that plugin in `config.plugins`, then works in an ordinary `generateBundle`. Measured on Vite 8.2.2, hashing the entry chunk:
|
|
166
|
+
|
|
167
|
+
| Hook | Entry chunk | Matches shipped file |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `transformIndexHtml` (post) | `io6MKsmc4G5y` | ✗ |
|
|
170
|
+
| `generateBundle` (post) | `io6MKsmc4G5y` | ✗ |
|
|
171
|
+
| after repositioning | `lvFyraHkqPN0` | ✓ |
|
|
172
|
+
| written file | `lvFyraHkqPN0` | — |
|
|
173
|
+
|
|
174
|
+
Only the entry chunk is affected, so a build without a dynamic import will not reveal the difference. As a second safeguard, every hashed file is re-hashed in `writeBundle` and the build fails if anything changed after the hash was taken.
|
|
175
|
+
|
|
176
|
+
This ordering constraint was first identified by [vite-plugin-sri3](https://github.com/yoyo930021/vite-plugin-sri3), which this plugin began as a fork of. Beyond it, this plugin adds `crossorigin` injection, a CORS pre-check with timeouts and retries for external resources, import map and manifest output for dynamically imported routes, `publicDir` resolution, and the drift check above.
|
|
87
177
|
|
|
88
178
|
## Example Project
|
|
89
179
|
|