vite-plugin-sri4 1.6.0 → 1.8.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.
Files changed (3) hide show
  1. package/dist/index.cjs +153 -91
  2. package/dist/index.js +153 -91
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3,6 +3,8 @@
3
3
  var node_crypto = require('node:crypto');
4
4
  var fetch = require('cross-fetch');
5
5
 
6
+ const LOG_PREFIX = '[vite-plugin-sri4]';
7
+
6
8
  const DEFAULT_OPTIONS = {
7
9
  algorithm: 'sha384',
8
10
  bypassDomains: [],
@@ -12,7 +14,7 @@ const DEFAULT_OPTIONS = {
12
14
 
13
15
  function log(message, options) {
14
16
  if (options.debug) {
15
- console.log(`[vite-plugin-sri4] ${message}`);
17
+ console.log(`${LOG_PREFIX} ${message}`);
16
18
  }
17
19
  }
18
20
 
@@ -23,7 +25,7 @@ function computeSri(content, algorithm = 'sha384') {
23
25
  .digest('base64');
24
26
  return `${algorithm}-${hash}`;
25
27
  } catch (error) {
26
- console.error(`[vite-plugin-sri4] Failed to compute SRI hash: ${error}`);
28
+ console.error(`${LOG_PREFIX} Failed to compute SRI hash: ${error}`);
27
29
  return null;
28
30
  }
29
31
  }
@@ -31,8 +33,7 @@ function computeSri(content, algorithm = 'sha384') {
31
33
  async function externalResourceIsCorsEnabled(url, options) {
32
34
  try {
33
35
  const response = await fetch(url, {
34
- method: 'HEAD',
35
- timeout: 5000
36
+ method: 'HEAD'
36
37
  });
37
38
  const acao = response.headers.get('access-control-allow-origin');
38
39
  if (acao && (acao === '*' || acao.includes(options.domain || ''))) {
@@ -45,38 +46,12 @@ async function externalResourceIsCorsEnabled(url, options) {
45
46
  }
46
47
  }
47
48
 
48
- async function replaceAsync(str, regex, asyncFn) {
49
- const promises = [];
50
- const matches = [];
51
-
52
- str.replace(regex, (...args) => {
53
- matches.push(args);
54
- promises.push(asyncFn(...args));
55
- return '';
56
- });
57
-
58
- const results = await Promise.all(promises);
59
-
60
- let lastIndex = 0;
61
- let result = '';
62
-
63
- for (let i = 0; i < matches.length; i++) {
64
- const match = matches[i][0];
65
- const index = str.indexOf(match, lastIndex);
66
- result += str.slice(lastIndex, index) + results[i];
67
- lastIndex = index + match.length;
68
- }
69
-
70
- result += str.slice(lastIndex);
71
- return result;
72
- }
73
-
74
49
  function isBypassDomain(url, bypassDomains = []) {
75
50
  if (!bypassDomains.length) return false;
76
51
  try {
77
52
  const parsedUrl = url.startsWith('//')
78
- ? new URL(url, 'http://dummy')
79
- : new URL(url);
53
+ ? new URL(`http:${url}`)
54
+ : new URL(url, 'http://dummy');
80
55
  return bypassDomains.some(
81
56
  (domain) => parsedUrl.hostname === domain ||
82
57
  parsedUrl.hostname.endsWith(`.${domain}`)
@@ -90,92 +65,179 @@ function hasCrossOriginAttr(tag) {
90
65
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
91
66
  }
92
67
 
68
+ function getAllPossiblePaths(url) {
69
+ const paths = [
70
+ url,
71
+ url.startsWith('/') ? url.slice(1) : url,
72
+ url.startsWith('/static/') ? url.slice(8) : url,
73
+ !url.startsWith('/static/') ? `static/${url}` : url,
74
+ !url.startsWith('/static/') ? `/static/${url}` : url,
75
+ url.replace(/^\/static\//, ''),
76
+ url.replace(/^static\//, '')
77
+ ];
78
+
79
+ const withoutHash = url.replace(/-[a-zA-Z0-9]+\./, '.');
80
+ if (withoutHash !== url) {
81
+ paths.push(...getAllPossiblePaths(withoutHash));
82
+ }
83
+
84
+ return [...new Set(paths)];
85
+ }
86
+
87
+ async function processTag(tag, url, options, sriMap) {
88
+ if (tag.includes('integrity=')) {
89
+ log(`Skip tag with existing integrity attribute: ${tag}`, options);
90
+ return tag;
91
+ }
92
+
93
+ log(`Processing tag: ${tag}`, options);
94
+ log(`URL: ${url}`, options);
95
+
96
+ // Handle external resources
97
+ if (/^(https?:)?\/\//i.test(url)) {
98
+ if (isBypassDomain(url, options.bypassDomains)) {
99
+ log(`Skip SRI for bypass domain: ${url}`, options);
100
+ return tag;
101
+ }
102
+
103
+ const corsOk = await externalResourceIsCorsEnabled(url, options);
104
+ if (!corsOk) {
105
+ log(`External resource ${url} does not support CORS`, options);
106
+ return tag;
107
+ }
108
+
109
+ try {
110
+ const response = await fetch(url);
111
+ const content = await response.arrayBuffer();
112
+ const hash = computeSri(Buffer.from(content), options.algorithm);
113
+ if (hash) {
114
+ log(`Computing SRI for external resource ${url}: ${hash}`, options);
115
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
116
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
117
+ const newTag = tag.replace(/>$/, ` integrity="${hash}"${crossOriginAttr}>`);
118
+ log(`New tag: ${newTag}`, options);
119
+ return newTag;
120
+ }
121
+ } catch (error) {
122
+ log(`Failed to process external resource ${url}: ${error}`, options);
123
+ }
124
+ return tag;
125
+ }
126
+
127
+ // Handle local resources
128
+ const possiblePaths = getAllPossiblePaths(url);
129
+ let integrity = null;
130
+
131
+ log(`Checking possible paths for ${url}:`, options);
132
+ for (const path of possiblePaths) {
133
+ log(`- Checking path: ${path}`, options);
134
+ if (sriMap.has(path)) {
135
+ integrity = sriMap.get(path);
136
+ log(`Found integrity for path ${path}: ${integrity}`, options);
137
+ break;
138
+ }
139
+ }
140
+
141
+ if (integrity) {
142
+ log(`Using precomputed SRI for ${url}: ${integrity}`, options);
143
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
144
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
145
+ const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
146
+ log(`New tag: ${newTag}`, options);
147
+ return newTag;
148
+ }
149
+
150
+ log(`No SRI hash found for ${url}`, options);
151
+ log(`Available paths in sriMap: ${Array.from(sriMap.keys()).join(', ')}`, options);
152
+ return tag;
153
+ }
154
+
93
155
  function sri(userOptions = {}) {
94
156
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
95
157
  const sriMap = new Map();
158
+ let isBuild = false;
96
159
 
97
160
  return {
98
161
  name: 'vite-plugin-sri4',
99
162
  apply: 'build',
163
+ enforce: 'post',
100
164
 
101
165
  configResolved(config) {
102
166
  options.domain = config.server?.host || '';
167
+ isBuild = config.command === 'build';
168
+ log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
169
+ },
170
+
171
+ async renderChunk(code, chunk) {
172
+ if (!isBuild) return null;
173
+
174
+ const hash = computeSri(code, options.algorithm);
175
+ if (hash) {
176
+ for (const path of getAllPossiblePaths(chunk.fileName)) {
177
+ sriMap.set(path, hash);
178
+ log(`Stored SRI for path ${path}: ${hash}`, options);
179
+ }
180
+ }
181
+ return null;
103
182
  },
104
183
 
105
184
  async generateBundle(_, bundle) {
185
+ if (!isBuild) return;
186
+
106
187
  for (const fileName in bundle) {
107
188
  const chunk = bundle[fileName];
108
- if (chunk.type === 'chunk' || chunk.type === 'asset') {
109
- const content = chunk.code || chunk.source;
110
- if (content) {
111
- const hash = computeSri(content, options.algorithm);
112
- if (hash) {
113
- sriMap.set(fileName, hash);
114
- log(`Computed SRI for ${fileName}: ${hash}`, options);
189
+ if (chunk.type === 'asset' && !sriMap.has(fileName)) {
190
+ const hash = computeSri(chunk.source, options.algorithm);
191
+ if (hash) {
192
+ for (const path of getAllPossiblePaths(fileName)) {
193
+ sriMap.set(path, hash);
194
+ log(`Computing SRI for asset ${path}: ${hash}`, options);
115
195
  }
116
196
  }
117
197
  }
118
198
  }
199
+
200
+ log('Final sriMap contents:', options);
201
+ for (const [key, value] of sriMap.entries()) {
202
+ log(`${key} => ${value}`, options);
203
+ }
119
204
  },
120
205
 
121
206
  async transformIndexHtml(html) {
122
- const hasIntegrity = (tag) => /integrity=/i.test(tag);
123
- const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
124
-
125
- const processTag = async (match, tag, src, moduleSrc) => {
126
- const actualSrc = src || moduleSrc;
207
+ if (!isBuild || !html) {
208
+ log('Skipping HTML transform in dev mode or empty HTML', options);
209
+ return html;
210
+ }
127
211
 
128
- if (hasIntegrity(tag)) {
129
- return tag;
212
+ try {
213
+ log('Starting HTML transformation', options);
214
+ log(`SRI Map size: ${sriMap.size}`, options);
215
+
216
+ // Process script tags
217
+ const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
218
+ log(`Found ${scriptTags.length} script tags`, options);
219
+ for (const tag of scriptTags) {
220
+ const url = tag.match(/src=["']([^"']+)["']/)[1];
221
+ log(`Processing script: ${url}`, options);
222
+ const newTag = await processTag(tag, url, options, sriMap);
223
+ html = html.replace(tag, newTag);
130
224
  }
131
225
 
132
- if (isExternalUrl(actualSrc) &&
133
- isBypassDomain(actualSrc, options.bypassDomains)) {
134
- log(`Skipping SRI injection for bypass domain: ${actualSrc}`, options);
135
- return tag;
226
+ // Process link tags
227
+ const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
228
+ log(`Found ${linkTags.length} link tags`, options);
229
+ for (const tag of linkTags) {
230
+ const url = tag.match(/href=["']([^"']+)["']/)[1];
231
+ log(`Processing link: ${url}`, options);
232
+ const newTag = await processTag(tag, url, options, sriMap);
233
+ html = html.replace(tag, newTag);
136
234
  }
137
235
 
138
- if (isExternalUrl(actualSrc)) {
139
- const corsOk = await externalResourceIsCorsEnabled(actualSrc, options);
140
- if (!corsOk) {
141
- log(`External resource ${actualSrc} does not support CORS`, options);
142
- return tag;
143
- }
144
- }
145
-
146
- const fileName = actualSrc.startsWith('/') ? actualSrc.slice(1) : actualSrc;
147
- const integrity = sriMap.get(fileName);
148
-
149
- if (integrity) {
150
- const hasCrossOrigin = hasCrossOriginAttr(tag);
151
- if (!hasCrossOrigin) {
152
- return tag.replace(
153
- />$/,
154
- ` integrity="${integrity}" crossorigin="${options.crossorigin}">`
155
- );
156
- }
157
- return tag.replace(
158
- />$/,
159
- ` integrity="${integrity}">`
160
- );
161
- }
162
-
163
- return tag;
164
- };
165
-
166
- html = await replaceAsync(
167
- html,
168
- /(<script[^>]+(?:src="([^"]+)"[^>]*|type="module"[^>]*src="([^"]+)"[^>]*)>)/g,
169
- processTag
170
- );
171
-
172
- html = await replaceAsync(
173
- html,
174
- /(<link[^>]+href="([^"]+)"[^>]*>)/g,
175
- processTag
176
- );
177
-
178
- return html;
236
+ return html;
237
+ } catch (error) {
238
+ console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
239
+ return html;
240
+ }
179
241
  }
180
242
  };
181
243
  }
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import fetch from 'cross-fetch';
3
3
 
4
+ const LOG_PREFIX = '[vite-plugin-sri4]';
5
+
4
6
  const DEFAULT_OPTIONS = {
5
7
  algorithm: 'sha384',
6
8
  bypassDomains: [],
@@ -10,7 +12,7 @@ const DEFAULT_OPTIONS = {
10
12
 
11
13
  function log(message, options) {
12
14
  if (options.debug) {
13
- console.log(`[vite-plugin-sri4] ${message}`);
15
+ console.log(`${LOG_PREFIX} ${message}`);
14
16
  }
15
17
  }
16
18
 
@@ -21,7 +23,7 @@ function computeSri(content, algorithm = 'sha384') {
21
23
  .digest('base64');
22
24
  return `${algorithm}-${hash}`;
23
25
  } catch (error) {
24
- console.error(`[vite-plugin-sri4] Failed to compute SRI hash: ${error}`);
26
+ console.error(`${LOG_PREFIX} Failed to compute SRI hash: ${error}`);
25
27
  return null;
26
28
  }
27
29
  }
@@ -29,8 +31,7 @@ function computeSri(content, algorithm = 'sha384') {
29
31
  async function externalResourceIsCorsEnabled(url, options) {
30
32
  try {
31
33
  const response = await fetch(url, {
32
- method: 'HEAD',
33
- timeout: 5000
34
+ method: 'HEAD'
34
35
  });
35
36
  const acao = response.headers.get('access-control-allow-origin');
36
37
  if (acao && (acao === '*' || acao.includes(options.domain || ''))) {
@@ -43,38 +44,12 @@ async function externalResourceIsCorsEnabled(url, options) {
43
44
  }
44
45
  }
45
46
 
46
- async function replaceAsync(str, regex, asyncFn) {
47
- const promises = [];
48
- const matches = [];
49
-
50
- str.replace(regex, (...args) => {
51
- matches.push(args);
52
- promises.push(asyncFn(...args));
53
- return '';
54
- });
55
-
56
- const results = await Promise.all(promises);
57
-
58
- let lastIndex = 0;
59
- let result = '';
60
-
61
- for (let i = 0; i < matches.length; i++) {
62
- const match = matches[i][0];
63
- const index = str.indexOf(match, lastIndex);
64
- result += str.slice(lastIndex, index) + results[i];
65
- lastIndex = index + match.length;
66
- }
67
-
68
- result += str.slice(lastIndex);
69
- return result;
70
- }
71
-
72
47
  function isBypassDomain(url, bypassDomains = []) {
73
48
  if (!bypassDomains.length) return false;
74
49
  try {
75
50
  const parsedUrl = url.startsWith('//')
76
- ? new URL(url, 'http://dummy')
77
- : new URL(url);
51
+ ? new URL(`http:${url}`)
52
+ : new URL(url, 'http://dummy');
78
53
  return bypassDomains.some(
79
54
  (domain) => parsedUrl.hostname === domain ||
80
55
  parsedUrl.hostname.endsWith(`.${domain}`)
@@ -88,92 +63,179 @@ function hasCrossOriginAttr(tag) {
88
63
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
89
64
  }
90
65
 
66
+ function getAllPossiblePaths(url) {
67
+ const paths = [
68
+ url,
69
+ url.startsWith('/') ? url.slice(1) : url,
70
+ url.startsWith('/static/') ? url.slice(8) : url,
71
+ !url.startsWith('/static/') ? `static/${url}` : url,
72
+ !url.startsWith('/static/') ? `/static/${url}` : url,
73
+ url.replace(/^\/static\//, ''),
74
+ url.replace(/^static\//, '')
75
+ ];
76
+
77
+ const withoutHash = url.replace(/-[a-zA-Z0-9]+\./, '.');
78
+ if (withoutHash !== url) {
79
+ paths.push(...getAllPossiblePaths(withoutHash));
80
+ }
81
+
82
+ return [...new Set(paths)];
83
+ }
84
+
85
+ async function processTag(tag, url, options, sriMap) {
86
+ if (tag.includes('integrity=')) {
87
+ log(`Skip tag with existing integrity attribute: ${tag}`, options);
88
+ return tag;
89
+ }
90
+
91
+ log(`Processing tag: ${tag}`, options);
92
+ log(`URL: ${url}`, options);
93
+
94
+ // Handle external resources
95
+ if (/^(https?:)?\/\//i.test(url)) {
96
+ if (isBypassDomain(url, options.bypassDomains)) {
97
+ log(`Skip SRI for bypass domain: ${url}`, options);
98
+ return tag;
99
+ }
100
+
101
+ const corsOk = await externalResourceIsCorsEnabled(url, options);
102
+ if (!corsOk) {
103
+ log(`External resource ${url} does not support CORS`, options);
104
+ return tag;
105
+ }
106
+
107
+ try {
108
+ const response = await fetch(url);
109
+ const content = await response.arrayBuffer();
110
+ const hash = computeSri(Buffer.from(content), options.algorithm);
111
+ if (hash) {
112
+ log(`Computing SRI for external resource ${url}: ${hash}`, options);
113
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
114
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
115
+ const newTag = tag.replace(/>$/, ` integrity="${hash}"${crossOriginAttr}>`);
116
+ log(`New tag: ${newTag}`, options);
117
+ return newTag;
118
+ }
119
+ } catch (error) {
120
+ log(`Failed to process external resource ${url}: ${error}`, options);
121
+ }
122
+ return tag;
123
+ }
124
+
125
+ // Handle local resources
126
+ const possiblePaths = getAllPossiblePaths(url);
127
+ let integrity = null;
128
+
129
+ log(`Checking possible paths for ${url}:`, options);
130
+ for (const path of possiblePaths) {
131
+ log(`- Checking path: ${path}`, options);
132
+ if (sriMap.has(path)) {
133
+ integrity = sriMap.get(path);
134
+ log(`Found integrity for path ${path}: ${integrity}`, options);
135
+ break;
136
+ }
137
+ }
138
+
139
+ if (integrity) {
140
+ log(`Using precomputed SRI for ${url}: ${integrity}`, options);
141
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
142
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
143
+ const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
144
+ log(`New tag: ${newTag}`, options);
145
+ return newTag;
146
+ }
147
+
148
+ log(`No SRI hash found for ${url}`, options);
149
+ log(`Available paths in sriMap: ${Array.from(sriMap.keys()).join(', ')}`, options);
150
+ return tag;
151
+ }
152
+
91
153
  function sri(userOptions = {}) {
92
154
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
93
155
  const sriMap = new Map();
156
+ let isBuild = false;
94
157
 
95
158
  return {
96
159
  name: 'vite-plugin-sri4',
97
160
  apply: 'build',
161
+ enforce: 'post',
98
162
 
99
163
  configResolved(config) {
100
164
  options.domain = config.server?.host || '';
165
+ isBuild = config.command === 'build';
166
+ log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
167
+ },
168
+
169
+ async renderChunk(code, chunk) {
170
+ if (!isBuild) return null;
171
+
172
+ const hash = computeSri(code, options.algorithm);
173
+ if (hash) {
174
+ for (const path of getAllPossiblePaths(chunk.fileName)) {
175
+ sriMap.set(path, hash);
176
+ log(`Stored SRI for path ${path}: ${hash}`, options);
177
+ }
178
+ }
179
+ return null;
101
180
  },
102
181
 
103
182
  async generateBundle(_, bundle) {
183
+ if (!isBuild) return;
184
+
104
185
  for (const fileName in bundle) {
105
186
  const chunk = bundle[fileName];
106
- if (chunk.type === 'chunk' || chunk.type === 'asset') {
107
- const content = chunk.code || chunk.source;
108
- if (content) {
109
- const hash = computeSri(content, options.algorithm);
110
- if (hash) {
111
- sriMap.set(fileName, hash);
112
- log(`Computed SRI for ${fileName}: ${hash}`, options);
187
+ if (chunk.type === 'asset' && !sriMap.has(fileName)) {
188
+ const hash = computeSri(chunk.source, options.algorithm);
189
+ if (hash) {
190
+ for (const path of getAllPossiblePaths(fileName)) {
191
+ sriMap.set(path, hash);
192
+ log(`Computing SRI for asset ${path}: ${hash}`, options);
113
193
  }
114
194
  }
115
195
  }
116
196
  }
197
+
198
+ log('Final sriMap contents:', options);
199
+ for (const [key, value] of sriMap.entries()) {
200
+ log(`${key} => ${value}`, options);
201
+ }
117
202
  },
118
203
 
119
204
  async transformIndexHtml(html) {
120
- const hasIntegrity = (tag) => /integrity=/i.test(tag);
121
- const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
122
-
123
- const processTag = async (match, tag, src, moduleSrc) => {
124
- const actualSrc = src || moduleSrc;
205
+ if (!isBuild || !html) {
206
+ log('Skipping HTML transform in dev mode or empty HTML', options);
207
+ return html;
208
+ }
125
209
 
126
- if (hasIntegrity(tag)) {
127
- return tag;
210
+ try {
211
+ log('Starting HTML transformation', options);
212
+ log(`SRI Map size: ${sriMap.size}`, options);
213
+
214
+ // Process script tags
215
+ const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
216
+ log(`Found ${scriptTags.length} script tags`, options);
217
+ for (const tag of scriptTags) {
218
+ const url = tag.match(/src=["']([^"']+)["']/)[1];
219
+ log(`Processing script: ${url}`, options);
220
+ const newTag = await processTag(tag, url, options, sriMap);
221
+ html = html.replace(tag, newTag);
128
222
  }
129
223
 
130
- if (isExternalUrl(actualSrc) &&
131
- isBypassDomain(actualSrc, options.bypassDomains)) {
132
- log(`Skipping SRI injection for bypass domain: ${actualSrc}`, options);
133
- return tag;
224
+ // Process link tags
225
+ const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
226
+ log(`Found ${linkTags.length} link tags`, options);
227
+ for (const tag of linkTags) {
228
+ const url = tag.match(/href=["']([^"']+)["']/)[1];
229
+ log(`Processing link: ${url}`, options);
230
+ const newTag = await processTag(tag, url, options, sriMap);
231
+ html = html.replace(tag, newTag);
134
232
  }
135
233
 
136
- if (isExternalUrl(actualSrc)) {
137
- const corsOk = await externalResourceIsCorsEnabled(actualSrc, options);
138
- if (!corsOk) {
139
- log(`External resource ${actualSrc} does not support CORS`, options);
140
- return tag;
141
- }
142
- }
143
-
144
- const fileName = actualSrc.startsWith('/') ? actualSrc.slice(1) : actualSrc;
145
- const integrity = sriMap.get(fileName);
146
-
147
- if (integrity) {
148
- const hasCrossOrigin = hasCrossOriginAttr(tag);
149
- if (!hasCrossOrigin) {
150
- return tag.replace(
151
- />$/,
152
- ` integrity="${integrity}" crossorigin="${options.crossorigin}">`
153
- );
154
- }
155
- return tag.replace(
156
- />$/,
157
- ` integrity="${integrity}">`
158
- );
159
- }
160
-
161
- return tag;
162
- };
163
-
164
- html = await replaceAsync(
165
- html,
166
- /(<script[^>]+(?:src="([^"]+)"[^>]*|type="module"[^>]*src="([^"]+)"[^>]*)>)/g,
167
- processTag
168
- );
169
-
170
- html = await replaceAsync(
171
- html,
172
- /(<link[^>]+href="([^"]+)"[^>]*>)/g,
173
- processTag
174
- );
175
-
176
- return html;
234
+ return html;
235
+ } catch (error) {
236
+ console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
237
+ return html;
238
+ }
177
239
  }
178
240
  };
179
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-sri4",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "A Vite plugin to generate Subresource Integrity (SRI) hashes for output files.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",