diff --git a/.changeset/empty-carrots-sneeze.md b/.changeset/empty-carrots-sneeze.md
new file mode 100644
index 000000000..bf77febf6
--- /dev/null
+++ b/.changeset/empty-carrots-sneeze.md
@@ -0,0 +1,11 @@
+---
+'@web/rollup-plugin-html': major
+---
+
+1. Enabled CSS assets extraction by default (as a result, removed configuration option bundleAssetsFromCss).
+2. Made extraction of assets from all link rel types
+3. Fixed "assetFileNames" behavior
+4. Refactored all tests, added tests for more corner cases
+5. Added legacy modes for old 2.x.x behavior.
+
+See MIGRATION.md for migration notes.
diff --git a/.gitignore b/.gitignore
index 1d8925996..03a8d4933 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,6 @@ local.log
docs/_merged_data/
docs/_merged_assets/
docs/_merged_includes/
+
+## temp
+.tmp
\ No newline at end of file
diff --git a/docs/docs/building/rollup-plugin-html.md b/docs/docs/building/rollup-plugin-html.md
index f3b805245..e202486c0 100644
--- a/docs/docs/building/rollup-plugin-html.md
+++ b/docs/docs/building/rollup-plugin-html.md
@@ -105,65 +105,98 @@ export default {
### Bundling assets
-The HTML plugin will bundle assets referenced from `img` and `link` and social media tag elements in your HTML. The assets are emitted as rollup assets, and the paths are updated to the rollup output paths.
+The HTML plugin will bundle assets referenced in `img` and `link` and social media tag elements in your HTML:
-By default rollup will hash the asset filenames, enabling long term caching. You can customize the filename pattern using the [assetFileNames option](https://rollupjs.org/guide/en/#outputassetfilenames) in your rollup config.
-
-To turn off bundling assets completely, set the `extractAssets` option to false:
-
-```js
-import { rollupPluginHTML as html } from '@web/rollup-plugin-html';
-
-export default {
- input: 'index.html',
- output: { dir: 'dist' },
- plugins: [
- html({
- extractAssets: false,
- }),
- ],
-};
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
```
-#### Including assets referenced from css
-
-If your css files reference other assets via `url`, like for example:
+And the assets referenced in CSS via `url`:
```css
body {
- background-image: url('images/star.gif');
+ background-image: url('images/image.png');
}
-/* or */
@font-face {
- src: url('fonts/font-bold.woff2') format('woff2');
- /* ...etc */
+ src: url('fonts/font.woff2') format('woff2');
}
```
-You can enable the `bundleAssetsFromCss` option:
+The assets are emitted as rollup assets, and the paths are updated to the rollup output paths:
-```js
-rollupPluginHTML({
- bundleAssetsFromCss: true,
- // ...etc
-});
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
```
-And those assets will get output to the `assets/` dir, and the source css file will get updated with the output locations of those assets, e.g.:
-
```css
body {
- background-image: url('assets/star-P4TYRBwL.gif');
+ background-image: url('assets/image-C4yLPiIL.png');
}
-/* or */
@font-face {
- src: url('assets/font-bold-f0mNRiTD.woff2') format('woff2');
- /* ...etc */
+ src: url('assets/font-f0mNRiTD.woff2') format('woff2');
}
```
+The images are deduped when same ones are referenced in different tags and files.
+
+You can configure the output paths via [assetFileNames option](https://rollupjs.org/guide/en/#outputassetfilenames) (by default `assets/[name]-[hash][extname]` at the time of writing).
+The hash in the asset filenames enables long term caching.
+
+#### Disable assets bundling
+
+To turn off bundling assets completely, set the `extractAssets` option to false:
+
+```js
+import { rollupPluginHTML as html } from '@web/rollup-plugin-html';
+
+export default {
+ input: 'index.html',
+ output: { dir: 'dist' },
+ plugins: [
+ html({
+ extractAssets: false,
+ }),
+ ],
+};
+```
+
+#### Enable legacy behavior
+
+For smooth migration we added legacy modes:
+
+- `extractAssets: 'legacy-html'` is the same as 2.x.x behavior when `bundleAssetsFromCss: false`
+- `extractAssets: 'legacy-html-and-css'` is the same as 2.x.x behavior when `bundleAssetsFromCss: true`
+
+The 2.x.x behavior was limited to ` ` only and the assets referenced in the CSS files were hardcoded to be put into the nested `assets/` dir.
+
+We recommend to use legacy modes only during the migration of large multi-project codebases to 3.x.x in order to temporarily keep the old behavior until all projects can reliably use the new behavior, while at the same time upgrading tools centrally to the new version of `@web/rollup-plugin-html`.
+
### Handling absolute paths
If your HTML file contains any absolute paths they will be resolved against the current working directory. You can set a different root directory in the config. Input paths will be resolved relative to this root directory as well.
@@ -361,7 +394,7 @@ export interface RollupPluginHTMLOptions {
/** Transform HTML file before output. */
transformHtml?: TransformHtmlFunction | TransformHtmlFunction[];
/** Whether to extract and bundle assets referenced in HTML. Defaults to true. */
- extractAssets?: boolean;
+ extractAssets?: boolean | 'legacy-html' | 'legacy-html-and-css';
/** Whether to ignore assets referenced in HTML and CSS with glob patterns. */
externalAssets?: string | string[];
/** Define a full absolute url to your site (e.g. https://domain.com) */
diff --git a/package-lock.json b/package-lock.json
index 27e8208a1..d25393b8d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4146,6 +4146,22 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@prettier/sync": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.6.1.tgz",
+ "integrity": "sha512-yF9G8vK/LYUTF3Cijd7VC9La3b20F20/J/fgoR4H0B8JGOWnZVZX6+I6+vODPosjmMcpdlUV+gUqJQZp3kLOcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "make-synchronized": "^0.8.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier-synchronized?sponsor=1"
+ },
+ "peerDependencies": {
+ "prettier": "*"
+ }
+ },
"node_modules/@promptbook/utils": {
"version": "0.69.5",
"resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.69.5.tgz",
@@ -7145,6 +7161,17 @@
"@types/node": "*"
}
},
+ "node_modules/@types/prettier": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-3.0.0.tgz",
+ "integrity": "sha512-mFMBfMOz8QxhYVbuINtswBp9VL2b4Y0QqYHwqLz3YbgtfAcat2Dl6Y1o4e22S/OVE6Ebl9m7wWiMT2lSbAs1wA==",
+ "deprecated": "This is a stub types definition. prettier provides its own type definitions, so you do not need this installed.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prettier": "*"
+ }
+ },
"node_modules/@types/prismjs": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz",
@@ -21143,6 +21170,16 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/make-synchronized": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.8.0.tgz",
+ "integrity": "sha512-DZu4lwc0ffoFz581BSQa/BJl+1ZqIkoRQ+VejMlH0VrP4E86StAODnZujZ4sepumQj8rcP7wUnUBGM8Gu+zKUA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/fisker/make-synchronized?sponsor=1"
+ }
+ },
"node_modules/map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -36454,8 +36491,11 @@
"picomatch": "^2.2.2"
},
"devDependencies": {
+ "@prettier/sync": "^0.6.1",
"@types/html-minifier-terser": "^7.0.0",
"@types/picomatch": "^2.2.1",
+ "@types/prettier": "^3.0.0",
+ "prettier": "^3.6.2",
"rollup": "^4.4.0"
},
"engines": {
@@ -36505,6 +36545,22 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "packages/rollup-plugin-html/node_modules/prettier": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
+ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"packages/rollup-plugin-import-meta-assets": {
"name": "@web/rollup-plugin-import-meta-assets",
"version": "2.3.0",
diff --git a/packages/rollup-plugin-html/MIGRATION.md b/packages/rollup-plugin-html/MIGRATION.md
new file mode 100644
index 000000000..099125caa
--- /dev/null
+++ b/packages/rollup-plugin-html/MIGRATION.md
@@ -0,0 +1,20 @@
+# Migration
+
+## From version 2.x.x to 3.x.x
+
+Remove `bundleAssetsFromCss` configuration option, now we bundle assets referenced in CSS by default.
+
+Check all output assets since now we handle all link `rel` types, specifically:
+
+- icon
+- apple-touch-icon
+- mask-icon
+- stylesheet
+- manifest
+- preload
+- prefetch
+- modulepreload
+
+If any of them reference external assets or assets that don't need to be bundled, you can exclude such assets using the `externalAssets` configuration option.
+
+For old behavior which is only recommeneded during the migration you can check legacy modes `extractAssets: 'legacy-html'` and `extractAssets: 'legacy-html-and-css'` in the documentation.
diff --git a/packages/rollup-plugin-html/package.json b/packages/rollup-plugin-html/package.json
index 0c5c80172..15da1f9b6 100644
--- a/packages/rollup-plugin-html/package.json
+++ b/packages/rollup-plugin-html/package.json
@@ -52,8 +52,11 @@
"picomatch": "^2.2.2"
},
"devDependencies": {
+ "@prettier/sync": "^0.6.1",
"@types/html-minifier-terser": "^7.0.0",
"@types/picomatch": "^2.2.1",
+ "@types/prettier": "^3.0.0",
+ "prettier": "^3.6.2",
"rollup": "^4.4.0"
}
}
diff --git a/packages/rollup-plugin-html/src/RollupPluginHTMLOptions.ts b/packages/rollup-plugin-html/src/RollupPluginHTMLOptions.ts
index c65198af3..26a34fb6a 100644
--- a/packages/rollup-plugin-html/src/RollupPluginHTMLOptions.ts
+++ b/packages/rollup-plugin-html/src/RollupPluginHTMLOptions.ts
@@ -27,8 +27,8 @@ export interface RollupPluginHTMLOptions {
transformAsset?: TransformAssetFunction | TransformAssetFunction[];
/** Transform HTML file before output. */
transformHtml?: TransformHtmlFunction | TransformHtmlFunction[];
- /** Whether to extract and bundle assets referenced in HTML. Defaults to true. */
- extractAssets?: boolean;
+ /** Whether to extract and bundle assets referenced in HTML and CSS. Defaults to true. */
+ extractAssets?: boolean | 'legacy-html' | 'legacy-html-and-css';
/** Whether to ignore assets referenced in HTML and CSS with glob patterns. */
externalAssets?: string | string[];
/** Define a full absolute url to your site (e.g. https://domain.com) */
@@ -43,8 +43,6 @@ export interface RollupPluginHTMLOptions {
absolutePathPrefix?: string;
/** When set to true, will insert meta tags for CSP and add script-src values for inline scripts by sha256-hashing the contents */
strictCSPInlineScripts?: boolean;
- /** Bundle assets reference from CSS via `url` */
- bundleAssetsFromCss?: boolean;
}
export interface GeneratedBundle {
diff --git a/packages/rollup-plugin-html/src/assets/utils.ts b/packages/rollup-plugin-html/src/assets/utils.ts
index 5af29a52f..eb0591e8b 100644
--- a/packages/rollup-plugin-html/src/assets/utils.ts
+++ b/packages/rollup-plugin-html/src/assets/utils.ts
@@ -5,8 +5,18 @@ import { findElements, getTagName, getAttribute } from '@web/parse5-utils';
import { createError } from '../utils.js';
import { serialize } from 'v8';
-const hashedLinkRels = ['stylesheet'];
-const linkRels = [...hashedLinkRels, 'icon', 'manifest', 'apple-touch-icon', 'mask-icon'];
+const assetLinkRels = [
+ 'icon',
+ 'apple-touch-icon',
+ 'mask-icon',
+ 'stylesheet',
+ 'manifest',
+ 'preload',
+ 'prefetch',
+ 'modulepreload',
+];
+const legacyHashedLinkRels = ['stylesheet'];
+const assetMetaProperties = ['og:image'];
function getSrcSetUrls(srcset: string) {
if (!srcset) {
@@ -41,13 +51,14 @@ function isAsset(node: Element) {
path = extractFirstUrlOfSrcSet(node) ?? '';
}
break;
- case 'link':
- if (linkRels.includes(getAttribute(node, 'rel') ?? '')) {
+ case 'link': {
+ if (assetLinkRels.includes(getAttribute(node, 'rel') ?? '')) {
path = getAttribute(node, 'href') ?? '';
}
break;
+ }
case 'meta':
- if (getAttribute(node, 'property') === 'og:image' && getAttribute(node, 'content')) {
+ if (assetMetaProperties.includes(getAttribute(node, 'property') ?? '')) {
path = getAttribute(node, 'content') ?? '';
}
break;
@@ -70,7 +81,10 @@ function isAsset(node: Element) {
}
}
-export function isHashedAsset(node: Element) {
+export function isHashedAsset(
+ node: Element,
+ extractAssets: boolean | 'legacy-html' | 'legacy-html-and-css',
+) {
switch (getTagName(node)) {
case 'img':
return true;
@@ -78,8 +92,13 @@ export function isHashedAsset(node: Element) {
return true;
case 'script':
return true;
- case 'link':
- return hashedLinkRels.includes(getAttribute(node, 'rel')!);
+ case 'link': {
+ if (extractAssets === 'legacy-html' || extractAssets === 'legacy-html-and-css') {
+ return legacyHashedLinkRels.includes(getAttribute(node, 'rel') ?? '');
+ } else {
+ return true;
+ }
+ }
case 'meta':
return true;
default:
diff --git a/packages/rollup-plugin-html/src/input/extract/extractAssets.ts b/packages/rollup-plugin-html/src/input/extract/extractAssets.ts
index b2ae8b8fc..4a71ae84c 100644
--- a/packages/rollup-plugin-html/src/input/extract/extractAssets.ts
+++ b/packages/rollup-plugin-html/src/input/extract/extractAssets.ts
@@ -15,6 +15,7 @@ export interface ExtractAssetsParams {
htmlFilePath: string;
htmlDir: string;
rootDir: string;
+ extractAssets: boolean | 'legacy-html' | 'legacy-html-and-css';
externalAssets?: string | string[];
absolutePathPrefix?: string;
}
@@ -35,7 +36,7 @@ export function extractAssets(params: ExtractAssetsParams): InputAsset[] {
params.rootDir,
params.absolutePathPrefix,
);
- const hashed = isHashedAsset(node);
+ const hashed = isHashedAsset(node, params.extractAssets);
const alreadyHandled = allAssets.find(a => a.filePath === filePath && a.hashed === hashed);
if (!alreadyHandled) {
try {
@@ -49,7 +50,7 @@ export function extractAssets(params: ExtractAssetsParams): InputAsset[] {
}
const content = fs.readFileSync(filePath);
- allAssets.push({ filePath, hashed, content });
+ allAssets.push({ filePath, hashed: hashed, content });
}
}
}
diff --git a/packages/rollup-plugin-html/src/input/extract/extractModulesAndAssets.ts b/packages/rollup-plugin-html/src/input/extract/extractModulesAndAssets.ts
index b06d59ded..0deea609f 100644
--- a/packages/rollup-plugin-html/src/input/extract/extractModulesAndAssets.ts
+++ b/packages/rollup-plugin-html/src/input/extract/extractModulesAndAssets.ts
@@ -7,7 +7,7 @@ export interface ExtractParams {
html: string;
htmlFilePath: string;
rootDir: string;
- extractAssets: boolean;
+ extractAssets: boolean | 'legacy-html' | 'legacy-html-and-css';
externalAssets?: string | string[];
absolutePathPrefix?: string;
}
@@ -30,6 +30,7 @@ export function extractModulesAndAssets(params: ExtractParams) {
htmlDir,
htmlFilePath,
rootDir,
+ extractAssets: params.extractAssets,
externalAssets,
absolutePathPrefix,
})
diff --git a/packages/rollup-plugin-html/src/input/getInputData.ts b/packages/rollup-plugin-html/src/input/getInputData.ts
index 102cb062e..9d217c5f5 100644
--- a/packages/rollup-plugin-html/src/input/getInputData.ts
+++ b/packages/rollup-plugin-html/src/input/getInputData.ts
@@ -30,14 +30,21 @@ export interface CreateInputDataParams {
html: string;
rootDir: string;
filePath?: string;
- extractAssets: boolean;
+ extractAssets: boolean | 'legacy-html' | 'legacy-html-and-css';
externalAssets?: string | string[];
absolutePathPrefix?: string;
}
function createInputData(params: CreateInputDataParams): InputData {
- const { name, html, rootDir, filePath, extractAssets, externalAssets, absolutePathPrefix } =
- params;
+ const {
+ name,
+ html,
+ rootDir,
+ filePath,
+ extractAssets = true,
+ externalAssets,
+ absolutePathPrefix,
+ } = params;
const htmlFilePath = filePath ? filePath : path.resolve(rootDir, name);
const result = extractModulesAndAssets({
html,
diff --git a/packages/rollup-plugin-html/src/output/createHTMLOutput.ts b/packages/rollup-plugin-html/src/output/createHTMLOutput.ts
index cb2224267..aa68f4da6 100644
--- a/packages/rollup-plugin-html/src/output/createHTMLOutput.ts
+++ b/packages/rollup-plugin-html/src/output/createHTMLOutput.ts
@@ -1,3 +1,4 @@
+import * as path from 'path';
import { getEntrypointBundles } from './getEntrypointBundles.js';
import { getOutputHTML } from './getOutputHTML.js';
import { createError } from '../utils.js';
@@ -65,7 +66,14 @@ export async function createHTMLAsset(params: CreateHTMLAssetParams): Promise();
const emittedHashedAssets = new Map();
const emittedStaticAssetNames = new Set();
@@ -85,7 +88,7 @@ export async function emitAssets(
const isExternal = createAssetPicomatchMatcher(options.externalAssets);
const emittedExternalAssets = new Map();
if (asset.hashed) {
- if (basename.endsWith('.css') && options.bundleAssetsFromCss) {
+ if (basename.endsWith('.css') && extractAssets) {
let updatedCssSource = false;
const { code } = await transform({
filename: basename,
@@ -104,22 +107,47 @@ export async function emitAssets(
// Avoid duplicates
if (!emittedExternalAssets.has(assetLocation)) {
- const fontFileRef = this.emitFile({
+ const basename = path.basename(filePath);
+ const fileRef = this.emitFile({
type: 'asset',
- name: path.join('assets', path.basename(filePath)),
+ name: extractAssetsLegacyCss ? `assets/${basename}` : basename,
source: assetContent,
});
- const emittedAssetFilePath = path.basename(this.getFileName(fontFileRef));
- emittedExternalAssets.set(assetLocation, emittedAssetFilePath);
+ const emittedAssetFilepath = this.getFileName(fileRef);
+ const emittedAssetBasename = path.basename(emittedAssetFilepath);
+ emittedExternalAssets.set(assetLocation, emittedAssetFilepath);
// Update the URL in the original CSS file to point to the emitted asset file
- url.url = `assets/${
- idRef ? `${emittedAssetFilePath}#${idRef}` : emittedAssetFilePath
- }`;
+ if (extractAssetsLegacyCss) {
+ url.url = `assets/${emittedAssetBasename}`;
+ } else {
+ if (options.publicPath) {
+ url.url = toBrowserPath(
+ path.join(options.publicPath, emittedAssetFilepath),
+ );
+ } else {
+ url.url = emittedAssetBasename;
+ }
+ }
+ if (idRef) {
+ url.url = `${url.url}#${idRef}`;
+ }
} else {
- const emittedAssetFilePath = emittedExternalAssets.get(assetLocation);
- url.url = `assets/${
- idRef ? `${emittedAssetFilePath}#${idRef}` : emittedAssetFilePath
- }`;
+ const emittedAssetFilepath = emittedExternalAssets.get(assetLocation);
+ const emittedAssetBasename = path.basename(emittedAssetFilepath);
+ if (extractAssetsLegacyCss) {
+ url.url = `assets/${emittedAssetBasename}`;
+ } else {
+ if (options.publicPath) {
+ url.url = toBrowserPath(
+ path.join(options.publicPath, emittedAssetFilepath),
+ );
+ } else {
+ url.url = emittedAssetBasename;
+ }
+ }
+ if (idRef) {
+ url.url = `${url.url}#${idRef}`;
+ }
}
}
updatedCssSource = true;
diff --git a/packages/rollup-plugin-html/src/output/getOutputHTML.ts b/packages/rollup-plugin-html/src/output/getOutputHTML.ts
index 7f2725ae6..9b39ea7c4 100644
--- a/packages/rollup-plugin-html/src/output/getOutputHTML.ts
+++ b/packages/rollup-plugin-html/src/output/getOutputHTML.ts
@@ -53,6 +53,7 @@ export async function getOutputHTML(params: GetOutputHTMLParams) {
outputDir,
rootDir,
emittedAssets,
+ extractAssets: pluginOptions.extractAssets,
externalAssets: pluginOptions.externalAssets,
absolutePathPrefix,
publicPath: pluginOptions.publicPath,
diff --git a/packages/rollup-plugin-html/src/output/injectedUpdatedAssetPaths.ts b/packages/rollup-plugin-html/src/output/injectedUpdatedAssetPaths.ts
index e5ba484ae..a7cdedc9a 100644
--- a/packages/rollup-plugin-html/src/output/injectedUpdatedAssetPaths.ts
+++ b/packages/rollup-plugin-html/src/output/injectedUpdatedAssetPaths.ts
@@ -21,6 +21,7 @@ export interface InjectUpdatedAssetPathsArgs {
outputDir: string;
rootDir: string;
emittedAssets: EmittedAssets;
+ extractAssets?: boolean | 'legacy-html' | 'legacy-html-and-css';
externalAssets?: string | string[];
publicPath?: string;
absolutePathPrefix?: string;
@@ -44,6 +45,7 @@ export function injectedUpdatedAssetPaths(args: InjectUpdatedAssetPathsArgs) {
outputDir,
rootDir,
emittedAssets,
+ extractAssets = true,
externalAssets,
publicPath = './',
absolutePathPrefix,
@@ -59,7 +61,9 @@ export function injectedUpdatedAssetPaths(args: InjectUpdatedAssetPathsArgs) {
const htmlFilePath = input.filePath ? input.filePath : path.join(rootDir, input.name);
const htmlDir = path.dirname(htmlFilePath);
const filePath = resolveAssetFilePath(sourcePath, htmlDir, rootDir, absolutePathPrefix);
- const assetPaths = isHashedAsset(node) ? emittedAssets.hashed : emittedAssets.static;
+ const assetPaths = isHashedAsset(node, extractAssets)
+ ? emittedAssets.hashed
+ : emittedAssets.static;
const relativeOutputPath = assetPaths.get(filePath);
if (!relativeOutputPath) {
diff --git a/packages/rollup-plugin-html/src/rollupPluginHTML.ts b/packages/rollup-plugin-html/src/rollupPluginHTML.ts
index ffe1a0880..388c32967 100644
--- a/packages/rollup-plugin-html/src/rollupPluginHTML.ts
+++ b/packages/rollup-plugin-html/src/rollupPluginHTML.ts
@@ -72,7 +72,6 @@ export function rollupPluginHTML(pluginOptions: RollupPluginHTMLOptions = {}): R
if (pluginOptions.strictCSPInlineScripts) {
strictCSPInlineScripts = pluginOptions.strictCSPInlineScripts;
}
- pluginOptions.bundleAssetsFromCss = !!pluginOptions.bundleAssetsFromCss;
if (pluginOptions.input == null) {
// we are reading rollup input, so replace whatever was there
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/favicon.ico b/packages/rollup-plugin-html/test/fixtures/assets/favicon.ico
deleted file mode 100644
index e7b0a98b6..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/favicon.ico and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/foo.svg b/packages/rollup-plugin-html/test/fixtures/assets/foo.svg
deleted file mode 100644
index 8603a411c..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/foo.svg
+++ /dev/null
@@ -1 +0,0 @@
-x
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/foo/bar/y.css b/packages/rollup-plugin-html/test/fixtures/assets/foo/bar/y.css
deleted file mode 100644
index 85419bc9e..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/foo/bar/y.css
+++ /dev/null
@@ -1,3 +0,0 @@
-:root {
- color: y;
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/foo/x.css b/packages/rollup-plugin-html/test/fixtures/assets/foo/x.css
deleted file mode 100644
index feb977525..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/foo/x.css
+++ /dev/null
@@ -1,3 +0,0 @@
-:root {
- color: x;
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-a.png b/packages/rollup-plugin-html/test/fixtures/assets/image-a.png
deleted file mode 100644
index 088d83d6d..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/image-a.png and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-a.svg b/packages/rollup-plugin-html/test/fixtures/assets/image-a.svg
deleted file mode 100644
index 26766e2ac..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/image-a.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-b.png b/packages/rollup-plugin-html/test/fixtures/assets/image-b.png
deleted file mode 100644
index 088d83d6d..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/image-b.png and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-b.svg b/packages/rollup-plugin-html/test/fixtures/assets/image-b.svg
deleted file mode 100644
index a0d6b69d5..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/image-b.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-c.png b/packages/rollup-plugin-html/test/fixtures/assets/image-c.png
deleted file mode 100644
index 088d83d6d..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/image-c.png and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-d.png b/packages/rollup-plugin-html/test/fixtures/assets/image-d.png
deleted file mode 100644
index 731a4fb7b..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/image-d.png
+++ /dev/null
@@ -1 +0,0 @@
-image-d.png
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-d.svg b/packages/rollup-plugin-html/test/fixtures/assets/image-d.svg
deleted file mode 100644
index 82fe9253a..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/image-d.svg
+++ /dev/null
@@ -1 +0,0 @@
-image-d.svg
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/image-social.png b/packages/rollup-plugin-html/test/fixtures/assets/image-social.png
deleted file mode 100644
index 088d83d6d..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/image-social.png and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.avif b/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.avif
deleted file mode 100644
index 8e699d8a7..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.avif and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.jpeg b/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.jpeg
deleted file mode 100644
index af4d5d9af..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-30.jpeg and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.avif b/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.avif
deleted file mode 100644
index 8de0a6ff7..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.avif and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.jpeg b/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.jpeg
deleted file mode 100644
index 09c18b0f9..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/images/eb26e6ca-60.jpeg and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/index.html b/packages/rollup-plugin-html/test/fixtures/assets/index.html
deleted file mode 100644
index 1ac43699e..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/index.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/no-module.js b/packages/rollup-plugin-html/test/fixtures/assets/no-module.js
deleted file mode 100644
index b089a583f..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/no-module.js
+++ /dev/null
@@ -1 +0,0 @@
-/* no module script file */
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/styles-with-referenced-assets.css b/packages/rollup-plugin-html/test/fixtures/assets/styles-with-referenced-assets.css
deleted file mode 100644
index acb8baa56..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/styles-with-referenced-assets.css
+++ /dev/null
@@ -1,15 +0,0 @@
-#a1 {
- background-image: url('image-a.png');
-}
-
-#a2 {
- background-image: url('image-a.svg');
-}
-
-#d1 {
- background-image: url('./image-d.png');
-}
-
-#d2 {
- background-image: url('./image-d.svg');
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/styles.css b/packages/rollup-plugin-html/test/fixtures/assets/styles.css
deleted file mode 100644
index c11eb03fe..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/styles.css
+++ /dev/null
@@ -1,3 +0,0 @@
-:root {
- color: blue;
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/videos/typer-hydration.mp4 b/packages/rollup-plugin-html/test/fixtures/assets/videos/typer-hydration.mp4
deleted file mode 100644
index 53176ab71..000000000
Binary files a/packages/rollup-plugin-html/test/fixtures/assets/videos/typer-hydration.mp4 and /dev/null differ
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/webmanifest.json b/packages/rollup-plugin-html/test/fixtures/assets/webmanifest.json
deleted file mode 100644
index 3c935e111..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/webmanifest.json
+++ /dev/null
@@ -1 +0,0 @@
-{ "message": "hello world" }
diff --git a/packages/rollup-plugin-html/test/fixtures/assets/x/foo.svg b/packages/rollup-plugin-html/test/fixtures/assets/x/foo.svg
deleted file mode 100644
index ae50e4b7a..000000000
--- a/packages/rollup-plugin-html/test/fixtures/assets/x/foo.svg
+++ /dev/null
@@ -1 +0,0 @@
-y
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/app.js b/packages/rollup-plugin-html/test/fixtures/basic/app.js
deleted file mode 100644
index 6be02374d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/app.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('hello world');
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/index.html b/packages/rollup-plugin-html/test/fixtures/basic/index.html
deleted file mode 100644
index e3b2a7bfb..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/index.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- Hello world
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/not-index.html b/packages/rollup-plugin-html/test/fixtures/basic/not-index.html
deleted file mode 100644
index 0d1ef727f..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/not-index.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- not-index.html
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-a.html b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-a.html
deleted file mode 100644
index b73a61323..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-a.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-a.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-a.js b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-a.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-b.html b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-b.html
deleted file mode 100644
index c61c79147..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-b.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-b.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-b.js b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-b.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-c.html b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-c.html
deleted file mode 100644
index 05e306ede..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-c.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-c.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/page-c.js b/packages/rollup-plugin-html/test/fixtures/basic/pages/page-c.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/pages/shared.js b/packages/rollup-plugin-html/test/fixtures/basic/pages/shared.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/src/foo.js b/packages/rollup-plugin-html/test/fixtures/basic/src/foo.js
deleted file mode 100644
index 6be02374d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/src/foo.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('hello world');
diff --git a/packages/rollup-plugin-html/test/fixtures/basic/src/index.html b/packages/rollup-plugin-html/test/fixtures/basic/src/index.html
deleted file mode 100644
index 02ab03884..000000000
--- a/packages/rollup-plugin-html/test/fixtures/basic/src/index.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- Foo
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/index.html b/packages/rollup-plugin-html/test/fixtures/inject-service-worker/index.html
deleted file mode 100644
index cc61d8f8f..000000000
--- a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/index.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- inject a service worker into /index.html
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-pure-html/index.html b/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-pure-html/index.html
deleted file mode 100644
index 2719f7b18..000000000
--- a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-pure-html/index.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- inject a service worker into /sub-page/index.html
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/index.html b/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/index.html
deleted file mode 100644
index ea1b64867..000000000
--- a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/index.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- inject a service worker into /sub-page/index.html
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/sub-js.js b/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/sub-js.js
deleted file mode 100644
index 50e2d5d4b..000000000
--- a/packages/rollup-plugin-html/test/fixtures/inject-service-worker/sub-with-js/sub-js.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('sub-with-js');
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/fonts/font-normal.woff2 b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/fonts/font-normal.woff2
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-a.css b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-a.css
deleted file mode 100644
index 391732403..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-a.css
+++ /dev/null
@@ -1,7 +0,0 @@
-@font-face {
- font-family: 'Font';
- src: url('fonts/font-normal.woff2') format('woff2');
- font-weight: normal;
- font-style: normal;
- font-display: swap;
-}
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-b.css b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-b.css
deleted file mode 100644
index 2c13aec86..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/styles-b.css
+++ /dev/null
@@ -1,7 +0,0 @@
-@font-face {
- font-family: 'Font2';
- src: url('fonts/font-normal.woff2') format('woff2');
- font-weight: normal;
- font-style: normal;
- font-display: swap;
-}
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.avif b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.avif
deleted file mode 100644
index 2e65efe2a..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.avif
+++ /dev/null
@@ -1 +0,0 @@
-a
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.gif b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.gif
deleted file mode 100644
index 63d8dbd40..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.gif
+++ /dev/null
@@ -1 +0,0 @@
-b
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpeg b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpeg
deleted file mode 100644
index 3410062ba..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpeg
+++ /dev/null
@@ -1 +0,0 @@
-c
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpg b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpg
deleted file mode 100644
index c59d9b634..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.jpg
+++ /dev/null
@@ -1 +0,0 @@
-d
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.png b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.png
deleted file mode 100644
index 9cbe6ea56..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.png
+++ /dev/null
@@ -1 +0,0 @@
-e
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.svg b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.svg
deleted file mode 100644
index 4d1ae35ba..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.svg
+++ /dev/null
@@ -1 +0,0 @@
-f
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.webp b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.webp
deleted file mode 100644
index 7937c68fb..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/images/star.webp
+++ /dev/null
@@ -1 +0,0 @@
-g
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/styles.css b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/styles.css
deleted file mode 100644
index bb0fa19d5..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-images/styles.css
+++ /dev/null
@@ -1,24 +0,0 @@
-#a {
- background-image: url("images/star.svg");
-}
-#b {
- background-image: url("images/star.svg#foo");
-}
-#c {
- background-image: url("images/star.png");
-}
-#d {
- background-image: url("images/star.jpg");
-}
-#e {
- background-image: url("images/star.jpeg");
-}
-#f {
- background-image: url("images/star.webp");
-}
-#g {
- background-image: url("images/star.gif");
-}
-#h {
- background-image: url("images/star.avif");
-}
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/fonts/font-bold.woff2 b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/fonts/font-bold.woff2
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/fonts/font-normal.woff2 b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/fonts/font-normal.woff2
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/node_modules-styles-with-fonts.css b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/node_modules-styles-with-fonts.css
deleted file mode 100644
index a12383545..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-node-modules/node_modules/foo/node_modules-styles-with-fonts.css
+++ /dev/null
@@ -1,15 +0,0 @@
-@font-face {
- font-family: 'Font';
- src: url('fonts/font-normal.woff2') format('woff2');
- font-weight: normal;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: 'Font';
- src: url('fonts/font-bold.woff2') format('woff2');
- font-weight: bold;
- font-style: normal;
- font-display: swap;
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/fonts/font-bold.woff2 b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/fonts/font-bold.woff2
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/fonts/font-normal.woff2 b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/fonts/font-normal.woff2
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/styles-with-fonts.css b/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/styles-with-fonts.css
deleted file mode 100644
index a12383545..000000000
--- a/packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles/styles-with-fonts.css
+++ /dev/null
@@ -1,15 +0,0 @@
-@font-face {
- font-family: 'Font';
- src: url('fonts/font-normal.woff2') format('woff2');
- font-weight: normal;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: 'Font';
- src: url('fonts/font-bold.woff2') format('woff2');
- font-weight: bold;
- font-style: normal;
- font-display: swap;
-}
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-a.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-a.html
deleted file mode 100644
index cb228937b..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-a.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-hello world
-
-
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-b.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-b.html
deleted file mode 100644
index 16aa25114..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-b.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-hello world
-
-
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-c.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-c.html
deleted file mode 100644
index 59ae9f80d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/csp-page-c.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-hello world
-
-
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-a.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-a.js
deleted file mode 100644
index 1e396263d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-a.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './modules/module-a.js';
-
-console.log('entrypoint-a.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-b.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-b.js
deleted file mode 100644
index 43071b698..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-b.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './modules/module-b.js';
-
-console.log('entrypoint-b.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-c.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-c.js
deleted file mode 100644
index bfca03130..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/entrypoint-c.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './modules/module-c.js';
-
-console.log('entrypoint-c.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/assets/partial.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/assets/partial.html
deleted file mode 100644
index ab7da9e61..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/assets/partial.html
+++ /dev/null
@@ -1 +0,0 @@
-I'm a partial!
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/index.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/index.html
deleted file mode 100644
index 97ed84e72..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/exclude/index.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.html
deleted file mode 100644
index 5f2b937fa..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.js
deleted file mode 100644
index 81afa3157..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/foo/foo.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('foo');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/index.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/index.html
deleted file mode 100644
index 2dffb27c2..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/index.html
+++ /dev/null
@@ -1,3 +0,0 @@
-hello world
-
-
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/module.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/module.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-a.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-a.js
deleted file mode 100644
index 5c2200d03..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-a.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './shared-module.js';
-
-console.log('module-a.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-b.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-b.js
deleted file mode 100644
index 48ebae220..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-b.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './shared-module.js';
-
-console.log('module-b.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-c.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-c.js
deleted file mode 100644
index 48ebae220..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/module-c.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './shared-module.js';
-
-console.log('module-b.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/shared-module.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/shared-module.js
deleted file mode 100644
index 0842867ca..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/modules/shared-module.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('shared-module.js');
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/my-page.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/my-page.html
deleted file mode 100644
index bbbc2338d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/my-page.html
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.html
deleted file mode 100644
index b73a61323..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-a.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.js
deleted file mode 100644
index e1fa0e0ce..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-a.js
+++ /dev/null
@@ -1 +0,0 @@
-export default 'page a';
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.html
deleted file mode 100644
index c61c79147..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-b.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.js
deleted file mode 100644
index c469b20a3..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-b.js
+++ /dev/null
@@ -1 +0,0 @@
-export default 'page b';
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.html
deleted file mode 100644
index 05e306ede..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- page-c.html
-
-
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.js
deleted file mode 100644
index a236bb8bd..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/page-c.js
+++ /dev/null
@@ -1 +0,0 @@
-export default 'page c';
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/shared.js b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/shared.js
deleted file mode 100644
index 7c18e65fc..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pages/shared.js
+++ /dev/null
@@ -1 +0,0 @@
-export default 'shared';
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index.html
deleted file mode 100644
index b44880118..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index.html
+++ /dev/null
@@ -1 +0,0 @@
-hello world
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index2.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index2.html
deleted file mode 100644
index 45b615663..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/pure-index2.html
+++ /dev/null
@@ -1 +0,0 @@
-hey there
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/retain-attributes.html b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/retain-attributes.html
deleted file mode 100644
index 7d4b2712d..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/retain-attributes.html
+++ /dev/null
@@ -1,3 +0,0 @@
-hello world
-
-
diff --git a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/styles.css b/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/styles.css
deleted file mode 100644
index c11eb03fe..000000000
--- a/packages/rollup-plugin-html/test/fixtures/rollup-plugin-html/styles.css
+++ /dev/null
@@ -1,3 +0,0 @@
-:root {
- color: blue;
-}
diff --git a/packages/rollup-plugin-html/test/rollup-plugin-html.test.ts b/packages/rollup-plugin-html/test/rollup-plugin-html.test.ts
index 7ccd949b0..799e39099 100644
--- a/packages/rollup-plugin-html/test/rollup-plugin-html.test.ts
+++ b/packages/rollup-plugin-html/test/rollup-plugin-html.test.ts
@@ -1,224 +1,439 @@
-import { rollup, OutputChunk, OutputAsset, OutputOptions, Plugin } from 'rollup';
+import { rollup, OutputChunk, OutputOptions, Plugin } from 'rollup';
import { expect } from 'chai';
import path from 'path';
import { rollupPluginHTML } from '../src/index.js';
-
-type Output = (OutputChunk | OutputAsset)[];
-
-function getChunk(output: Output, name: string) {
- return output.find(o => o.fileName === name && o.type === 'chunk') as OutputChunk;
-}
-
-function getAsset(output: Output, name: string) {
- return output.find(o => o.name === name && o.type === 'asset') as OutputAsset & {
- source: string;
- };
-}
+import { html, css, js, svg, generateTestBundle, createApp, cleanApp } from './utils.js';
const outputConfig: OutputOptions = {
format: 'es',
dir: 'dist',
};
-function stripNewlines(str: string) {
- return str.replace(/(\r\n|\n|\r)/gm, '');
-}
-
-const rootDir = path.join(__dirname, 'fixtures', 'rollup-plugin-html');
-
describe('rollup-plugin-html', () => {
+ afterEach(() => {
+ cleanApp();
+ });
+
it('can build with an input path as input', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ import './modules/module-a.js';
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ import './modules/module-b.js';
+ console.log('entrypoint-b.js');
+ `,
+ 'modules/module-a.js': js`
+ import './shared-module.js';
+ console.log('module-a.js');
+ `,
+ 'modules/module-b.js': js`
+ import './shared-module.js';
+ console.log('module-b.js');
+ `,
+ 'modules/shared-module.js': js`
+ console.log('shared-module.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/index.html'),
rootDir,
+ input: './index.html',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- 'hello world ' +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(3);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
it('can build with html file as rollup input', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ import './modules/module-a.js';
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ import './modules/module-b.js';
+ console.log('entrypoint-b.js');
+ `,
+ 'modules/module-a.js': js`
+ import './shared-module.js';
+ console.log('module-a.js');
+ `,
+ 'modules/module-b.js': js`
+ import './shared-module.js';
+ console.log('module-b.js');
+ `,
+ 'modules/shared-module.js': js`
+ console.log('shared-module.js');
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/index.html'),
+ input: './index.html',
plugins: [rollupPluginHTML({ rootDir })],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- 'hello world ' +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(3);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
it('will retain attributes on script tags', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ import './modules/module-a.js';
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ import './modules/module-b.js';
+ console.log('entrypoint-b.js');
+ `,
+ 'modules/module-a.js': js`
+ import './shared-module.js';
+ console.log('module-a.js');
+ `,
+ 'modules/module-b.js': js`
+ import './shared-module.js';
+ console.log('module-b.js');
+ `,
+ 'modules/shared-module.js': js`
+ console.log('shared-module.js');
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/retain-attributes.html'),
+ input: './index.html',
plugins: [rollupPluginHTML({ rootDir })],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'retain-attributes.html').source)).to.equal(
- 'hello world ' +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(3);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
it('can build with pure html file as rollup input', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+ hello world
+
+
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/pure-index.html'),
+ input: './index.html',
plugins: [rollupPluginHTML({ rootDir })],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(stripNewlines(getAsset(output, 'pure-index.html').source)).to.equal(
- 'hello world ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+ hello world
+
+
+ `);
});
it('can build with multiple pure html inputs', async () => {
+ const rootDir = createApp({
+ 'index1.html': html`
+
+
+
+ hello world
+
+
+ `,
+ 'index2.html': html`
+
+
+
+ hey there
+
+
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: [
- require.resolve('./fixtures/rollup-plugin-html/pure-index.html'),
- require.resolve('./fixtures/rollup-plugin-html/pure-index2.html'),
- ],
rootDir,
+ input: ['./index1.html', './index2.html'],
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(stripNewlines(getAsset(output, 'pure-index.html').source)).to.equal(
- 'hello world ',
- );
- expect(stripNewlines(getAsset(output, 'pure-index2.html').source)).to.equal(
- 'hey there ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(2);
+
+ expect(assets['index1.html']).to.equal(html`
+
+
+
+ hello world
+
+
+ `);
+
+ expect(assets['index2.html']).to.equal(html`
+
+
+
+ hey there
+
+
+ `);
});
it('can build with html string as input', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: {
name: 'index.html',
- html: 'Hello world ',
+ html: ``,
},
- rootDir,
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- 'Hello world ' +
- '',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('resolves paths relative to virtual html filename', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: {
- name: 'pages/index.html',
- html: 'Hello world ',
+ name: 'nested/index.html',
+ html: ``,
},
- rootDir,
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(stripNewlines(getAsset(output, 'pages/index.html').source)).to.equal(
- 'Hello world ' +
- '',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['nested/index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('can build with inline modules', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
input: {
name: 'index.html',
- html: 'Hello world ',
+ html: ``,
},
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- const hash = '5ec680a4efbb48ae254268ab1defe610';
- const { code: appCode } = getChunk(output, `inline-module-${hash}.js`);
- expect(appCode).to.include("console.log('entrypoint-a.js');");
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- 'Hello world ' +
- `` +
- '',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ const hash = '16165cb387fc14ed1fe1749d05f19f7b';
+
+ expect(chunks[`inline-module-${hash}.js`]).to.include(js`console.log('app.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('resolves inline module imports relative to the HTML file', async () => {
+ const rootDir = createApp({
+ 'nested/index.html': html`
+
+
+
+
+
+
+ `,
+ 'nested/app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/foo/foo.html'),
rootDir,
+ input: './nested/index.html',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- const { code: appCode } = getChunk(output, 'inline-module-1b13383486c70d87f4e2585ff87b147c.js');
- expect(appCode).to.include("console.log('foo');");
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ const hash = 'b774aefb8bf002b291fd54d27694a34d';
+ expect(chunks[`inline-module-${hash}.js`]).to.include(js`console.log('app.js');`);
});
it('can build transforming final output', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/entrypoint-a.js'),
plugins: [
rollupPluginHTML({
rootDir,
input: {
- html: 'Hello world ',
+ html: `Hello world `,
},
transformHtml(html) {
return html.replace('Hello world', 'Goodbye world');
@@ -226,133 +441,243 @@ describe('rollup-plugin-html', () => {
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(getAsset(output, 'index.html').source).to.equal(
- 'Goodbye world ' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+ Goodbye world
+
+
+
+ `);
});
it('can build with a public path', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/entrypoint-a.js'),
plugins: [
rollupPluginHTML({
rootDir,
+ publicPath: '/static/',
input: {
- html: 'Hello world ',
+ html: ``,
},
- publicPath: '/static/',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(getAsset(output, 'index.html').source).to.equal(
- 'Hello world ' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('can build with a public path with a file in a directory', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/entrypoint-a.js'),
plugins: [
rollupPluginHTML({
rootDir,
+ publicPath: '/static/',
input: {
- name: 'pages/index.html',
- html: 'Hello world ',
+ name: 'nested/index.html',
+ html: ``,
},
- publicPath: '/static/',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(getAsset(output, 'pages/index.html').source).to.equal(
- 'Hello world ' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['nested/index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('can build with multiple build outputs', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ import './modules/module.js';
+ console.log('app.js');
+ `,
+ 'modules/module.js': js`
+ console.log('module.js');
+ `,
+ });
+
const plugin = rollupPluginHTML({
rootDir,
+ publicPath: '/static/',
input: {
- html: 'Hello world ',
+ html: ``,
},
- publicPath: '/static/',
});
+
const config = {
- input: require.resolve('./fixtures/rollup-plugin-html/entrypoint-a.js'),
+ input: path.join(rootDir, 'app.js'),
plugins: [plugin],
};
+
const build = await rollup(config);
- const bundleA = build.generate({
+
+ const bundleA = generateTestBundle(build, {
format: 'system',
dir: 'dist',
plugins: [plugin.api.addOutput('legacy')],
});
- const bundleB = build.generate({
+
+ const bundleB = generateTestBundle(build, {
format: 'es',
dir: 'dist',
plugins: [plugin.api.addOutput('modern')],
});
- const { output: outputA } = await bundleA;
- const { output: outputB } = await bundleB;
- expect(outputA.length).to.equal(1);
- expect(outputB.length).to.equal(2);
- const { code: entrypointA1 } = getChunk(outputA, 'entrypoint-a.js');
- const { code: entrypointA2 } = getChunk(outputB, 'entrypoint-a.js');
- expect(entrypointA1).to.include("console.log('entrypoint-a.js');");
- expect(entrypointA1).to.include("console.log('module-a.js');");
- expect(entrypointA2).to.include("console.log('entrypoint-a.js');");
- expect(entrypointA2).to.include("console.log('module-a.js');");
- expect(getAsset(outputA, 'index.html')).to.not.exist;
- expect(getAsset(outputB, 'index.html').source).to.equal(
- 'Hello world ' +
- '' +
- '',
- );
+
+ const { chunks: chunksA, assets: assetsA } = await bundleA;
+ const { chunks: chunksB, assets: assetsB } = await bundleB;
+
+ expect(Object.keys(chunksA)).to.have.lengthOf(1);
+ expect(Object.keys(assetsA)).to.have.lengthOf(0);
+ expect(Object.keys(chunksB)).to.have.lengthOf(1);
+ expect(Object.keys(assetsB)).to.have.lengthOf(1);
+
+ expect(chunksA['app.js']).to.include(js`console.log('app.js');`);
+ expect(chunksA['app.js']).to.include(js`console.log('module.js');`);
+ expect(chunksB['app.js']).to.include(js`console.log('app.js');`);
+ expect(chunksB['app.js']).to.include(js`console.log('module.js');`);
+
+ expect(assetsA['index.html']).to.not.exist;
+ expect(assetsB['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
it('can build with index.html as input and an extra html file as output', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
input: {
- html: 'Hello world ',
+ html: ``,
},
}),
rollupPluginHTML({
rootDir,
input: {
name: 'foo.html',
- html: 'foo.html ',
+ html: `foo.html `,
},
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- expect(getChunk(output, 'entrypoint-a.js')).to.exist;
- expect(getAsset(output, 'index.html').source).to.equal(
- 'Hello world ' +
- '',
- );
- expect(getAsset(output, 'foo.html').source).to.equal(
- 'foo.html ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(2);
+ expect(Object.keys(assets)).to.have.lengthOf(2);
+
+ expect(chunks['app.js']).to.exist;
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['foo.html']).to.equal(html`
+
+
+
+ foo.html
+
+
+ `);
});
it('can build with multiple html inputs', async () => {
+ const rootDir = createApp({
+ 'entrypoint-a.js': js`
+ import './modules/module-a.js';
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ import './modules/module-b.js';
+ console.log('entrypoint-b.js');
+ `,
+ 'entrypoint-c.js': js`
+ import './modules/module-c.js';
+ console.log('entrypoint-c.js');
+ `,
+ 'modules/module-a.js': js`
+ import './shared-module.js';
+ console.log('module-a.js');
+ `,
+ 'modules/module-b.js': js`
+ import './shared-module.js';
+ console.log('module-b.js');
+ `,
+ 'modules/module-c.js': js`
+ import './shared-module.js';
+ console.log('module-c.js');
+ `,
+ 'modules/shared-module.js': js`
+ console.log('shared-module.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
@@ -374,24 +699,91 @@ describe('rollup-plugin-html', () => {
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(7);
- expect(getChunk(output, 'entrypoint-a.js')).to.exist;
- expect(getChunk(output, 'entrypoint-b.js')).to.exist;
- expect(getChunk(output, 'entrypoint-c.js')).to.exist;
- expect(getAsset(output, 'page-a.html').source).to.equal(
- 'Page A ',
- );
- expect(getAsset(output, 'page-b.html').source).to.equal(
- 'Page B ',
- );
- expect(getAsset(output, 'page-c.html').source).to.equal(
- 'Page C ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(4);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(chunks['entrypoint-a.js']).to.exist;
+ expect(chunks['entrypoint-b.js']).to.exist;
+ expect(chunks['entrypoint-c.js']).to.exist;
+
+ expect(assets['page-a.html']).to.equal(html`
+
+
+
+ Page A
+
+
+
+ `);
+
+ expect(assets['page-b.html']).to.equal(html`
+
+
+
+ Page B
+
+
+
+ `);
+
+ expect(assets['page-c.html']).to.equal(html`
+
+
+
+ Page C
+
+
+
+ `);
});
it('can use a glob to build multiple pages', async () => {
+ const rootDir = createApp({
+ 'pages/page-a.html': html`
+
+
+ page-a.html
+
+
+
+
+ `,
+ 'pages/page-b.html': html`
+
+
+ page-b.html
+
+
+
+
+ `,
+ 'pages/page-c.html': html`
+
+
+ page-c.html
+
+
+
+
+ `,
+ 'pages/page-a.js': js`
+ export default 'page a';
+ `,
+ 'pages/page-b.js': js`
+ export default 'page b';
+ `,
+ 'pages/page-c.js': js`
+ export default 'page c';
+ `,
+ 'pages/shared.js': js`
+ export default 'shared';
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
@@ -401,82 +793,144 @@ describe('rollup-plugin-html', () => {
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- const pageA = getAsset(output, 'page-a.html').source;
- const pageB = getAsset(output, 'page-b.html').source;
- const pageC = getAsset(output, 'page-c.html').source;
- expect(output.length).to.equal(7);
- expect(getChunk(output, 'page-a.js')).to.exist;
- expect(getChunk(output, 'page-b.js')).to.exist;
- expect(getChunk(output, 'page-c.js')).to.exist;
- expect(pageA).to.include('page-a.html
');
- expect(pageA).to.include('');
- expect(pageA).to.include('');
- expect(pageB).to.include('page-b.html
');
- expect(pageB).to.include('');
- expect(pageB).to.include('');
- expect(pageC).to.include('page-c.html
');
- expect(pageC).to.include('');
- expect(pageC).to.include('');
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(4);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(chunks['page-a.js']).to.exist;
+ expect(chunks['page-b.js']).to.exist;
+ expect(chunks['page-c.js']).to.exist;
+
+ expect(assets['page-a.html']).to.equal(html`
+
+
+
+ page-a.html
+
+
+
+
+ `);
+
+ expect(assets['page-b.html']).to.equal(html`
+
+
+
+ page-b.html
+
+
+
+
+ `);
+
+ // TODO: investigate why shared.js is after page-c.js here but before in the others
+ expect(assets['page-c.html']).to.equal(html`
+
+
+
+ page-c.html
+
+
+
+
+ `);
});
it('can exclude globs', async () => {
+ const rootDir = createApp({
+ 'exclude/index.html': html` `,
+ 'exclude/assets/partial.html': html`I'm a partial! `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: 'exclude/**/*.html',
exclude: '**/partial.html',
- rootDir,
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets).to.have.keys(['index.html']);
});
it('creates unique inline script names', async () => {
+ const rootDir = createApp({});
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
input: [
{
- name: 'foo/index.html',
- html: 'Page A ',
+ name: 'nestedA/indexA.html',
+ html: `Page A `,
},
{
- name: 'bar/index.html',
- html: 'Page B ',
+ name: 'nestedB/indexB.html',
+ html: `Page B `,
},
{
- name: 'x.html',
- html: 'Page C ',
+ name: 'indexC.html',
+ html: `Page C `,
},
],
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(6);
- expect(getChunk(output, 'inline-module-b8667c926d8a16ee8b4499492c1726ed.js')).to.exist;
- expect(getChunk(output, 'inline-module-c91911481b66e7483731d4de5df616a6.js')).to.exist;
- expect(getChunk(output, 'inline-module-fbf0242ebea027b7392472c19328791d.js')).to.exist;
- expect(getAsset(output, 'foo/index.html').source).to.equal(
- 'Page A ',
- );
- expect(getAsset(output, 'bar/index.html').source).to.equal(
- 'Page B ',
- );
- expect(getAsset(output, 'x.html').source).to.equal(
- 'Page C ',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(3);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(chunks['inline-module-d463148d1d5869e52917a3b270db9e72.js']).to.exist;
+ expect(chunks['inline-module-b81da853430abdf130bcc7c4d0ade6d9.js']).to.exist;
+ expect(chunks['inline-module-170bb2146da66c440259138c7e0fea7e.js']).to.exist;
+
+ expect(assets['nestedA/indexA.html']).to.equal(html`
+
+
+
+ Page A
+
+
+
+ `);
+
+ expect(assets['nestedB/indexB.html']).to.equal(html`
+
+
+
+ Page B
+
+
+
+ `);
+
+ expect(assets['indexC.html']).to.equal(html`
+
+
+
+ Page C
+
+
+
+ `);
});
it('deduplicates common modules', async () => {
+ const rootDir = createApp({});
+
const config = {
plugins: [
rollupPluginHTML({
@@ -484,136 +938,247 @@ describe('rollup-plugin-html', () => {
input: [
{
name: 'a.html',
- html: 'Page A ',
+ html: `Page A `,
},
{
name: 'b.html',
- html: 'Page B ',
+ html: `Page B `,
},
{
name: 'c.html',
- html: 'Page C ',
+ html: `Page C `,
},
],
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- expect(getChunk(output, 'inline-module-b8667c926d8a16ee8b4499492c1726ed.js')).to.exist;
- expect(getAsset(output, 'a.html').source).to.equal(
- 'Page A ',
- );
- expect(getAsset(output, 'b.html').source).to.equal(
- 'Page B ',
- );
- expect(getAsset(output, 'c.html').source).to.equal(
- 'Page C ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(chunks['inline-module-44281cf3dede62434e0dd368df08902f.js']).to.exist;
+
+ expect(assets['a.html']).to.equal(html`
+
+
+
+ Page A
+
+
+
+ `);
+
+ expect(assets['b.html']).to.equal(html`
+
+
+
+ Page B
+
+
+
+ `);
+
+ expect(assets['c.html']).to.equal(html`
+
+
+
+ Page C
+
+
+
+ `);
});
it('outputs the hashed entrypoint name', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
input: {
- html:
- 'Hello world ' + ``,
+ html: ``,
},
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate({
+
+ const build = await rollup(config);
+ const { output, chunks, assets } = await generateTestBundle(build, {
...outputConfig,
entryFileNames: '[name]-[hash].js',
});
- expect(output.length).to.equal(2);
- const entrypoint = output.find(f =>
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ const appChunk = output.find(f =>
// @ts-ignore
- f.facadeModuleId.endsWith('entrypoint-a.js'),
+ f.facadeModuleId.endsWith('app.js'),
) as OutputChunk;
+
// ensure it's actually hashed
- expect(entrypoint.fileName).to.not.equal('entrypoint-a.js');
+ expect(appChunk.fileName).to.not.equal('app.js');
+
// get hashed name dynamically
- expect(getAsset(output, 'index.html').source).to.equal(
- `Hello world `,
- );
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('outputs import path relative to the final output html', async () => {
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
input: {
- name: 'pages/index.html',
- html: 'Hello world ',
+ name: 'nested/index.html',
+ html: '',
},
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(getAsset(output, 'pages/index.html').source).to.equal(
- 'Hello world ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['nested/index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('can change HTML root directory', async () => {
+ const rootDir = createApp({
+ 'different-root/src/app.js': js`
+ console.log('app.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- rootDir: path.join(__dirname, 'fixtures'),
+ rootDir: path.join(rootDir, 'different-root'),
input: {
- name: 'rollup-plugin-html/pages/index.html',
- html: 'Hello world ',
+ name: 'src/nested/index.html',
+ html: '',
},
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(2);
- expect(getAsset(output, 'rollup-plugin-html/pages/index.html').source).to.equal(
- 'Hello world ',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['src/nested/index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
});
it('can get the input with getInputs()', async () => {
// default filename
const pluginA = rollupPluginHTML({ input: { html: 'Hello world' } });
+
// filename inferred from input filename
+ const rootDirB = createApp({
+ 'my-page.html': html``,
+ 'app.js': js`console.log('app.js');`,
+ });
const pluginB = rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/my-page.html'),
+ input: path.join(rootDirB, 'my-page.html'),
});
+
// filename explicitly set
+ const rootDirC = createApp({
+ 'index.html': html``,
+ 'app.js': js`console.log('app.js');`,
+ });
const pluginC = rollupPluginHTML({
input: {
- name: 'pages/my-other-page.html',
- path: require.resolve('./fixtures/rollup-plugin-html/index.html'),
+ name: 'nested/my-other-page.html',
+ path: path.join(rootDirC, 'index.html'),
},
});
- await rollup({
- input: require.resolve('./fixtures/rollup-plugin-html/entrypoint-a.js'),
- plugins: [pluginA],
- });
+
+ await rollup({ plugins: [pluginA] });
await rollup({ plugins: [pluginB] });
await rollup({ plugins: [pluginC] });
+
expect(pluginA.api.getInputs()[0].name).to.equal('index.html');
expect(pluginB.api.getInputs()[0].name).to.equal('my-page.html');
- expect(pluginC.api.getInputs()[0].name).to.equal('pages/my-other-page.html');
+ expect(pluginC.api.getInputs()[0].name).to.equal('nested/my-other-page.html');
});
it('supports other plugins injecting a transform function', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ import './modules/module-a.js';
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ import './modules/module-b.js';
+ console.log('entrypoint-b.js');
+ `,
+ 'modules/module-a.js': js`
+ import './shared-module.js';
+ console.log('module-a.js');
+ `,
+ 'modules/module-b.js': js`
+ import './shared-module.js';
+ console.log('module-b.js');
+ `,
+ 'modules/shared-module.js': js`
+ console.log('shared-module.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
rootDir,
- input: require.resolve('./fixtures/rollup-plugin-html/index.html'),
+ input: './index.html',
}),
{
name: 'other-plugin',
@@ -632,684 +1197,1996 @@ describe('rollup-plugin-html', () => {
} as Plugin,
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- 'hello world ' +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(3);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+ `);
});
it('includes referenced assets in the bundle', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ 'image-b.png': 'image-b.png',
+ 'image-c.png': 'image-c.png',
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'image-c.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'foo/bar/y.css': css`
+ :root {
+ color: y;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: {
- html: `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(11);
- const expectedAssets = [
- 'image-c.png',
- 'webmanifest.json',
- 'image-a.svg',
- 'styles.css',
- 'x.css',
- 'y.css',
- 'image-b.svg',
- ];
-
- for (const name of expectedAssets) {
- const asset = getAsset(output, name);
- expect(asset).to.exist;
- expect(asset.source).to.exist;
- }
-
- const outputHtml = getAsset(output, 'index.html').source;
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(11);
+
+ expect(assets).to.have.keys([
+ 'assets/image-a-XOCPHCrV.png',
+ 'assets/image-b-BgQHKcRn.png',
+ 'assets/image-c-C4yLPiIL.png',
+ 'assets/image-a-BCCvKrTe.svg',
+ 'assets/image-b-C4stzVZW.svg',
+ 'assets/image-c-DPeYetg3.svg',
+ 'assets/styles-CF2Iy5n1.css',
+ 'assets/x-DDGg8O6h.css',
+ 'assets/y-DJTrnPH3.css',
+ 'assets/webmanifest-BkrOR1WG.json',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
});
- it('deduplicates static assets with similar names', async () => {
+ it('[legacy] includes referenced assets in the bundle', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ 'image-b.png': 'image-b.png',
+ 'image-c.png': 'image-c.png',
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'foo/bar/y.css': css`
+ :root {
+ color: y;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html',
input: {
- html: `
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(10);
+
+ expect(assets).to.have.keys([
+ 'assets/image-a.png',
+ 'assets/image-b.png',
+ 'assets/image-c-C4yLPiIL.png',
+ 'assets/image-a.svg',
+ 'assets/image-b-C4stzVZW.svg',
+ 'assets/styles-CF2Iy5n1.css',
+ 'assets/x-DDGg8O6h.css',
+ 'assets/y-DJTrnPH3.css',
+ 'assets/webmanifest.json',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+ });
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- '' +
- ' ' +
- ' ' +
- '',
- );
+ it('does not deduplicate static assets with similar names', async () => {
+ const rootDir = createApp({
+ 'foo.svg': svg` `,
+ 'x/foo.svg': svg` `,
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ input: {
+ html: html`
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(assets).to.have.keys([
+ 'assets/foo-BCCvKrTe.svg',
+ 'assets/foo-C4stzVZW.svg',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
- it('static and hashed asset nodes can reference the same files', async () => {
+ it('[legacy] deduplicates static assets with similar names', async () => {
+ const rootDir = createApp({
+ 'foo.svg': svg` `,
+ 'x/foo.svg': svg` `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html',
input: {
- html: `
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(assets).to.have.keys(['assets/foo.svg', 'assets/foo1.svg', 'index.html']);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
+ });
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- ' ' +
- ' ',
- );
+ it('[legacy] static and hashed asset nodes can reference the same files', async () => {
+ const rootDir = createApp({
+ 'foo.svg': svg` `,
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html',
+ input: {
+ html: html`
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(assets).to.have.keys(['assets/foo.svg', 'assets/foo-BCCvKrTe.svg', 'index.html']);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+ `);
});
it('deduplicates common assets', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: {
- html: `
-
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- '' +
- ' ' +
- ' ' +
- ' ' +
- '',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(2);
+
+ expect(assets).to.have.keys(['assets/image-a-XOCPHCrV.png', 'index.html']);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+ `);
});
it('deduplicates common assets across HTML files', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: [
{
name: 'page-a.html',
- html: `
-
-
-
- `,
+ html: html`
+
+
+
+
+
+ `,
},
{
name: 'page-b.html',
- html: `
-
-
-
- `,
+ html: html`
+
+
+
+
+
+ `,
},
{
name: 'page-c.html',
- html: `
-
-
-
-
- `,
+ html: html`
+
+
+
+
+
+
+ `,
},
],
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- expect(stripNewlines(getAsset(output, 'page-a.html').source)).to.equal(
- '' +
- ' ' +
- ' ',
- );
-
- expect(stripNewlines(getAsset(output, 'page-b.html').source)).to.equal(
- '' +
- ' ' +
- ' ',
- );
-
- expect(stripNewlines(getAsset(output, 'page-c.html').source)).to.equal(
- '' +
- ' ' +
- ' ' +
- ' ',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/image-a-XOCPHCrV.png',
+ 'page-a.html',
+ 'page-b.html',
+ 'page-c.html',
+ ]);
+
+ expect(assets['page-a.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['page-b.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['page-c.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
});
it('can turn off extracting assets', async () => {
+ const rootDir = createApp({
+ 'image-c.png': 'image-c.png',
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
extractAssets: false,
+ rootDir,
input: {
- html: `
-
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- expect(output.length).to.equal(2);
- expect(stripNewlines(getAsset(output, 'index.html').source)).to.equal(
- ' ',
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+ `);
});
it('can inject a CSP meta tag for inline scripts', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ console.log('entrypoint-b.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/csp-page-a.html'),
- rootDir,
strictCSPInlineScripts: true,
+ rootDir,
+ input: './index.html',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'csp-page-a.html').source)).to.equal(
- '' +
- " " +
- 'hello world ' +
- "" +
- "" +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(2);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('can add to an existing CSP meta tag for inline scripts', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ console.log('entrypoint-b.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/csp-page-b.html'),
- rootDir,
strictCSPInlineScripts: true,
+ rootDir,
+ input: './index.html',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'csp-page-b.html').source)).to.equal(
- '' +
- " " +
- 'hello world ' +
- "" +
- "" +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(2);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('can add to an existing CSP meta tag for inline scripts even if script-src is already there', async () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ 'entrypoint-a.js': js`
+ console.log('entrypoint-a.js');
+ `,
+ 'entrypoint-b.js': js`
+ console.log('entrypoint-b.js');
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- input: require.resolve('./fixtures/rollup-plugin-html/csp-page-c.html'),
- rootDir,
strictCSPInlineScripts: true,
+ rootDir,
+ input: './index.html',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- expect(output.length).to.equal(4);
- const { code: entryA } = getChunk(output, 'entrypoint-a.js');
- const { code: entryB } = getChunk(output, 'entrypoint-b.js');
- expect(entryA).to.include("console.log('entrypoint-a.js');");
- expect(entryB).to.include("console.log('entrypoint-b.js');");
- expect(stripNewlines(getAsset(output, 'csp-page-c.html').source)).to.equal(
- '' +
- " " +
- 'hello world ' +
- "" +
- "" +
- '' +
- '' +
- '',
- );
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(2);
+ expect(Object.keys(assets)).to.have.lengthOf(1);
+
+ expect(chunks['entrypoint-a.js']).to.include(js`console.log('entrypoint-a.js');`);
+ expect(chunks['entrypoint-b.js']).to.include(js`console.log('entrypoint-b.js');`);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('can inject a service worker registration script if injectServiceWorker and serviceWorkerPath are provided', async () => {
- const serviceWorkerPath = path.join(
- // @ts-ignore
- path.resolve(outputConfig.dir),
- 'service-worker.js',
- );
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ inject a service worker into /index.html
+
+
+ `,
+ 'sub-pure-html/index.html': html`
+
+
+ inject a service worker into /sub-page/index.html
+
+
+ `,
+ 'sub-with-js/index.html': html`
+
+
+ inject a service worker into /sub-page/index.html
+
+
+
+ `,
+ 'sub-with-js/sub-js.js': js`console.log('sub-with-js');`,
+ });
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: '**/*.html',
- rootDir: path.join(__dirname, 'fixtures', 'inject-service-worker'),
flattenOutput: false,
injectServiceWorker: true,
- serviceWorkerPath,
+ serviceWorkerPath: path.join(
+ path.resolve(outputConfig.dir as string),
+ 'service-worker.js',
+ ),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
- function extractServiceWorkerPath(src: string) {
- const registerOpen = src.indexOf(".register('");
- const registerClose = src.indexOf("')", registerOpen + 11);
- return src.substring(registerOpen + 11, registerClose);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(3);
+
+ expect(assets).to.have.keys([
+ 'index.html',
+ 'sub-with-js/index.html',
+ 'sub-pure-html/index.html',
+ ]);
+
+ function extractServiceWorkerPath(code: string) {
+ const registerOpen = code.indexOf(".register('");
+ const registerClose = code.indexOf("')", registerOpen + 11);
+ return code.substring(registerOpen + 11, registerClose);
}
- expect(extractServiceWorkerPath(getAsset(output, 'index.html').source)).to.equal(
- 'service-worker.js',
+ expect(extractServiceWorkerPath(assets['index.html'] as string)).to.equal('service-worker.js');
+ expect(extractServiceWorkerPath(assets['sub-with-js/index.html'] as string)).to.equal(
+ '../service-worker.js',
+ );
+ expect(extractServiceWorkerPath(assets['sub-pure-html/index.html'] as string)).to.equal(
+ '../service-worker.js',
);
- expect(
- extractServiceWorkerPath(getAsset(output, path.join('sub-with-js', 'index.html')).source),
- ).to.equal(`../service-worker.js`);
- expect(
- extractServiceWorkerPath(getAsset(output, path.join('sub-pure-html', 'index.html')).source),
- ).to.equal(`../service-worker.js`);
});
it('does support a absolutePathPrefix to allow for sub folder deployments', async () => {
+ const rootDir = createApp({
+ 'x/foo.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ absolutePathPrefix: '/my-prefix/',
+ rootDir,
input: {
- html: `
-
-
-
-
-
-`,
name: 'x/index.html',
+ html: html`
+
+
+
+
+
+
+
+
+
+ `,
},
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
- absolutePathPrefix: '/my-prefix/',
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- expect(stripNewlines(getAsset(output, 'x/index.html').source)).to.equal(
- [
- '',
- ' ',
- ' ',
- ' ',
- '',
- ].join(''),
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/styles-CF2Iy5n1.css',
+ 'assets/foo-CxmWeBHm.svg',
+ 'assets/image-b-C4stzVZW.svg',
+ 'x/index.html',
+ ]);
+
+ expect(assets['x/index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+ `);
});
it('handles fonts linked from css files', async () => {
+ const rootDir = createApp({
+ 'fonts/font-bold.woff2': 'font-bold',
+ 'fonts/font-normal.woff2': 'font-normal',
+ 'styles.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-bold.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- bundleAssetsFromCss: true,
+ rootDir,
input: {
- html: `
+ html: html`
-
+
-
-
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/font-normal-Cht9ZB76.woff2',
+ 'assets/font-bold-eQjSonqH.woff2',
+ 'assets/styles-Dhs3ufep.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-Dhs3ufep.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('font-bold-eQjSonqH.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+ });
+
+ it('[legacy] handles fonts linked from css files', async () => {
+ const rootDir = createApp({
+ 'fonts/font-bold.woff2': 'font-bold',
+ 'fonts/font-normal.woff2': 'font-normal',
+ 'styles.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-bold.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html-and-css',
+ input: {
+ html: html`
+
+
+
+
+
`,
},
- rootDir: path.join(__dirname, 'fixtures', 'resolves-assets-in-styles'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- const fontNormal = output.find(o => o.name?.endsWith('font-normal.woff2'));
- const fontBold = output.find(o => o.name?.endsWith('font-normal.woff2'));
- const style = output.find(o => o.name?.endsWith('styles-with-fonts.css'));
- // It has emitted the font
- expect(fontBold).to.exist;
- expect(fontNormal).to.exist;
- // e.g. "font-normal-f0mNRiTD.woff2"
- // eslint-disable-next-line no-useless-escape
- const regex = /assets[\/\\]font-normal-\w+\.woff2/;
- // It outputs the font to the assets folder
- expect(regex.test(fontNormal!.fileName)).to.equal(true);
-
- // The source of the style includes the font
- const source = (style as OutputAsset)?.source.toString();
- expect(source.includes(fontNormal!.fileName));
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/assets/font-normal-Cht9ZB76.woff2',
+ 'assets/assets/font-bold-eQjSonqH.woff2',
+ 'assets/styles-BUBaODov.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-BUBaODov.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('assets/font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('assets/font-bold-eQjSonqH.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
});
it('handles fonts linked from css files in node_modules', async () => {
+ const rootDir = createApp({
+ 'node_modules/foo/fonts/font-bold.woff2': 'font-bold',
+ 'node_modules/foo/fonts/font-normal.woff2': 'font-normal',
+ 'node_modules/foo/styles.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-bold.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- bundleAssetsFromCss: true,
+ rootDir,
input: {
- html: `
+ html: html`
-
+
-
-
+
`,
},
- rootDir: path.join(__dirname, 'fixtures', 'resolves-assets-in-styles-node-modules'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/font-normal-Cht9ZB76.woff2',
+ 'assets/font-bold-eQjSonqH.woff2',
+ 'assets/styles-Dhs3ufep.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-Dhs3ufep.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('font-bold-eQjSonqH.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+ });
- const font = output.find(o => o.name?.endsWith('font-normal.woff2'));
- const style = output.find(o => o.name?.endsWith('node_modules-styles-with-fonts.css'));
+ it('[legacy] handles fonts linked from css files in node_modules', async () => {
+ const rootDir = createApp({
+ 'node_modules/foo/fonts/font-bold.woff2': 'font-bold',
+ 'node_modules/foo/fonts/font-normal.woff2': 'font-normal',
+ 'node_modules/foo/styles.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-bold.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ });
- // It has emitted the font
- expect(font).to.exist;
- // e.g. "font-normal-f0mNRiTD.woff2"
- // eslint-disable-next-line no-useless-escape
- const regex = /assets[\/\\]font-normal-\w+\.woff2/;
- // It outputs the font to the assets folder
- expect(regex.test(font!.fileName)).to.equal(true);
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html-and-css',
+ input: {
+ html: html`
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
- // The source of the style includes the font
- const source = (style as OutputAsset)?.source.toString();
- expect(source.includes(font!.fileName));
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/assets/font-normal-Cht9ZB76.woff2',
+ 'assets/assets/font-bold-eQjSonqH.woff2',
+ 'assets/styles-BUBaODov.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-BUBaODov.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('assets/font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+
+ @font-face {
+ font-family: Font;
+ src: url('assets/font-bold-eQjSonqH.woff2') format('woff2');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
});
it('handles duplicate fonts correctly', async () => {
+ const rootDir = createApp({
+ 'fonts/font-normal.woff2': 'font-normal',
+ 'styles-a.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ 'styles-b.css': css`
+ @font-face {
+ font-family: Font2;
+ src: url('fonts/font-normal.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- bundleAssetsFromCss: true,
+ rootDir,
input: {
- html: `
+ html: html`
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(4);
+
+ expect(assets).to.have.keys([
+ 'assets/font-normal-Cht9ZB76.woff2',
+ 'assets/styles-a-jFIfrzm8.css',
+ 'assets/styles-b-B-8m1N7T.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-a-jFIfrzm8.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+
+ expect(assets['assets/styles-b-B-8m1N7T.css']).to.equal(css`
+ @font-face {
+ font-family: Font2;
+ src: url('font-normal-Cht9ZB76.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+ });
+
+ it('handles images referenced from css', async () => {
+ const rootDir = createApp({
+ 'images/star.avif': 'star.avif',
+ 'images/star.gif': 'star.gif',
+ 'images/star.jpeg': 'star.jpeg',
+ 'images/star.jpg': 'star.jpg',
+ 'images/star.png': 'star.png',
+ 'images/star.svg': 'star.svg',
+ 'images/star.webp': 'star.webp',
+ 'styles.css': css`
+ #a {
+ background-image: url('images/star.avif');
+ }
+
+ #b {
+ background-image: url('images/star.gif');
+ }
+
+ #c {
+ background-image: url('images/star.jpeg');
+ }
+
+ #d {
+ background-image: url('images/star.jpg');
+ }
+
+ #e {
+ background-image: url('images/star.png');
+ }
+
+ #f {
+ background-image: url('images/star.svg');
+ }
+
+ #g {
+ background-image: url('images/star.svg#foo');
+ }
+
+ #h {
+ background-image: url('images/star.webp');
+ }
+ `,
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ input: {
+ html: html`
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(9);
+
+ expect(assets).to.have.keys([
+ 'assets/star-D_LO5feX.avif',
+ 'assets/star-BKg9qmmf.gif',
+ 'assets/star-BZWqL7hS.jpeg',
+ 'assets/star-Df0JryvN.jpg',
+ 'assets/star-CXig10q7.png',
+ 'assets/star-CwhgM_z4.svg',
+ 'assets/star-CKbh5mKn.webp',
+ 'assets/styles-mywkihBc.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-mywkihBc.css']).to.equal(css`
+ #a {
+ background-image: url('star-D_LO5feX.avif');
+ }
+
+ #b {
+ background-image: url('star-BKg9qmmf.gif');
+ }
+
+ #c {
+ background-image: url('star-BZWqL7hS.jpeg');
+ }
+
+ #d {
+ background-image: url('star-Df0JryvN.jpg');
+ }
+
+ #e {
+ background-image: url('star-CXig10q7.png');
+ }
+
+ #f {
+ background-image: url('star-CwhgM_z4.svg');
+ }
+
+ #g {
+ background-image: url('star-CwhgM_z4.svg#foo');
+ }
+
+ #h {
+ background-image: url('star-CKbh5mKn.webp');
+ }
+ `);
+ });
+
+ it('[legacy] handles images referenced from css', async () => {
+ const rootDir = createApp({
+ 'images/star.avif': 'star.avif',
+ 'images/star.gif': 'star.gif',
+ 'images/star.jpeg': 'star.jpeg',
+ 'images/star.jpg': 'star.jpg',
+ 'images/star.png': 'star.png',
+ 'images/star.svg': 'star.svg',
+ 'images/star.webp': 'star.webp',
+ 'styles.css': css`
+ #a {
+ background-image: url('images/star.avif');
+ }
+
+ #b {
+ background-image: url('images/star.gif');
+ }
+
+ #c {
+ background-image: url('images/star.jpeg');
+ }
+
+ #d {
+ background-image: url('images/star.jpg');
+ }
+
+ #e {
+ background-image: url('images/star.png');
+ }
+
+ #f {
+ background-image: url('images/star.svg');
+ }
+
+ #g {
+ background-image: url('images/star.svg#foo');
+ }
+
+ #h {
+ background-image: url('images/star.webp');
+ }
+ `,
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ extractAssets: 'legacy-html-and-css',
+ input: {
+ html: html`
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
+
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(9);
+
+ expect(assets).to.have.keys([
+ 'assets/assets/star-D_LO5feX.avif',
+ 'assets/assets/star-BKg9qmmf.gif',
+ 'assets/assets/star-BZWqL7hS.jpeg',
+ 'assets/assets/star-Df0JryvN.jpg',
+ 'assets/assets/star-CXig10q7.png',
+ 'assets/assets/star-CwhgM_z4.svg',
+ 'assets/assets/star-CKbh5mKn.webp',
+ 'assets/styles-Cuqf3qRf.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-Cuqf3qRf.css']).to.equal(css`
+ #a {
+ background-image: url('assets/star-D_LO5feX.avif');
+ }
+
+ #b {
+ background-image: url('assets/star-BKg9qmmf.gif');
+ }
+
+ #c {
+ background-image: url('assets/star-BZWqL7hS.jpeg');
+ }
+
+ #d {
+ background-image: url('assets/star-Df0JryvN.jpg');
+ }
+
+ #e {
+ background-image: url('assets/star-CXig10q7.png');
+ }
+
+ #f {
+ background-image: url('assets/star-CwhgM_z4.svg');
+ }
+
+ #g {
+ background-image: url('assets/star-CwhgM_z4.svg#foo');
+ }
+
+ #h {
+ background-image: url('assets/star-CKbh5mKn.webp');
+ }
+ `);
+ });
+
+ it('allows to exclude external assets usign a glob pattern', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ 'image-b.png': 'image-b.png',
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ #a1 {
+ background-image: url('image-a.png');
+ }
+
+ #a2 {
+ background-image: url('image-a.svg');
+ }
+
+ #d1 {
+ background-image: url('./image-b.png');
+ }
+
+ #d2 {
+ background-image: url('./image-b.svg');
+ }
+ `,
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'foo/bar/y.css': css`
+ :root {
+ color: y;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ externalAssets: ['**/foo/**/*', '*.svg'],
+ rootDir,
+ input: {
+ html: html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`,
},
- rootDir: path.join(__dirname, 'fixtures', 'resolves-assets-in-styles-duplicates'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- const fonts = output.filter(o => o.name?.endsWith('font-normal.woff2'));
- expect(fonts.length).to.equal(1);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(5);
+
+ expect(assets).to.have.keys([
+ 'assets/image-a-XOCPHCrV.png',
+ 'assets/image-b-BgQHKcRn.png',
+ 'assets/styles-Bv-4gk2N.css',
+ 'assets/webmanifest-BkrOR1WG.json',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-Bv-4gk2N.css']).to.equal(css`
+ #a1 {
+ background-image: url('image-a-XOCPHCrV.png');
+ }
+
+ #a2 {
+ background-image: url('image-a.svg');
+ }
+
+ #d1 {
+ background-image: url('image-b-BgQHKcRn.png');
+ }
+
+ #d2 {
+ background-image: url('./image-b.svg');
+ }
+ `);
});
- it('handles images referenced from css', async () => {
+ it('[legacy] allows to exclude external assets usign a glob pattern', async () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ 'image-b.png': 'image-b.png',
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ #a1 {
+ background-image: url('image-a.png');
+ }
+
+ #a2 {
+ background-image: url('image-a.svg');
+ }
+
+ #d1 {
+ background-image: url('./image-b.png');
+ }
+
+ #d2 {
+ background-image: url('./image-b.svg');
+ }
+ `,
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'foo/bar/y.css': css`
+ :root {
+ color: y;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
const config = {
plugins: [
rollupPluginHTML({
- bundleAssetsFromCss: true,
+ externalAssets: ['**/foo/**/*', '*.svg'],
+ rootDir,
+ extractAssets: 'legacy-html-and-css',
input: {
- html: `
+ html: html`
+
+
+
+
+
+
+
+
+
+
+
`,
},
- rootDir: path.join(__dirname, 'fixtures', 'resolves-assets-in-styles-images'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
-
- expect(output.find(o => o.name?.endsWith('star.avif'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.gif'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.jpeg'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.jpg'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.png'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.svg'))).to.exist;
- expect(output.find(o => o.name?.endsWith('star.webp'))).to.exist;
-
- const rewrittenCss = (output.find(o => o.name === 'styles.css') as OutputAsset).source
- .toString()
- .trim();
- expect(rewrittenCss).to.equal(
- `#a {
- background-image: url("assets/star-CauvOfkF.svg");
-}
-
-#b {
- background-image: url("assets/star-CauvOfkF.svg#foo");
-}
-
-#c {
- background-image: url("assets/star-B4Suw7Xi.png");
-}
-
-#d {
- background-image: url("assets/star-DKp8fJdA.jpg");
-}
-
-#e {
- background-image: url("assets/star-b-LlGmiF.jpeg");
-}
-
-#f {
- background-image: url("assets/star-CXtvny3e.webp");
-}
-
-#g {
- background-image: url("assets/star-_hNhEHAt.gif");
-}
-
-#h {
- background-image: url("assets/star-fTpYetjL.avif");
-}`.trim(),
- );
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, outputConfig);
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(7);
+
+ expect(assets).to.have.keys([
+ 'assets/assets/image-a-XOCPHCrV.png',
+ 'assets/assets/image-b-BgQHKcRn.png',
+ 'assets/image-a.png',
+ 'assets/image-b.png',
+ 'assets/styles-DFIb0lB5.css',
+ 'assets/webmanifest.json',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `);
+
+ expect(assets['assets/styles-DFIb0lB5.css']).to.equal(css`
+ #a1 {
+ background-image: url('assets/image-a-XOCPHCrV.png');
+ }
+
+ #a2 {
+ background-image: url('image-a.svg');
+ }
+
+ #d1 {
+ background-image: url('assets/image-b-BgQHKcRn.png');
+ }
+
+ #d2 {
+ background-image: url('./image-b.svg');
+ }
+ `);
});
- it('allows to exclude external assets usign a glob pattern', async () => {
+ it('rewrites paths according to assetFileNames', async () => {
+ const rootDir = createApp({
+ 'node_modules/ing-web/fonts/font.woff2': 'font.woff',
+ 'node_modules/ing-web/global.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ 'assets/images/image.png': 'image.png',
+ 'assets/styles.css': css`
+ #a {
+ background-image: url('images/image.png');
+ }
+ `,
+ 'src/main.js': js`
+ const imageUrl = new URL('../assets/images/image.png', import.meta.url).href;
+ `,
+ });
+
const config = {
plugins: [
rollupPluginHTML({
+ rootDir,
input: {
- html: `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`,
+ html: html`
+
+
+
+
+
+
+
+
+
+
+ `,
},
- bundleAssetsFromCss: true,
- externalAssets: ['**/foo/**/*', '*.svg'],
- rootDir: path.join(__dirname, 'fixtures', 'assets'),
}),
],
};
- const bundle = await rollup(config);
- const { output } = await bundle.generate(outputConfig);
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, {
+ ...outputConfig,
+ assetFileNames: 'static/[name].immutable.[hash][extname]',
+ });
+
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(5);
+
+ expect(assets).to.have.keys([
+ 'static/font.immutable.C5MNjX-h.woff2',
+ 'static/global.immutable.DB0fKkjs.css',
+ 'static/image.immutable.7xJLr_7N.png',
+ 'static/styles.immutable.D4tZXVv0.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+ `);
+
+ expect(assets['static/global.immutable.DB0fKkjs.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('font.immutable.C5MNjX-h.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+
+ expect(assets['static/styles.immutable.D4tZXVv0.css']).to.equal(css`
+ #a {
+ background-image: url('image.immutable.7xJLr_7N.png');
+ }
+ `);
+ });
- expect(output.length).to.equal(8);
+ it('resolves paths by using publicPath when assetFileNames puts assets in different dirs', async () => {
+ const rootDir = createApp({
+ 'node_modules/ing-web/fonts/font.woff2': 'font.woff',
+ 'node_modules/ing-web/global.css': css`
+ @font-face {
+ font-family: Font;
+ src: url('fonts/font.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `,
+ 'assets/images/image.png': 'image.png',
+ 'assets/styles.css': css`
+ #a {
+ background-image: url('images/image.png');
+ }
+ `,
+ 'src/main.js': js`
+ const imageUrl = new URL('../assets/images/image.png', import.meta.url).href;
+ `,
+ });
- const expectedAssets = [
- 'image-a.png',
- 'image-d.png',
- 'styles-with-referenced-assets.css',
- 'image-a.png',
- 'image-d.png',
- 'webmanifest.json',
- ];
+ const config = {
+ plugins: [
+ rollupPluginHTML({
+ rootDir,
+ publicPath: '/static/',
+ input: {
+ html: html`
+
+
+
+
+
+
+
+
+
+
+ `,
+ },
+ }),
+ ],
+ };
- for (const name of expectedAssets) {
- const asset = getAsset(output, name);
- expect(asset).to.exist;
- expect(asset.source).to.exist;
- }
+ const build = await rollup(config);
+ const { chunks, assets } = await generateTestBundle(build, {
+ ...outputConfig,
+ assetFileNames: assetInfo => {
+ const name = assetInfo.names[0] || '';
+ if (name.endsWith('.woff2')) {
+ return 'fonts/[name].immutable.[hash][extname]';
+ } else if (name.endsWith('.css')) {
+ return 'styles/[name].immutable.[hash][extname]';
+ } else if (name.endsWith('.png')) {
+ return 'images/[name].immutable.[hash][extname]';
+ }
+ return '[name].immutable.[hash][extname]';
+ },
+ });
- const outputHtml = getAsset(output, 'index.html').source;
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(
- ' ',
- );
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
- expect(outputHtml).to.include(' ');
-
- const rewrittenCss = getAsset(output, 'styles-with-referenced-assets.css')
- .source.toString()
- .trim();
- expect(rewrittenCss).to.equal(
- `#a1 {
- background-image: url("assets/image-a-yvktvaNB.png");
-}
-
-#a2 {
- background-image: url("image-a.svg");
-}
-
-#d1 {
- background-image: url("assets/image-d-DLz8BAwO.png");
-}
-
-#d2 {
- background-image: url("./image-d.svg");
-}`.trim(),
- );
+ expect(Object.keys(chunks)).to.have.lengthOf(1);
+ expect(Object.keys(assets)).to.have.lengthOf(5);
+
+ expect(assets).to.have.keys([
+ 'fonts/font.immutable.C5MNjX-h.woff2',
+ 'styles/global.immutable.B3Q0ucg4.css',
+ 'images/image.immutable.7xJLr_7N.png',
+ 'styles/styles.immutable.C3Z0Fs2-.css',
+ 'index.html',
+ ]);
+
+ expect(assets['index.html']).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+ `);
+
+ expect(assets['styles/global.immutable.B3Q0ucg4.css']).to.equal(css`
+ @font-face {
+ font-family: Font;
+ src: url('/static/fonts/font.immutable.C5MNjX-h.woff2') format('woff2');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+ }
+ `);
+
+ expect(assets['styles/styles.immutable.C3Z0Fs2-.css']).to.equal(css`
+ #a {
+ background-image: url('/static/images/image.immutable.7xJLr_7N.png');
+ }
+ `);
});
});
diff --git a/packages/rollup-plugin-html/test/src/input/InputData.test.ts b/packages/rollup-plugin-html/test/src/input/InputData.test.ts
index aaf229d0b..f1fab22f9 100644
--- a/packages/rollup-plugin-html/test/src/input/InputData.test.ts
+++ b/packages/rollup-plugin-html/test/src/input/InputData.test.ts
@@ -1,11 +1,10 @@
import { expect } from 'chai';
import path from 'path';
+import { cleanApp, createApp, html, js } from '../../utils.js';
import { getInputData } from '../../../src/input/getInputData.js';
import { InputData } from '../../../src/input/InputData.js';
-const rootDir = path.join(__dirname, '..', '..', 'fixtures', 'basic');
-
function cleanupHtml(str: string) {
return str.replace(/(\r\n|\n|\r| )/gm, '');
}
@@ -19,7 +18,24 @@ function cleanupResult(result: InputData[]) {
}
describe('getInputData()', () => {
+ afterEach(() => {
+ cleanApp();
+ });
+
it('supports setting input as string', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ input: 'index.html', rootDir });
expect(cleanupResult(result)).to.eql([
{
@@ -34,6 +50,19 @@ describe('getInputData()', () => {
});
it('supports setting input as object', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ input: { path: 'index.html' }, rootDir });
expect(cleanupResult(result)).to.eql([
{
@@ -48,6 +77,19 @@ describe('getInputData()', () => {
});
it('supports changing file name', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ input: { path: 'index.html', name: 'foo.html' }, rootDir });
expect(cleanupResult(result)).to.eql([
{
@@ -62,6 +104,26 @@ describe('getInputData()', () => {
});
it('supports setting multiple inputs', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'not-index.html': html`
+
+
+ not-index.html
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({
input: [{ path: 'index.html' }, { path: 'not-index.html' }],
rootDir,
@@ -87,13 +149,26 @@ describe('getInputData()', () => {
});
it('resolves modules relative to HTML file', () => {
+ const rootDir = createApp({
+ 'src/index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'src/app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ input: 'src/index.html', rootDir });
expect(cleanupResult(result)).to.eql([
{
filePath: path.join(rootDir, 'src/index.html'),
- html: 'Foo
',
+ html: 'Helloworld
',
inlineModules: [],
- moduleImports: [{ importPath: path.join(rootDir, 'src', 'foo.js'), attributes: [] }],
+ moduleImports: [{ importPath: path.join(rootDir, 'src', 'app.js'), attributes: [] }],
assets: [],
name: 'index.html',
},
@@ -101,6 +176,19 @@ describe('getInputData()', () => {
});
it('supports setting input as rollup input string', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ rootDir }, 'index.html');
expect(cleanupResult(result)).to.eql([
{
@@ -115,6 +203,19 @@ describe('getInputData()', () => {
});
it('supports setting input as rollup input array', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ rootDir }, ['index.html']);
expect(cleanupResult(result)).to.eql([
{
@@ -129,6 +230,26 @@ describe('getInputData()', () => {
});
it('supports setting input as rollup input array', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'not-index.html': html`
+
+
+ not-index.html
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ rootDir }, ['index.html', 'not-index.html']);
expect(cleanupResult(result)).to.eql([
{
@@ -151,6 +272,26 @@ describe('getInputData()', () => {
});
it('supports setting input as rollup input object', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'not-index.html': html`
+
+
+ not-index.html
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData(
{ rootDir },
{ 'a.html': 'index.html', 'b.html': 'not-index.html' },
@@ -176,6 +317,26 @@ describe('getInputData()', () => {
});
it('plugin input takes presedence over rollup input', () => {
+ const rootDir = createApp({
+ 'index.html': html`
+
+
+ Hello world
+
+
+
+ `,
+ 'not-index.html': html`
+
+
+ not-index.html
+
+
+ `,
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({ input: 'index.html', rootDir }, 'not-index.html');
expect(cleanupResult(result)).to.eql([
{
@@ -190,15 +351,24 @@ describe('getInputData()', () => {
});
it('can set html string as input', () => {
- const html = `
-
-
- HTML as string
-
-
-
- `;
- const result = getInputData({ input: { html }, rootDir });
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
+ const result = getInputData({
+ input: {
+ html: html`
+
+
+ HTML as string
+
+
+
+ `,
+ },
+ rootDir,
+ });
expect(cleanupResult(result)).to.eql([
{
filePath: undefined,
@@ -212,27 +382,36 @@ describe('getInputData()', () => {
});
it('can set multiple html strings as input', () => {
- const html1 = `
-
-
- HTML1
-
-
-
- `;
- const html2 = `
-
-
- HTML2
-
-
- `;
+ const rootDir = createApp({
+ 'app.js': js`
+ console.log('hello world');
+ `,
+ });
const result = getInputData({
+ rootDir,
input: [
- { html: html1, name: '1.html' },
- { html: html2, name: '2.html' },
+ {
+ name: '1.html',
+ html: html`
+
+
+ HTML1
+
+
+
+ `,
+ },
+ {
+ name: '2.html',
+ html: html`
+
+
+ HTML2
+
+
+ `,
+ },
],
- rootDir,
});
expect(cleanupResult(result)).to.eql([
{
@@ -255,6 +434,47 @@ describe('getInputData()', () => {
});
it('supports setting input to a glob', () => {
+ const rootDir = createApp({
+ 'pages/page-a.html': html`
+
+
+ page-a.html
+
+
+
+
+ `,
+ 'pages/page-b.html': html`
+
+
+ page-b.html
+
+
+
+
+ `,
+ 'pages/page-c.html': html`
+
+
+ page-c.html
+
+
+
+
+ `,
+ 'pages/page-a.js': js`
+ export default 'page a';
+ `,
+ 'pages/page-b.js': js`
+ export default 'page b';
+ `,
+ 'pages/page-c.js': js`
+ export default 'page c';
+ `,
+ 'pages/shared.js': js`
+ export default 'shared';
+ `,
+ });
const result = getInputData({ input: 'pages/**/*.html', rootDir });
expect(cleanupResult(result)).to.eql([
{
@@ -294,6 +514,47 @@ describe('getInputData()', () => {
});
it('supports not flattening output directories', () => {
+ const rootDir = createApp({
+ 'pages/page-a.html': html`
+
+
+ page-a.html
+
+
+
+
+ `,
+ 'pages/page-b.html': html`
+
+
+ page-b.html
+
+
+
+
+ `,
+ 'pages/page-c.html': html`
+
+
+ page-c.html
+
+
+
+
+ `,
+ 'pages/page-a.js': js`
+ export default 'page a';
+ `,
+ 'pages/page-b.js': js`
+ export default 'page b';
+ `,
+ 'pages/page-c.js': js`
+ export default 'page c';
+ `,
+ 'pages/shared.js': js`
+ export default 'shared';
+ `,
+ });
const result = getInputData({ input: 'pages/**/*.html', flattenOutput: false, rootDir });
expect(cleanupResult(result)).to.eql([
{
@@ -333,14 +594,19 @@ describe('getInputData()', () => {
});
it('supports pure HTML files', () => {
- const html = `
-
-
- pure HTML
-
-
- `;
- const result = getInputData({ input: { html }, rootDir });
+ const rootDir = createApp({});
+ const result = getInputData({
+ rootDir,
+ input: {
+ html: html`
+
+
+ pure HTML
+
+
+ `,
+ },
+ });
expect(cleanupResult(result)).to.eql([
{
filePath: undefined,
@@ -354,6 +620,7 @@ describe('getInputData()', () => {
});
it('throws when no files or html is given', () => {
+ const rootDir = createApp({});
expect(() => getInputData({ rootDir })).to.throw();
});
});
diff --git a/packages/rollup-plugin-html/test/src/input/extract/extractAssets.test.ts b/packages/rollup-plugin-html/test/src/input/extract/extractAssets.test.ts
index f2d4cdcd9..24a8dbd2b 100644
--- a/packages/rollup-plugin-html/test/src/input/extract/extractAssets.test.ts
+++ b/packages/rollup-plugin-html/test/src/input/extract/extractAssets.test.ts
@@ -2,20 +2,38 @@ import { expect } from 'chai';
import { parse } from 'parse5';
import path from 'path';
import { extractAssets } from '../../../../src/input/extract/extractAssets.js';
-
-const rootDir = path.resolve(__dirname, '..', '..', '..', 'fixtures', 'assets');
+import { html, css, js, svg, createApp, cleanApp } from '../../../utils.js';
describe('extractAssets', () => {
+ afterEach(() => {
+ cleanApp();
+ });
+
it('extracts assets from a document', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ 'image-b.png': 'image-b.png',
+ 'image-c.png': 'image-c.png',
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'image-c.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
+ const document = parse(html`
-
-
-
-
-
-
+
+
+
+
+
+
@@ -30,6 +48,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: rootDir,
rootDir,
+ extractAssets: true,
});
const assetsWithoutcontent = assets.map(a => ({ ...a, content: undefined }));
@@ -37,22 +56,22 @@ describe('extractAssets', () => {
{
content: undefined,
filePath: path.join(rootDir, 'image-a.png'),
- hashed: false,
+ hashed: true,
},
{
content: undefined,
filePath: path.join(rootDir, 'image-b.png'),
- hashed: false,
+ hashed: true,
},
{
content: undefined,
filePath: path.join(rootDir, 'webmanifest.json'),
- hashed: false,
+ hashed: true,
},
{
content: undefined,
filePath: path.join(rootDir, 'image-a.svg'),
- hashed: false,
+ hashed: true,
},
{
content: undefined,
@@ -61,7 +80,7 @@ describe('extractAssets', () => {
},
{
content: undefined,
- filePath: path.join(rootDir, 'image-social.png'),
+ filePath: path.join(rootDir, 'image-c.svg'),
hashed: true,
},
{
@@ -78,15 +97,25 @@ describe('extractAssets', () => {
});
it('reads file sources', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'image-a.svg': svg` `,
+ 'image-b.svg': svg` `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ 'webmanifest.json': { message: 'hello world' },
+ });
+
+ const document = parse(html`
-
-
-
+
+
+
-
@@ -98,6 +127,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: rootDir,
rootDir,
+ extractAssets: true,
});
const transformedAssets = assets.map(asset => ({
@@ -108,13 +138,12 @@ describe('extractAssets', () => {
{
content: '{"message":"helloworld"}',
filePath: path.join(rootDir, 'webmanifest.json'),
- hashed: false,
+ hashed: true,
},
{
- content:
- '',
+ content: ' ',
filePath: path.join(rootDir, 'image-a.svg'),
- hashed: false,
+ hashed: true,
},
{
content: ':root{color:blue;}',
@@ -122,8 +151,7 @@ describe('extractAssets', () => {
hashed: true,
},
{
- content:
- '',
+ content: ' ',
filePath: path.join(rootDir, 'image-b.svg'),
hashed: true,
},
@@ -131,11 +159,24 @@ describe('extractAssets', () => {
});
it('handles paths into directories', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'foo/bar/y.css': css`
+ :root {
+ color: y;
+ }
+ `,
+ });
+
+ const document = parse(html`
-
-
+
+
`);
@@ -144,6 +185,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: rootDir,
rootDir,
+ extractAssets: true,
});
expect(assets.length).to.equal(2);
@@ -154,11 +196,24 @@ describe('extractAssets', () => {
});
it('resolves relative to HTML file location', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ });
+
+ const document = parse(html`
-
-
+
+
`);
@@ -167,6 +222,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'foo', 'index.html'),
htmlDir: path.join(rootDir, 'foo'),
rootDir,
+ extractAssets: true,
});
expect(assets.length).to.equal(2);
@@ -177,11 +233,24 @@ describe('extractAssets', () => {
});
it('resolves absolute paths relative to root dir', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'foo/x.css': css`
+ :root {
+ color: x;
+ }
+ `,
+ 'styles.css': css`
+ :root {
+ color: blue;
+ }
+ `,
+ });
+
+ const document = parse(html`
-
-
+
+
`);
@@ -190,6 +259,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'foo', 'index.html'),
htmlDir: path.join(rootDir, 'foo'),
rootDir,
+ extractAssets: true,
});
expect(assets.length).to.equal(2);
@@ -199,12 +269,16 @@ describe('extractAssets', () => {
expect(assets[1].content.toString('utf-8').replace(/\s/g, '')).to.equal(':root{color:blue;}');
});
- it('can reference the same asset with a hashed and non-hashed node', () => {
- const document = parse(`
+ it('can deduplicate assets with same names', () => {
+ const rootDir = createApp({
+ 'image-a.png': 'image-a.png',
+ });
+
+ const document = parse(html`
-
-
+
+
`);
@@ -213,9 +287,10 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: rootDir,
rootDir,
+ extractAssets: true,
});
- expect(assets.length).to.equal(2);
+ expect(assets.length).to.equal(1);
const assetsWithoutcontent = assets.map(a => ({ ...a, content: undefined }));
expect(assetsWithoutcontent).to.eql([
{
@@ -223,19 +298,16 @@ describe('extractAssets', () => {
filePath: path.join(rootDir, 'image-a.png'),
hashed: true,
},
- {
- content: undefined,
- filePath: path.join(rootDir, 'image-a.png'),
- hashed: false,
- },
]);
});
it('does not count remote URLs as assets', () => {
- const document = parse(`
+ const rootDir = createApp({});
+
+ const document = parse(html`
-
+
`);
@@ -244,13 +316,18 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'foo', 'index.html'),
htmlDir: path.join(rootDir, 'foo'),
rootDir,
+ extractAssets: true,
});
expect(assets.length).to.equal(0);
});
it('does treat non module script tags as assets', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'no-module.js': js`/* no module script file */`,
+ });
+
+ const document = parse(html`
@@ -262,6 +339,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: path.join(rootDir),
rootDir,
+ extractAssets: true,
});
expect(assets.length).to.equal(1);
@@ -270,7 +348,14 @@ describe('extractAssets', () => {
});
it('handles a picture tag using source tags with srcset', () => {
- const document = parse(`
+ const rootDir = createApp({
+ 'images/eb26e6ca-30.avif': 'images/eb26e6ca-30.avif',
+ 'images/eb26e6ca-60.avif': 'images/eb26e6ca-60.avif',
+ 'images/eb26e6ca-30.jpeg': 'images/eb26e6ca-30.jpeg',
+ 'images/eb26e6ca-60.jpeg': 'images/eb26e6ca-60.jpeg',
+ });
+
+ const document = parse(html`
@@ -302,6 +387,7 @@ describe('extractAssets', () => {
htmlFilePath: path.join(rootDir, 'index.html'),
htmlDir: path.join(rootDir),
rootDir,
+ extractAssets: true,
});
// the src is not the same as the small jpeg image
diff --git a/packages/rollup-plugin-html/test/src/input/extract/extractModules.test.ts b/packages/rollup-plugin-html/test/src/input/extract/extractModules.test.ts
index 11fd545b5..f560f339e 100644
--- a/packages/rollup-plugin-html/test/src/input/extract/extractModules.test.ts
+++ b/packages/rollup-plugin-html/test/src/input/extract/extractModules.test.ts
@@ -1,19 +1,28 @@
import path from 'path';
import { parse, serialize } from 'parse5';
import { expect } from 'chai';
+import { html, js } from '../../../utils.js';
import { extractModules } from '../../../../src/input/extract/extractModules.js';
+import { ScriptModuleTag } from '../../../../src/RollupPluginHTMLOptions.js';
const { sep } = path;
+function cleanupInlineModules(modules: ScriptModuleTag[]) {
+ return modules.map(module => ({
+ ...module,
+ code: module.code ? js`${module.code}` : undefined,
+ }));
+}
+
describe('extractModules()', () => {
it('extracts all modules from a html document', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -27,18 +36,24 @@ describe('extractModules()', () => {
{ importPath: `${sep}foo.js`, attributes: [] },
{ importPath: `${sep}bar.js`, attributes: [] },
]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+ after
+
+
+ `);
});
it('does not touch non module scripts', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -49,18 +64,26 @@ describe('extractModules()', () => {
expect(inlineModules.length).to.equal(0);
expect(moduleImports).to.eql([]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+
+
+ after
+
+
+ `);
});
it('resolves imports relative to the root dir', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -74,18 +97,24 @@ describe('extractModules()', () => {
{ importPath: `${sep}foo.js`, attributes: [] },
{ importPath: `${sep}base${sep}bar.js`, attributes: [] },
]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+ after
+
+
+ `);
});
it('resolves relative imports relative to the relative import base', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -99,18 +128,28 @@ describe('extractModules()', () => {
{ importPath: `${sep}base-1${sep}base-2${sep}foo.js`, attributes: [] },
{ importPath: `${sep}base-1${sep}bar.js`, attributes: [] },
]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+ after
+
+
+ `);
});
it('extracts all inline modules from a html document', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -119,31 +158,41 @@ describe('extractModules()', () => {
});
const htmlWithoutModules = serialize(document);
- expect(inlineModules).to.eql([
+ expect(cleanupInlineModules(inlineModules)).to.eql([
{
- importPath: '/inline-module-cce79ce714e2c3b250afef32e61fb003.js',
- code: '/* my module 1 */',
+ importPath: '/inline-module-80efb22c2d1ce27c40eae10611f7680f.js',
+ code: js`/* my module 1 */`,
attributes: [],
},
{
- importPath: '/inline-module-d9a0918508784903d131c7c4eb98e424.js',
- code: '/* my module 2 */',
+ importPath: '/inline-module-b8a73bff59b998da13ce8a6801934f77.js',
+ code: js`/* my module 2 */`,
attributes: [],
},
]);
expect(moduleImports).to.eql([]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+ after
+
+
+ `);
});
it('prefixes inline module with index.html directory', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -152,31 +201,37 @@ describe('extractModules()', () => {
});
const htmlWithoutModules = serialize(document);
- expect(inlineModules).to.eql([
+ expect(cleanupInlineModules(inlineModules)).to.eql([
{
- importPath: '/foo/bar/inline-module-cce79ce714e2c3b250afef32e61fb003.js',
- code: '/* my module 1 */',
+ importPath: '/foo/bar/inline-module-80efb22c2d1ce27c40eae10611f7680f.js',
+ code: js`/* my module 1 */`,
attributes: [],
},
{
- importPath: '/foo/bar/inline-module-d9a0918508784903d131c7c4eb98e424.js',
- code: '/* my module 2 */',
+ importPath: '/foo/bar/inline-module-b8a73bff59b998da13ce8a6801934f77.js',
+ code: js`/* my module 2 */`,
attributes: [],
},
]);
expect(moduleImports).to.eql([]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+ after
+
+
+ `);
});
it('ignores absolute paths', () => {
- const document = parse(
- 'before
' +
- '' +
- '' +
- 'after
',
- );
+ const document = parse(html`
+ before
+
+
+ after
+ `);
const { moduleImports, inlineModules } = extractModules({
document,
@@ -187,8 +242,15 @@ describe('extractModules()', () => {
expect(inlineModules.length).to.equal(0);
expect(moduleImports).to.eql([{ importPath: `${sep}bar.js`, attributes: [] }]);
- expect(htmlWithoutModules).to.eql(
- 'before
after
',
- );
+ expect(html`${htmlWithoutModules}`).to.eql(html`
+
+
+
+ before
+
+ after
+
+
+ `);
});
});
diff --git a/packages/rollup-plugin-html/test/src/output/getOutputHTML.test.ts b/packages/rollup-plugin-html/test/src/output/getOutputHTML.test.ts
index 11cf7a7ed..024635e43 100644
--- a/packages/rollup-plugin-html/test/src/output/getOutputHTML.test.ts
+++ b/packages/rollup-plugin-html/test/src/output/getOutputHTML.test.ts
@@ -2,6 +2,7 @@ import { expect } from 'chai';
import path from 'path';
import { getOutputHTML, GetOutputHTMLParams } from '../../../src/output/getOutputHTML.js';
import { EntrypointBundle } from '../../../src/RollupPluginHTMLOptions.js';
+import { html } from '../../utils.js';
describe('getOutputHTML()', () => {
const defaultEntrypointBundles: Record = {
@@ -19,7 +20,7 @@ describe('getOutputHTML()', () => {
emittedAssets: { static: new Map(), hashed: new Map() },
entrypointBundles: defaultEntrypointBundles,
input: {
- html: 'Input HTML ',
+ html: html`Input HTML `,
name: 'index.html',
moduleImports: [],
assets: [],
@@ -33,12 +34,16 @@ describe('getOutputHTML()', () => {
it('injects output into the input HTML', async () => {
const output = await getOutputHTML(defaultOptions);
- expect(output).to.equal(
- 'Input HTML ' +
- '' +
- '' +
- '',
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Input HTML
+
+
+
+
+ `);
});
it('generates a HTML file for multiple rollup bundles', async () => {
@@ -58,14 +63,22 @@ describe('getOutputHTML()', () => {
};
const output = await getOutputHTML({ ...defaultOptions, entrypointBundles });
- expect(output).to.equal(
- 'Input HTML ' +
- '' +
- '' +
- '' +
- '' +
- '',
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Input HTML
+
+
+
+
+
+
+ `);
});
it('can transform html output', async () => {
@@ -77,12 +90,16 @@ describe('getOutputHTML()', () => {
},
});
- expect(output).to.equal(
- 'Transformed Input HTML ' +
- '' +
- '' +
- '',
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Transformed Input HTML
+
+
+
+
+ `);
});
it('allows setting multiple html transform functions', async () => {
@@ -97,12 +114,16 @@ describe('getOutputHTML()', () => {
},
});
- expect(output).to.equal(
- 'Transformed Input HTML ' +
- '' +
- '' +
- '',
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Transformed Input HTML
+
+
+
+
+ `);
});
it('can combine external and regular transform functions', async () => {
@@ -115,12 +136,16 @@ describe('getOutputHTML()', () => {
externalTransformHtmlFns: [html => html.replace(/h1/g, 'h2')],
});
- expect(output).to.equal(
- 'Transformed Input HTML ' +
- '' +
- '' +
- '',
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Transformed Input HTML
+
+
+
+
+ `);
});
it('can disable default injection', async () => {
@@ -129,7 +154,14 @@ describe('getOutputHTML()', () => {
defaultInjectDisabled: true,
});
- expect(output).to.equal('Input HTML ');
+ expect(html`${output}`).to.equal(html`
+
+
+
+ Input HTML
+
+
+ `);
});
it('can converts absolute urls to full absolute urls', async () => {
@@ -147,30 +179,34 @@ describe('getOutputHTML()', () => {
emittedAssets: { static: new Map(), hashed },
input: {
...defaultOptions.input,
- html: [
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- ].join('\n'),
+ html: html`
+
+
+
+
+
+
+
+
+
+
+ `,
filePath: path.join(rootDir, 'index.html'),
},
});
- expect(output).to.equal(
- [
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- ].join('\n'),
- );
+ expect(html`${output}`).to.equal(html`
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('can minify HTML', async () => {
diff --git a/packages/rollup-plugin-html/test/src/output/injectBundles.test.ts b/packages/rollup-plugin-html/test/src/output/injectBundles.test.ts
index 5068d8dc3..fb52cda0c 100644
--- a/packages/rollup-plugin-html/test/src/output/injectBundles.test.ts
+++ b/packages/rollup-plugin-html/test/src/output/injectBundles.test.ts
@@ -1,6 +1,7 @@
import { getTextContent } from '@web/parse5-utils';
import { expect } from 'chai';
import { parse, serialize } from 'parse5';
+import { html } from '../../utils.js';
import { injectBundles, createLoadScript } from '../../../src/output/injectBundles.js';
@@ -37,17 +38,14 @@ describe('createLoadScript()', () => {
describe('injectBundles()', () => {
it('can inject a single bundle', () => {
- const document = parse(
- [
- //
- '',
- '',
- '',
- 'Hello world ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+ Hello world
+
+
+ `);
injectBundles(document, [
{
@@ -61,32 +59,29 @@ describe('injectBundles()', () => {
],
},
]);
- const expected = [
- //
- '',
- '',
- '',
- 'Hello world ',
- '',
- '',
- '',
- ].join('');
- expect(serialize(document)).to.eql(expected);
+ const htmlWithBundles = serialize(document);
+
+ expect(html`${htmlWithBundles}`).to.eql(html`
+
+
+
+ Hello world
+
+
+
+ `);
});
it('can inject multiple bundles', () => {
- const document = parse(
- [
- //
- '',
- '',
- '',
- 'Hello world ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+ Hello world
+
+
+ `);
injectBundles(document, [
// @ts-ignore
@@ -112,18 +107,18 @@ describe('injectBundles()', () => {
],
},
]);
- const expected = [
- //
- '',
- '',
- '',
- 'Hello world ',
- '',
- '',
- '',
- '',
- ].join('');
- expect(serialize(document)).to.eql(expected);
+ const htmlWithBundles = serialize(document);
+
+ expect(html`${htmlWithBundles}`).to.eql(html`
+
+
+
+ Hello world
+
+
+
+
+ `);
});
});
diff --git a/packages/rollup-plugin-html/test/src/output/injectedUpdatedAssetPaths.test.ts b/packages/rollup-plugin-html/test/src/output/injectedUpdatedAssetPaths.test.ts
index 85ae406fe..9e720b157 100644
--- a/packages/rollup-plugin-html/test/src/output/injectedUpdatedAssetPaths.test.ts
+++ b/packages/rollup-plugin-html/test/src/output/injectedUpdatedAssetPaths.test.ts
@@ -1,24 +1,25 @@
import { expect } from 'chai';
import path from 'path';
import { parse, serialize } from 'parse5';
+import { html } from '../../utils.js';
import { InputData } from '../../../src/input/InputData.js';
import { injectedUpdatedAssetPaths } from '../../../src/output/injectedUpdatedAssetPaths.js';
describe('injectedUpdatedAssetPaths()', () => {
it('injects updated asset paths', () => {
- const document = parse(
- [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -42,50 +43,50 @@ describe('injectedUpdatedAssetPaths()', () => {
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- '',
- ].join('');
-
- expect(serialize(document)).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('handles a picture tag using source tags with srcset', () => {
- const document = parse(
- [
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -109,29 +110,48 @@ describe('injectedUpdatedAssetPaths()', () => {
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ].join('\n');
- expect(serialize(document).replace(/ {4}/g, '\n')).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+
+ `);
});
it('handles video tag using source tags with src', () => {
- const document = parse(
- [
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -155,27 +175,32 @@ describe('injectedUpdatedAssetPaths()', () => {
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- '',
- ' ',
- ' ',
- ].join('\n');
- expect(serialize(document).replace(/ {4}/g, '\n')).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+ `);
});
it('handles virtual files', () => {
- const document = parse(
- [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -196,31 +221,34 @@ describe('injectedUpdatedAssetPaths()', () => {
rootDir: '/root/',
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join('');
-
- expect(serialize(document)).to.eql(expected);
+
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+ `);
});
it('handles HTML files in a sub directory', () => {
- const document = parse(
- [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -243,31 +271,33 @@ describe('injectedUpdatedAssetPaths()', () => {
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join('');
-
- expect(serialize(document)).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+ `);
});
it('handles virtual HTML files in a sub directory', () => {
- const document = parse(
- [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -289,31 +319,33 @@ describe('injectedUpdatedAssetPaths()', () => {
emittedAssets: { static: new Map(), hashed },
});
- const expected = [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join('');
-
- expect(serialize(document)).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+ `);
});
it('prefixes a publicpath', () => {
- const document = parse(
- [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join(''),
- );
+ const document = parse(html`
+
+
+
+
+
+
+
+
+
+ `);
const input: InputData = {
html: '',
@@ -337,16 +369,18 @@ describe('injectedUpdatedAssetPaths()', () => {
publicPath: './public/',
});
- const expected = [
- '',
- ' ',
- '',
- ' ',
- ' ',
- '',
- '',
- ].join('');
-
- expect(serialize(document)).to.eql(expected);
+ const result = serialize(document);
+
+ expect(html`${result}`).to.eql(html`
+
+
+
+
+
+
+
+
+
+ `);
});
});
diff --git a/packages/rollup-plugin-html/test/utils.ts b/packages/rollup-plugin-html/test/utils.ts
new file mode 100644
index 000000000..e34ab607b
--- /dev/null
+++ b/packages/rollup-plugin-html/test/utils.ts
@@ -0,0 +1,102 @@
+import synchronizedPrettier from '@prettier/sync';
+import fs from 'fs';
+import path from 'path';
+import * as prettier from 'prettier';
+import { OutputOptions, RollupBuild } from 'rollup';
+
+function collapseWhitespaceAll(str: string) {
+ return (
+ str &&
+ str.replace(/[ \n\r\t\f\xA0]+/g, spaces => {
+ return spaces === '\t' ? '\t' : spaces.replace(/(^|\xA0+)[^\xA0]+/g, '$1 ');
+ })
+ );
+}
+
+function format(str: string, parser: prettier.BuiltInParserName) {
+ return synchronizedPrettier.format(str, { parser, semi: true, singleQuote: true });
+}
+
+function merge(strings: TemplateStringsArray, ...values: string[]): string {
+ return strings.reduce((acc, str, i) => acc + str + (values[i] || ''), '');
+}
+
+const extnameToFormatter: Record string> = {
+ '.html': (str: string) => format(collapseWhitespaceAll(str), 'html'),
+ '.css': (str: string) => format(str, 'css'),
+ '.js': (str: string) => format(str, 'typescript'),
+ '.json': (str: string) => format(str, 'json'),
+ '.svg': (str: string) => format(collapseWhitespaceAll(str), 'html'),
+};
+
+function getFormatterFromFilename(name: string): undefined | ((str: string) => string) {
+ return extnameToFormatter[path.extname(name)];
+}
+
+export const html = (strings: TemplateStringsArray, ...values: string[]) =>
+ extnameToFormatter['.html'](merge(strings, ...values));
+
+export const css = (strings: TemplateStringsArray, ...values: string[]) =>
+ extnameToFormatter['.css'](merge(strings, ...values));
+
+export const js = (strings: TemplateStringsArray, ...values: string[]) =>
+ extnameToFormatter['.js'](merge(strings, ...values));
+
+export const svg = (strings: TemplateStringsArray, ...values: string[]) =>
+ extnameToFormatter['.svg'](merge(strings, ...values));
+
+export async function generateTestBundle(build: RollupBuild, outputConfig: OutputOptions) {
+ const { output } = await build.generate(outputConfig);
+ const chunks: Record = {};
+ const assets: Record = {};
+
+ for (const file of output) {
+ const filename = file.fileName;
+ const formatter = getFormatterFromFilename(filename);
+ if (file.type === 'chunk') {
+ chunks[filename] = formatter ? formatter(file.code) : file.code;
+ } else if (file.type === 'asset') {
+ let code = file.source;
+ if (typeof code !== 'string' && filename.endsWith('.css')) {
+ code = Buffer.from(code).toString('utf8');
+ }
+ if (typeof code === 'string' && formatter) {
+ code = formatter(code);
+ }
+ assets[filename] = code;
+ }
+ }
+
+ return { output, chunks, assets };
+}
+
+export function createApp(structure: Record) {
+ const timestamp = Date.now();
+ const rootDir = path.join(__dirname, `./.tmp/app-${timestamp}`);
+ if (!fs.existsSync(rootDir)) {
+ fs.mkdirSync(rootDir, { recursive: true });
+ }
+ Object.keys(structure).forEach(filePath => {
+ const fullPath = path.join(rootDir, filePath);
+ const dir = path.dirname(fullPath);
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+ if (!fs.existsSync(fullPath)) {
+ const content = structure[filePath];
+ const contentForWrite =
+ typeof content === 'object' && !(content instanceof Buffer)
+ ? JSON.stringify(content)
+ : content;
+ fs.writeFileSync(fullPath, contentForWrite);
+ }
+ });
+ return rootDir;
+}
+
+export function cleanApp() {
+ const tmpDir = path.join(__dirname, './.tmp');
+ if (fs.existsSync(tmpDir)) {
+ fs.rmSync(tmpDir, { recursive: true });
+ }
+}
diff --git a/packages/rollup-plugin-polyfills-loader/test/src/rollupPluginPolyfillsLoader.test.ts b/packages/rollup-plugin-polyfills-loader/test/src/rollupPluginPolyfillsLoader.test.ts
index 3460565fd..65e86d6b3 100644
--- a/packages/rollup-plugin-polyfills-loader/test/src/rollupPluginPolyfillsLoader.test.ts
+++ b/packages/rollup-plugin-polyfills-loader/test/src/rollupPluginPolyfillsLoader.test.ts
@@ -167,7 +167,7 @@ describe('rollup-plugin-polyfills-loader', function describe() {
await testSnapshot({
name: 'non-flattened',
- fileName: path.normalize(`non-flat/index.html`),
+ fileName: 'non-flat/index.html',
inputOptions,
outputOptions: defaultOutputOptions,
});
diff --git a/packages/storybook-builder/src/index.ts b/packages/storybook-builder/src/index.ts
index 99f4b1199..410e66d6d 100644
--- a/packages/storybook-builder/src/index.ts
+++ b/packages/storybook-builder/src/index.ts
@@ -164,7 +164,6 @@ export const build: WdsBuilder['build'] = async ({ startTime, options }) => {
rollupPluginHTML({
input: { html: await generateIframeHtml(options), name: 'iframe.html' },
extractAssets: true,
- bundleAssetsFromCss: true,
externalAssets: 'sb-common-assets/**',
}),
rollupPluginNodeResolve(),