@auioc/rollup-plugin-html 1.0.0 → 1.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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  A Rollup plugin that generates an HTML file from a template, automatically injecting bundled JavaScript and CSS assets.
7
7
 
8
- Supports placeholders, conditional stripping, and optional HTML minification.
8
+ Supports external assets, placeholders, conditional stripping, and optional HTML minification.
9
9
 
10
10
  ## Install
11
11
 
@@ -21,7 +21,7 @@ import html from '@auioc/rollup-plugin-html';
21
21
 
22
22
  export default {
23
23
  input: 'src/index.js',
24
- output: { dir: 'dist', format: 'es' },
24
+ output: { file: 'bundle.js', format: 'iife', name: 'bundle' },
25
25
  plugins: [
26
26
  html({
27
27
  template: 'src/index.html',
@@ -32,49 +32,109 @@ export default {
32
32
 
33
33
  ## Options
34
34
 
35
- | Option | Type | Default | Description |
36
- | ---------------------- | ------------------------------ | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
- | `template` | `string` | | Path to the template `.html` file, resolved relative to `process.cwd()`. **required**. |
38
- | `output` | `string` | `'index.html'` | Output file name of the emitted HTML file. |
39
- | `injectStyle` | `boolean` | `true` | Whether to inject bundled CSS files. |
40
- | `injectScript` | `boolean` \| `'module'` | `true` | Whether to inject bundled JS files. Use `'module'` to add `type="module"`. |
41
- | `styleTagPlaceholder` | `string` | `'<!-- inject:style -->'` | Placeholder comment replaced by CSS tags. |
42
- | `scriptTagPlaceholder` | `string` | `'<!-- inject:script -->'` | Placeholder comment replaced by script tags. |
43
- | `stripTag` | `string` | `'strip'` | Tag name used for strip comment blocks. |
44
- | `minify` | `boolean` \| `MinifierOptions` | `false` | Minify the output HTML with [html-minifier-terser](https://www.npmjs.com/package/html-minifier-terser). Pass an object to forward html-minifier-terser options. |
35
+ | Option | Type | Default | Description |
36
+ | ---------------------- | ---------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | `template` | `string` | | **Required**. Path to the template `.html` file, resolved relative to `process.cwd()`. |
38
+ | `output` | `string` | `'index.html'` | Output file name of the emitted HTML file. |
39
+ | `injectStyle` | `boolean` | `true` | Whether to inject styles. |
40
+ | `injectScript` | `boolean` \| `'module'` | `true` | Whether to inject scripts. Use `'module'` to add `type="module"`. |
41
+ | `external` | `{ style?: Asset[]; script?: Asset[] }` | `{ }` | External assets to inject. Their tags are placed before the bundled ones. See [External Assets](#external-assets). |
42
+ | `styleTagPlaceholder` | `string` | `'<!-- inject:style -->'` | Placeholder comment replaced by CSS tags. |
43
+ | `scriptTagPlaceholder` | `string` | `'<!-- inject:script -->'` | Placeholder comment replaced by script tags. |
44
+ | `stripTag` | `string` | `'strip'` | Tag name used for strip comment blocks. |
45
+ | `minify` | `boolean` \| `MinifierOptions` | `false` | Minify the output HTML with [html-minifier-terser](https://www.npmjs.com/package/html-minifier-terser). Pass an object to forward html-minifier-terser options. |
46
+ | `cacheBusting` | `CacheBusting` (`boolean` \| `string` \| `Function`) | `false` | Append a query string to bundled asset URLs. See [Cache busting](#4-cache-busting). |
47
+
48
+ - Asset
49
+
50
+ ```typescript
51
+ type Asset =
52
+ | string // treated as URL
53
+ | {
54
+ url: string;
55
+ integrity?: string;
56
+ crossorigin?: 'anonymous' | 'use-credentials';
57
+ };
58
+ ```
59
+
60
+ - CacheBusting
61
+
62
+ ```typescript
63
+ type CacheBusting =
64
+ | boolean
65
+ | string
66
+ | ((
67
+ fileName: string,
68
+ content: string | Uint8Array
69
+ ) => string | undefined | false);
70
+ ```
45
71
 
46
72
  ## How It Works
47
73
 
48
74
  ### 1. Injection
49
75
 
50
- When the bundle is generated, the plugin collects:
76
+ Assets are injected into the template in one of two ways:
51
77
 
52
- - **CSS assets** (any emitted asset ending in `.css`)
53
- - **JS chunks** that are entry points or dynamic entry points (files ending in `.js`)
78
+ - **Using placeholders** (Recommended)
54
79
 
55
- These are injected into the template in one of two ways:
80
+ ```html
81
+ <!DOCTYPE html>
82
+ <html>
83
+ <head>
84
+ <title>My App</title>
85
+ <!-- inject:style -->
86
+ </head>
87
+ <body>
88
+ <div id="app"></div>
89
+ <!-- inject:script -->
90
+ </body>
91
+ </html>
92
+ ```
56
93
 
57
- #### Using placeholders (Recommended)
94
+ The placeholders are configurable via the `styleTagPlaceholder`, `scriptTagPlaceholder` options.
58
95
 
59
- ```html
60
- <!DOCTYPE html>
61
- <html>
62
- <head>
63
- <title>My App</title>
64
- <!-- inject:style -->
65
- </head>
66
- <body>
67
- <div id="app"></div>
68
- <!-- inject:script -->
69
- </body>
70
- </html>
71
- ```
96
+ - **Using fallbacks**
97
+
98
+ If placeholders are not present, tags are inserted before `</head>` (CSS) or `</body>` (JS) when those tags exist;
99
+
100
+ Otherwise they are prepended (CSS) or appended (JS) to the document.
101
+
102
+ #### Bundled Assets
103
+
104
+ When the bundle is generated, the plugin collects:
105
+
106
+ - **CSS assets** (any emitted asset ending in `.css`)
107
+ - **JS chunks** that are entry points (files ending in `.js`)
72
108
 
73
- The placeholders are configurable via the `styleTagPlaceholder`, `scriptTagPlaceholder` options.
109
+ #### External Assets
74
110
 
75
- #### Using fallbacks
111
+ Use the `external` option to inject assets that are not produced by Rollup (e.g. CDN scripts, third-party stylesheets).
76
112
 
77
- If placeholders are not present, tags are inserted before `</head>` (CSS) or `</body>` (JS) when those tags exist; otherwise they are prepended (CSS) or appended (JS) to the document.
113
+ External tags are always emitted **before** the bundled tags within the same injection slot.
114
+
115
+ ```js
116
+ html({
117
+ template: 'src/index.html',
118
+ external: {
119
+ style: [
120
+ 'https://cdn.example.com/reset.css',
121
+ {
122
+ url: 'https://cdn.example.com/theme.css',
123
+ integrity: 'sha384-...',
124
+ crossorigin: 'anonymous',
125
+ },
126
+ ],
127
+ script: [
128
+ 'https://cdn.example.com/polyfill.js',
129
+ {
130
+ url: 'https://cdn.example.com/vendor.js',
131
+ integrity: 'sha384-...',
132
+ crossorigin: 'anonymous',
133
+ },
134
+ ],
135
+ },
136
+ });
137
+ ```
78
138
 
79
139
  ### 2. Stripping markup
80
140
 
@@ -88,7 +148,7 @@ Content (e.g., development-only markup) within stripping markup (including the m
88
148
 
89
149
  The tag name is configurable via the `stripTag` option.
90
150
 
91
- ### 4. Minification
151
+ ### 3. Minification
92
152
 
93
153
  Enable minification to shrink the final HTML:
94
154
 
@@ -115,6 +175,40 @@ html({
115
175
 
116
176
  See [`html-minifier-terser` options](https://github.com/terser/html-minifier-terser#options-quick-reference) for the full list.
117
177
 
178
+ ### 4. Cache busting
179
+
180
+ >**NOTE:** External assets injected through the `external` option are not affected.
181
+
182
+ Enable cache busting to append a query string to the URLs of bundled assets. The content hash is generated automatically:
183
+
184
+ ```js
185
+ html({
186
+ template: 'src/index.html',
187
+ cacheBusting: true,
188
+ });
189
+ ```
190
+
191
+ This produces tags such as `<script src="bundle.js?v=1a2b3c4d"></script>`.
192
+
193
+ You can also provide the query string yourself. The value is appended without the leading `?`:
194
+
195
+ ```js
196
+ html({
197
+ template: 'src/index.html',
198
+ cacheBusting: 'v=1.2.3',
199
+ });
200
+ ```
201
+
202
+ For per-asset control, pass a function receiving the asset file name and its content. Return an empty string to skip that asset:
203
+
204
+ ```js
205
+ html({
206
+ template: 'src/index.html',
207
+ cacheBusting: (fileName, content) =>
208
+ fileName.endsWith('.js') ? `v=${content.length}` : 'v=1.2.3',
209
+ });
210
+ ```
211
+
118
212
  ## License
119
213
 
120
214
  Package `@auioc/rollup-plugin-html` is licensed under the **MIT License**.
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  /*!
2
2
  * Package bundle (CJS) of @auioc/rollup-plugin-html
3
3
  * https://github.com/auioc/rollup-plugins/tree/main/packages/html
4
- * Generated at 2026-10-03T16:27:04.048Z
5
- * Version: v1.0.0 - tag:html@v1.0.0@20c4ec2b
4
+ * Generated at 2026-11-01T16:54:06.132Z
5
+ * Version: v1.2.0 - tag:html@v1.2.0@20a23efd
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
@@ -12,12 +12,60 @@
12
12
  Object.defineProperty(exports, '__esModule', { value: true });
13
13
 
14
14
  var htmlMinifierTerser = require('html-minifier-terser');
15
+ var node_crypto = require('node:crypto');
15
16
  var fs = require('node:fs');
16
17
  var Path = require('node:path');
17
18
 
18
19
  const NAME = 'html';
20
+ const DEFAULT_TERSER_OPTIONS = {
21
+ collapseWhitespace: true,
22
+ removeComments: true,
23
+ };
24
+ function appendQuery(url, query) {
25
+ const hashIndex = url.indexOf('#');
26
+ const hash = hashIndex === -1 ? '' : url.slice(hashIndex);
27
+ const base = hashIndex === -1 ? url : url.slice(0, hashIndex);
28
+ const separator = base.includes('?') ? '&' : '?';
29
+ return `${base}${separator}${query}${hash}`;
30
+ }
31
+ function cacheBustingQuery(cacheBusting, fileName, content) {
32
+ if (typeof cacheBusting === 'string') {
33
+ return cacheBusting;
34
+ }
35
+ if (typeof cacheBusting === 'function') {
36
+ return cacheBusting(fileName, content) || '';
37
+ }
38
+ return `v=${node_crypto.createHash('sha256').update(content).digest('hex').slice(0, 8)}`;
39
+ }
40
+ function assetURL(fileName, content, cacheBusting) {
41
+ if (!cacheBusting) {
42
+ return fileName;
43
+ }
44
+ const query = cacheBustingQuery(cacheBusting, fileName, content);
45
+ return query ? appendQuery(fileName, query) : fileName;
46
+ }
47
+ function styleTag(asset) {
48
+ if (typeof asset === 'string') {
49
+ return `<link rel="stylesheet" href="${asset}">`;
50
+ }
51
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
52
+ const crossorigin = asset.crossorigin
53
+ ? ` crossorigin="${asset.crossorigin}"`
54
+ : '';
55
+ return `<link rel="stylesheet" href="${asset.url}"${integrity}${crossorigin}>`;
56
+ }
57
+ function scriptTag(asset, module) {
58
+ if (typeof asset === 'string') {
59
+ return `<script ${module ? 'type="module" ' : ''}src="${asset}"></script>`;
60
+ }
61
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
62
+ const crossorigin = asset.crossorigin
63
+ ? ` crossorigin="${asset.crossorigin}"`
64
+ : '';
65
+ return `<script ${module ? 'type="module" ' : ''}src="${asset.url}"${integrity}${crossorigin}></script>`;
66
+ }
19
67
  function createHTML(options) {
20
- const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify = false, } = options;
68
+ const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify = false, cacheBusting = false, } = options;
21
69
  let template = '';
22
70
  return {
23
71
  name: NAME,
@@ -42,46 +90,54 @@ function createHTML(options) {
42
90
  const cssFiles = [];
43
91
  for (const [fileName, chunk] of Object.entries(bundle)) {
44
92
  if (chunk.type === 'chunk' && fileName.endsWith('.js')) {
45
- if (chunk.isEntry || chunk.isDynamicEntry) {
46
- jsFiles.push(fileName);
93
+ if (chunk.isEntry) {
94
+ jsFiles.push(assetURL(fileName, chunk.code, cacheBusting));
47
95
  }
48
96
  }
49
97
  else if (chunk.type === 'asset') {
50
98
  if (fileName.endsWith('.css')) {
51
- cssFiles.push(fileName);
99
+ cssFiles.push(assetURL(fileName, chunk.source, cacheBusting));
52
100
  }
53
101
  }
54
102
  }
55
- if (injectStyle && cssFiles.length > 0) {
56
- const tags = cssFiles
57
- .map((file) => `<link rel="stylesheet" href="${file}">`)
58
- .join('\n');
59
- if (html.includes(styleTagPlaceholder)) {
60
- html = html.replace(styleTagPlaceholder, tags);
61
- }
62
- else if (html.includes('</head>')) {
63
- html = html.replace('</head>', ` ${tags}\n</head>`);
64
- }
65
- else {
66
- html = `${tags}\n${html}`;
103
+ const external = options.external ?? { style: [], script: [] };
104
+ if (injectStyle) {
105
+ const externalTags = (external.style ?? []).map(styleTag);
106
+ const bundledTags = cssFiles.map(styleTag);
107
+ const tags = [...externalTags, ...bundledTags].join('\n');
108
+ if (tags) {
109
+ if (html.includes(styleTagPlaceholder)) {
110
+ html = html.replace(styleTagPlaceholder, tags);
111
+ }
112
+ else if (html.includes('</head>')) {
113
+ html = html.replace('</head>', ` ${tags}\n</head>`);
114
+ }
115
+ else {
116
+ html = `${tags}\n${html}`;
117
+ }
67
118
  }
68
119
  }
69
- if (injectScript && jsFiles.length > 0) {
70
- const tags = jsFiles
71
- .map((file) => `<script ${injectScript === 'module' ? 'type="module" ' : ''}src="${file}"></script>`)
72
- .join('\n');
73
- if (html.includes(scriptTagPlaceholder)) {
74
- html = html.replace(scriptTagPlaceholder, tags);
75
- }
76
- else if (html.includes('</body>')) {
77
- html = html.replace('</body>', ` ${tags}\n</body>`);
78
- }
79
- else {
80
- html += `\n${tags}`;
120
+ if (injectScript) {
121
+ const _toScriptTag = (asset) => scriptTag(asset, injectScript === 'module');
122
+ const externalTags = (external.script ?? []).map(_toScriptTag);
123
+ const bundledScriptTags = jsFiles.map(_toScriptTag);
124
+ const tags = [...externalTags, ...bundledScriptTags].join('\n');
125
+ if (tags) {
126
+ if (html.includes(scriptTagPlaceholder)) {
127
+ html = html.replace(scriptTagPlaceholder, tags);
128
+ }
129
+ else if (html.includes('</body>')) {
130
+ html = html.replace('</body>', ` ${tags}\n</body>`);
131
+ }
132
+ else {
133
+ html += `\n${tags}`;
134
+ }
81
135
  }
82
136
  }
83
137
  if (minify) {
84
- const minifyOptions = typeof minify === 'object' ? minify : {};
138
+ const minifyOptions = typeof minify === 'object'
139
+ ? minify
140
+ : DEFAULT_TERSER_OPTIONS;
85
141
  html = await htmlMinifierTerser.minify(html, minifyOptions);
86
142
  }
87
143
  const asset = {
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /*!
2
2
  * Type definitions of @auioc/rollup-plugin-html
3
3
  * https://github.com/auioc/rollup-plugins/tree/main/packages/html
4
- * Generated at 2026-10-03T16:27:04.048Z
5
- * Version: v1.0.0 - tag:html@v1.0.0@20c4ec2b
4
+ * Generated at 2026-11-01T16:54:06.132Z
5
+ * Version: v1.2.0 - tag:html@v1.2.0@20a23efd
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
@@ -10,6 +10,12 @@
10
10
  import { Options as Options$1 } from 'html-minifier-terser';
11
11
  import { Plugin } from 'rollup';
12
12
 
13
+ type Asset = string | {
14
+ url: string;
15
+ integrity?: string;
16
+ crossorigin?: 'anonymous' | 'use-credentials';
17
+ };
18
+ type CacheBusting = boolean | string | ((fileName: string, content: string | Uint8Array) => string | undefined | false);
13
19
  interface Options {
14
20
  /**
15
21
  * Path of template `.html` file
@@ -31,6 +37,14 @@ interface Options {
31
37
  * @default true
32
38
  */
33
39
  injectScript?: boolean | 'module';
40
+ /**
41
+ * External assets to inject.
42
+ * @default {}
43
+ */
44
+ external?: {
45
+ style?: Asset[];
46
+ script?: Asset[];
47
+ };
34
48
  /**
35
49
  * Placeholder comment replaced by CSS tags.
36
50
  * @default '<!-- inject:style -->'
@@ -54,8 +68,15 @@ interface Options {
54
68
  * @default false
55
69
  */
56
70
  minify?: boolean | Options$1;
71
+ /**
72
+ * Append a query string to bundled asset URLs to bust caches.
73
+ *
74
+ * External assets are not affected.
75
+ * @default false
76
+ */
77
+ cacheBusting?: CacheBusting;
57
78
  }
58
79
  declare function createHTML(options: Options): Plugin;
59
80
 
60
81
  export { createHTML as default };
61
- export type { Options };
82
+ export type { Asset, CacheBusting, Options };
package/dist/index.mjs CHANGED
@@ -1,19 +1,67 @@
1
1
  /*!
2
2
  * Package bundle (ESM) of @auioc/rollup-plugin-html
3
3
  * https://github.com/auioc/rollup-plugins/tree/main/packages/html
4
- * Generated at 2026-10-03T16:27:04.048Z
5
- * Version: v1.0.0 - tag:html@v1.0.0@20c4ec2b
4
+ * Generated at 2026-11-01T16:54:06.132Z
5
+ * Version: v1.2.0 - tag:html@v1.2.0@20a23efd
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
9
9
  */
10
10
  import { minify } from 'html-minifier-terser';
11
+ import { createHash } from 'node:crypto';
11
12
  import fs from 'node:fs';
12
13
  import Path from 'node:path';
13
14
 
14
15
  const NAME = 'html';
16
+ const DEFAULT_TERSER_OPTIONS = {
17
+ collapseWhitespace: true,
18
+ removeComments: true,
19
+ };
20
+ function appendQuery(url, query) {
21
+ const hashIndex = url.indexOf('#');
22
+ const hash = hashIndex === -1 ? '' : url.slice(hashIndex);
23
+ const base = hashIndex === -1 ? url : url.slice(0, hashIndex);
24
+ const separator = base.includes('?') ? '&' : '?';
25
+ return `${base}${separator}${query}${hash}`;
26
+ }
27
+ function cacheBustingQuery(cacheBusting, fileName, content) {
28
+ if (typeof cacheBusting === 'string') {
29
+ return cacheBusting;
30
+ }
31
+ if (typeof cacheBusting === 'function') {
32
+ return cacheBusting(fileName, content) || '';
33
+ }
34
+ return `v=${createHash('sha256').update(content).digest('hex').slice(0, 8)}`;
35
+ }
36
+ function assetURL(fileName, content, cacheBusting) {
37
+ if (!cacheBusting) {
38
+ return fileName;
39
+ }
40
+ const query = cacheBustingQuery(cacheBusting, fileName, content);
41
+ return query ? appendQuery(fileName, query) : fileName;
42
+ }
43
+ function styleTag(asset) {
44
+ if (typeof asset === 'string') {
45
+ return `<link rel="stylesheet" href="${asset}">`;
46
+ }
47
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
48
+ const crossorigin = asset.crossorigin
49
+ ? ` crossorigin="${asset.crossorigin}"`
50
+ : '';
51
+ return `<link rel="stylesheet" href="${asset.url}"${integrity}${crossorigin}>`;
52
+ }
53
+ function scriptTag(asset, module) {
54
+ if (typeof asset === 'string') {
55
+ return `<script ${module ? 'type="module" ' : ''}src="${asset}"></script>`;
56
+ }
57
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
58
+ const crossorigin = asset.crossorigin
59
+ ? ` crossorigin="${asset.crossorigin}"`
60
+ : '';
61
+ return `<script ${module ? 'type="module" ' : ''}src="${asset.url}"${integrity}${crossorigin}></script>`;
62
+ }
15
63
  function createHTML(options) {
16
- const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify: minify$1 = false, } = options;
64
+ const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify: minify$1 = false, cacheBusting = false, } = options;
17
65
  let template = '';
18
66
  return {
19
67
  name: NAME,
@@ -38,46 +86,54 @@ function createHTML(options) {
38
86
  const cssFiles = [];
39
87
  for (const [fileName, chunk] of Object.entries(bundle)) {
40
88
  if (chunk.type === 'chunk' && fileName.endsWith('.js')) {
41
- if (chunk.isEntry || chunk.isDynamicEntry) {
42
- jsFiles.push(fileName);
89
+ if (chunk.isEntry) {
90
+ jsFiles.push(assetURL(fileName, chunk.code, cacheBusting));
43
91
  }
44
92
  }
45
93
  else if (chunk.type === 'asset') {
46
94
  if (fileName.endsWith('.css')) {
47
- cssFiles.push(fileName);
95
+ cssFiles.push(assetURL(fileName, chunk.source, cacheBusting));
48
96
  }
49
97
  }
50
98
  }
51
- if (injectStyle && cssFiles.length > 0) {
52
- const tags = cssFiles
53
- .map((file) => `<link rel="stylesheet" href="${file}">`)
54
- .join('\n');
55
- if (html.includes(styleTagPlaceholder)) {
56
- html = html.replace(styleTagPlaceholder, tags);
57
- }
58
- else if (html.includes('</head>')) {
59
- html = html.replace('</head>', ` ${tags}\n</head>`);
60
- }
61
- else {
62
- html = `${tags}\n${html}`;
99
+ const external = options.external ?? { style: [], script: [] };
100
+ if (injectStyle) {
101
+ const externalTags = (external.style ?? []).map(styleTag);
102
+ const bundledTags = cssFiles.map(styleTag);
103
+ const tags = [...externalTags, ...bundledTags].join('\n');
104
+ if (tags) {
105
+ if (html.includes(styleTagPlaceholder)) {
106
+ html = html.replace(styleTagPlaceholder, tags);
107
+ }
108
+ else if (html.includes('</head>')) {
109
+ html = html.replace('</head>', ` ${tags}\n</head>`);
110
+ }
111
+ else {
112
+ html = `${tags}\n${html}`;
113
+ }
63
114
  }
64
115
  }
65
- if (injectScript && jsFiles.length > 0) {
66
- const tags = jsFiles
67
- .map((file) => `<script ${injectScript === 'module' ? 'type="module" ' : ''}src="${file}"></script>`)
68
- .join('\n');
69
- if (html.includes(scriptTagPlaceholder)) {
70
- html = html.replace(scriptTagPlaceholder, tags);
71
- }
72
- else if (html.includes('</body>')) {
73
- html = html.replace('</body>', ` ${tags}\n</body>`);
74
- }
75
- else {
76
- html += `\n${tags}`;
116
+ if (injectScript) {
117
+ const _toScriptTag = (asset) => scriptTag(asset, injectScript === 'module');
118
+ const externalTags = (external.script ?? []).map(_toScriptTag);
119
+ const bundledScriptTags = jsFiles.map(_toScriptTag);
120
+ const tags = [...externalTags, ...bundledScriptTags].join('\n');
121
+ if (tags) {
122
+ if (html.includes(scriptTagPlaceholder)) {
123
+ html = html.replace(scriptTagPlaceholder, tags);
124
+ }
125
+ else if (html.includes('</body>')) {
126
+ html = html.replace('</body>', ` ${tags}\n</body>`);
127
+ }
128
+ else {
129
+ html += `\n${tags}`;
130
+ }
77
131
  }
78
132
  }
79
133
  if (minify$1) {
80
- const minifyOptions = typeof minify$1 === 'object' ? minify$1 : {};
134
+ const minifyOptions = typeof minify$1 === 'object'
135
+ ? minify$1
136
+ : DEFAULT_TERSER_OPTIONS;
81
137
  html = await minify(html, minifyOptions);
82
138
  }
83
139
  const asset = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auioc/rollup-plugin-html",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },