@auioc/rollup-plugin-html 1.0.0 → 1.1.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,96 @@ 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. |
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
+
47
+ - Asset
48
+
49
+ ```typescript
50
+ type Asset =
51
+ | string // treated as URL
52
+ | {
53
+ url: string;
54
+ integrity?: string;
55
+ crossorigin?: 'anonymous' | 'use-credentials';
56
+ };
57
+ ```
45
58
 
46
59
  ## How It Works
47
60
 
48
61
  ### 1. Injection
49
62
 
50
- When the bundle is generated, the plugin collects:
63
+ Assets are injected into the template in one of two ways:
51
64
 
52
- - **CSS assets** (any emitted asset ending in `.css`)
53
- - **JS chunks** that are entry points or dynamic entry points (files ending in `.js`)
65
+ - **Using placeholders** (Recommended)
54
66
 
55
- These are injected into the template in one of two ways:
67
+ ```html
68
+ <!DOCTYPE html>
69
+ <html>
70
+ <head>
71
+ <title>My App</title>
72
+ <!-- inject:style -->
73
+ </head>
74
+ <body>
75
+ <div id="app"></div>
76
+ <!-- inject:script -->
77
+ </body>
78
+ </html>
79
+ ```
56
80
 
57
- #### Using placeholders (Recommended)
81
+ The placeholders are configurable via the `styleTagPlaceholder`, `scriptTagPlaceholder` options.
58
82
 
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
- ```
83
+ - **Using fallbacks**
84
+
85
+ If placeholders are not present, tags are inserted before `</head>` (CSS) or `</body>` (JS) when those tags exist;
86
+
87
+ Otherwise they are prepended (CSS) or appended (JS) to the document.
88
+
89
+ #### Bundled Assets
90
+
91
+ When the bundle is generated, the plugin collects:
72
92
 
73
- The placeholders are configurable via the `styleTagPlaceholder`, `scriptTagPlaceholder` options.
93
+ - **CSS assets** (any emitted asset ending in `.css`)
94
+ - **JS chunks** that are entry points (files ending in `.js`)
95
+
96
+ #### External Assets
97
+
98
+ Use the `external` option to inject assets that are not produced by Rollup (e.g. CDN scripts, third-party stylesheets).
74
99
 
75
- #### Using fallbacks
100
+ External tags are always emitted **before** the bundled tags within the same injection slot.
76
101
 
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.
102
+ ```js
103
+ html({
104
+ template: 'src/index.html',
105
+ external: {
106
+ style: [
107
+ 'https://cdn.example.com/reset.css',
108
+ {
109
+ url: 'https://cdn.example.com/theme.css',
110
+ integrity: 'sha384-...',
111
+ crossorigin: 'anonymous',
112
+ },
113
+ ],
114
+ script: [
115
+ 'https://cdn.example.com/polyfill.js',
116
+ {
117
+ url: 'https://cdn.example.com/vendor.js',
118
+ integrity: 'sha384-...',
119
+ crossorigin: 'anonymous',
120
+ },
121
+ ],
122
+ },
123
+ });
124
+ ```
78
125
 
79
126
  ### 2. Stripping markup
80
127
 
@@ -88,7 +135,7 @@ Content (e.g., development-only markup) within stripping markup (including the m
88
135
 
89
136
  The tag name is configurable via the `stripTag` option.
90
137
 
91
- ### 4. Minification
138
+ ### 3. Minification
92
139
 
93
140
  Enable minification to shrink the final HTML:
94
141
 
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-10-24T11:55:55.128Z
5
+ * Version: v1.1.0 - tag:html@v1.1.0@7188de8e
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
@@ -16,6 +16,30 @@ var fs = require('node:fs');
16
16
  var Path = require('node:path');
17
17
 
18
18
  const NAME = 'html';
19
+ const DEFAULT_TERSER_OPTIONS = {
20
+ collapseWhitespace: true,
21
+ removeComments: true,
22
+ };
23
+ function styleTag(asset) {
24
+ if (typeof asset === 'string') {
25
+ return `<link rel="stylesheet" href="${asset}">`;
26
+ }
27
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
28
+ const crossorigin = asset.crossorigin
29
+ ? ` crossorigin="${asset.crossorigin}"`
30
+ : '';
31
+ return `<link rel="stylesheet" href="${asset.url}"${integrity}${crossorigin}>`;
32
+ }
33
+ function scriptTag(asset, module) {
34
+ if (typeof asset === 'string') {
35
+ return `<script ${module ? 'type="module" ' : ''}src="${asset}"></script>`;
36
+ }
37
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
38
+ const crossorigin = asset.crossorigin
39
+ ? ` crossorigin="${asset.crossorigin}"`
40
+ : '';
41
+ return `<script ${module ? 'type="module" ' : ''}src="${asset.url}"${integrity}${crossorigin}></script>`;
42
+ }
19
43
  function createHTML(options) {
20
44
  const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify = false, } = options;
21
45
  let template = '';
@@ -42,7 +66,7 @@ function createHTML(options) {
42
66
  const cssFiles = [];
43
67
  for (const [fileName, chunk] of Object.entries(bundle)) {
44
68
  if (chunk.type === 'chunk' && fileName.endsWith('.js')) {
45
- if (chunk.isEntry || chunk.isDynamicEntry) {
69
+ if (chunk.isEntry) {
46
70
  jsFiles.push(fileName);
47
71
  }
48
72
  }
@@ -52,36 +76,44 @@ function createHTML(options) {
52
76
  }
53
77
  }
54
78
  }
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}`;
79
+ const external = options.external ?? { style: [], script: [] };
80
+ if (injectStyle) {
81
+ const externalTags = (external.style ?? []).map(styleTag);
82
+ const bundledTags = cssFiles.map(styleTag);
83
+ const tags = [...externalTags, ...bundledTags].join('\n');
84
+ if (tags) {
85
+ if (html.includes(styleTagPlaceholder)) {
86
+ html = html.replace(styleTagPlaceholder, tags);
87
+ }
88
+ else if (html.includes('</head>')) {
89
+ html = html.replace('</head>', ` ${tags}\n</head>`);
90
+ }
91
+ else {
92
+ html = `${tags}\n${html}`;
93
+ }
67
94
  }
68
95
  }
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}`;
96
+ if (injectScript) {
97
+ const _toScriptTag = (asset) => scriptTag(asset, injectScript === 'module');
98
+ const externalTags = (external.script ?? []).map(_toScriptTag);
99
+ const bundledScriptTags = jsFiles.map(_toScriptTag);
100
+ const tags = [...externalTags, ...bundledScriptTags].join('\n');
101
+ if (tags) {
102
+ if (html.includes(scriptTagPlaceholder)) {
103
+ html = html.replace(scriptTagPlaceholder, tags);
104
+ }
105
+ else if (html.includes('</body>')) {
106
+ html = html.replace('</body>', ` ${tags}\n</body>`);
107
+ }
108
+ else {
109
+ html += `\n${tags}`;
110
+ }
81
111
  }
82
112
  }
83
113
  if (minify) {
84
- const minifyOptions = typeof minify === 'object' ? minify : {};
114
+ const minifyOptions = typeof minify === 'object'
115
+ ? minify
116
+ : DEFAULT_TERSER_OPTIONS;
85
117
  html = await htmlMinifierTerser.minify(html, minifyOptions);
86
118
  }
87
119
  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-10-24T11:55:55.128Z
5
+ * Version: v1.1.0 - tag:html@v1.1.0@7188de8e
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
@@ -10,6 +10,11 @@
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
+ };
13
18
  interface Options {
14
19
  /**
15
20
  * Path of template `.html` file
@@ -31,6 +36,14 @@ interface Options {
31
36
  * @default true
32
37
  */
33
38
  injectScript?: boolean | 'module';
39
+ /**
40
+ * External assets to inject.
41
+ * @default {}
42
+ */
43
+ external?: {
44
+ style?: Asset[];
45
+ script?: Asset[];
46
+ };
34
47
  /**
35
48
  * Placeholder comment replaced by CSS tags.
36
49
  * @default '<!-- inject:style -->'
@@ -58,4 +71,4 @@ interface Options {
58
71
  declare function createHTML(options: Options): Plugin;
59
72
 
60
73
  export { createHTML as default };
61
- export type { Options };
74
+ export type { Asset, Options };
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
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-10-24T11:55:55.128Z
5
+ * Version: v1.1.0 - tag:html@v1.1.0@7188de8e
6
6
  * Copyright (C) 2026 AUIOC.ORG
7
7
  * Copyright (C) 2022-2026 PCC-Studio
8
8
  * Licensed under MIT
@@ -12,6 +12,30 @@ import fs from 'node:fs';
12
12
  import Path from 'node:path';
13
13
 
14
14
  const NAME = 'html';
15
+ const DEFAULT_TERSER_OPTIONS = {
16
+ collapseWhitespace: true,
17
+ removeComments: true,
18
+ };
19
+ function styleTag(asset) {
20
+ if (typeof asset === 'string') {
21
+ return `<link rel="stylesheet" href="${asset}">`;
22
+ }
23
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
24
+ const crossorigin = asset.crossorigin
25
+ ? ` crossorigin="${asset.crossorigin}"`
26
+ : '';
27
+ return `<link rel="stylesheet" href="${asset.url}"${integrity}${crossorigin}>`;
28
+ }
29
+ function scriptTag(asset, module) {
30
+ if (typeof asset === 'string') {
31
+ return `<script ${module ? 'type="module" ' : ''}src="${asset}"></script>`;
32
+ }
33
+ const integrity = asset.integrity ? ` integrity="${asset.integrity}"` : '';
34
+ const crossorigin = asset.crossorigin
35
+ ? ` crossorigin="${asset.crossorigin}"`
36
+ : '';
37
+ return `<script ${module ? 'type="module" ' : ''}src="${asset.url}"${integrity}${crossorigin}></script>`;
38
+ }
15
39
  function createHTML(options) {
16
40
  const { template: templateFile, output = 'index.html', injectStyle = true, injectScript = true, styleTagPlaceholder = '<!-- inject:style -->', scriptTagPlaceholder = '<!-- inject:script -->', stripTag = 'strip', minify: minify$1 = false, } = options;
17
41
  let template = '';
@@ -38,7 +62,7 @@ function createHTML(options) {
38
62
  const cssFiles = [];
39
63
  for (const [fileName, chunk] of Object.entries(bundle)) {
40
64
  if (chunk.type === 'chunk' && fileName.endsWith('.js')) {
41
- if (chunk.isEntry || chunk.isDynamicEntry) {
65
+ if (chunk.isEntry) {
42
66
  jsFiles.push(fileName);
43
67
  }
44
68
  }
@@ -48,36 +72,44 @@ function createHTML(options) {
48
72
  }
49
73
  }
50
74
  }
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}`;
75
+ const external = options.external ?? { style: [], script: [] };
76
+ if (injectStyle) {
77
+ const externalTags = (external.style ?? []).map(styleTag);
78
+ const bundledTags = cssFiles.map(styleTag);
79
+ const tags = [...externalTags, ...bundledTags].join('\n');
80
+ if (tags) {
81
+ if (html.includes(styleTagPlaceholder)) {
82
+ html = html.replace(styleTagPlaceholder, tags);
83
+ }
84
+ else if (html.includes('</head>')) {
85
+ html = html.replace('</head>', ` ${tags}\n</head>`);
86
+ }
87
+ else {
88
+ html = `${tags}\n${html}`;
89
+ }
63
90
  }
64
91
  }
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}`;
92
+ if (injectScript) {
93
+ const _toScriptTag = (asset) => scriptTag(asset, injectScript === 'module');
94
+ const externalTags = (external.script ?? []).map(_toScriptTag);
95
+ const bundledScriptTags = jsFiles.map(_toScriptTag);
96
+ const tags = [...externalTags, ...bundledScriptTags].join('\n');
97
+ if (tags) {
98
+ if (html.includes(scriptTagPlaceholder)) {
99
+ html = html.replace(scriptTagPlaceholder, tags);
100
+ }
101
+ else if (html.includes('</body>')) {
102
+ html = html.replace('</body>', ` ${tags}\n</body>`);
103
+ }
104
+ else {
105
+ html += `\n${tags}`;
106
+ }
77
107
  }
78
108
  }
79
109
  if (minify$1) {
80
- const minifyOptions = typeof minify$1 === 'object' ? minify$1 : {};
110
+ const minifyOptions = typeof minify$1 === 'object'
111
+ ? minify$1
112
+ : DEFAULT_TERSER_OPTIONS;
81
113
  html = await minify(html, minifyOptions);
82
114
  }
83
115
  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.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },