@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 +128 -34
- package/dist/index.cjs +87 -31
- package/dist/index.d.ts +24 -3
- package/dist/index.mjs +87 -31
- package/package.json +1 -1
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: {
|
|
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
|
|
36
|
-
| ---------------------- |
|
|
37
|
-
| `template` | `string`
|
|
38
|
-
| `output` | `string`
|
|
39
|
-
| `injectStyle` | `boolean`
|
|
40
|
-
| `injectScript` | `boolean` \| `'module'`
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
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
|
-
|
|
76
|
+
Assets are injected into the template in one of two ways:
|
|
51
77
|
|
|
52
|
-
- **
|
|
53
|
-
- **JS chunks** that are entry points or dynamic entry points (files ending in `.js`)
|
|
78
|
+
- **Using placeholders** (Recommended)
|
|
54
79
|
|
|
55
|
-
|
|
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
|
-
|
|
94
|
+
The placeholders are configurable via the `styleTagPlaceholder`, `scriptTagPlaceholder` options.
|
|
58
95
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
109
|
+
#### External Assets
|
|
74
110
|
|
|
75
|
-
|
|
111
|
+
Use the `external` option to inject assets that are not produced by Rollup (e.g. CDN scripts, third-party stylesheets).
|
|
76
112
|
|
|
77
|
-
|
|
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
|
-
###
|
|
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-
|
|
5
|
-
* Version: v1.
|
|
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
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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'
|
|
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-
|
|
5
|
-
* Version: v1.
|
|
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-
|
|
5
|
-
* Version: v1.
|
|
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
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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'
|
|
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 = {
|