Skip to content

Commit 3dd7d5c

Browse files
authored
Merge pull request #2671 from JulianCataldo/feat/support-external-assets-glob-patterns
feat(rollup-plugin-html): glob patterns exclusion for external assets
2 parents 2f04ee7 + 6207e41 commit 3dd7d5c

16 files changed

+164
-6
lines changed

.changeset/nervous-bugs-rhyme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@web/rollup-plugin-html': minor
3+
---
4+
5+
glob patterns exclusion for external assets

docs/docs/building/rollup-plugin-html.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ export interface RollupPluginHTMLOptions {
362362
transformHtml?: TransformHtmlFunction | TransformHtmlFunction[];
363363
/** Whether to extract and bundle assets referenced in HTML. Defaults to true. */
364364
extractAssets?: boolean;
365+
/** Whether to ignore assets referenced in HTML and CSS with glob patterns. */
366+
externalAssets?: string | string[];
365367
/** Define a full absolute url to your site (e.g. https://domain.com) */
366368
absoluteBaseUrl?: string;
367369
/** Whether to set full absolute urls for ['meta[property=og:image]', 'link[rel=canonical]', 'meta[property=og:url]'] or not. Requires a absoluteBaseUrl to be set. Default to true. */

package-lock.json

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/rollup-plugin-html/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@
4848
"glob": "^10.0.0",
4949
"html-minifier-terser": "^7.1.0",
5050
"lightningcss": "^1.24.0",
51-
"parse5": "^6.0.1"
51+
"parse5": "^6.0.1",
52+
"picomatch": "^2.2.2"
5253
},
5354
"devDependencies": {
5455
"@types/html-minifier-terser": "^7.0.0",
56+
"@types/picomatch": "^2.2.1",
5557
"rollup": "^4.4.0"
5658
}
5759
}

packages/rollup-plugin-html/src/RollupPluginHTMLOptions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface RollupPluginHTMLOptions {
2929
transformHtml?: TransformHtmlFunction | TransformHtmlFunction[];
3030
/** Whether to extract and bundle assets referenced in HTML. Defaults to true. */
3131
extractAssets?: boolean;
32+
/** Whether to ignore assets referenced in HTML and CSS with glob patterns. */
33+
externalAssets?: string | string[];
3234
/** Define a full absolute url to your site (e.g. https://domain.com) */
3335
absoluteBaseUrl?: string;
3436
/** Whether to set full absolute urls for ['meta[property=og:image]', 'link[rel=canonical]', 'meta[property=og:url]'] or not. Requires a absoluteBaseUrl to be set. Default to true. */

packages/rollup-plugin-html/src/assets/utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Document, Element } from 'parse5';
22
import path from 'path';
3+
import picomatch from 'picomatch';
34
import { findElements, getTagName, getAttribute } from '@web/parse5-utils';
45
import { createError } from '../utils.js';
56
import { serialize } from 'v8';
@@ -143,3 +144,11 @@ export function getSourcePaths(node: Element) {
143144
export function findAssets(document: Document) {
144145
return findElements(document, isAsset);
145146
}
147+
148+
// picomatch follows glob spec and requires "./" to be removed for the matcher to work
149+
// it is safe, because with or without it resolves to the same file
150+
// read more: https://github.com/micromatch/picomatch/issues/77
151+
const removeLeadingSlash = (str: string) => (str.startsWith('./') ? str.slice(2) : str);
152+
export function createAssetPicomatchMatcher(glob?: string | string[]) {
153+
return picomatch(glob || [], { format: removeLeadingSlash });
154+
}

packages/rollup-plugin-html/src/input/extract/extractAssets.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,28 @@ import {
77
getSourcePaths,
88
isHashedAsset,
99
resolveAssetFilePath,
10+
createAssetPicomatchMatcher,
1011
} from '../../assets/utils.js';
1112

1213
export interface ExtractAssetsParams {
1314
document: Document;
1415
htmlFilePath: string;
1516
htmlDir: string;
1617
rootDir: string;
18+
externalAssets?: string | string[];
1719
absolutePathPrefix?: string;
1820
}
1921

2022
export function extractAssets(params: ExtractAssetsParams): InputAsset[] {
2123
const assetNodes = findAssets(params.document);
2224
const allAssets: InputAsset[] = [];
25+
const isExternal = createAssetPicomatchMatcher(params.externalAssets);
2326

2427
for (const node of assetNodes) {
2528
const sourcePaths = getSourcePaths(node);
2629
for (const sourcePath of sourcePaths) {
30+
if (isExternal(sourcePath)) continue;
31+
2732
const filePath = resolveAssetFilePath(
2833
sourcePath,
2934
params.htmlDir,

packages/rollup-plugin-html/src/input/extract/extractModulesAndAssets.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ export interface ExtractParams {
88
htmlFilePath: string;
99
rootDir: string;
1010
extractAssets: boolean;
11+
externalAssets?: string | string[];
1112
absolutePathPrefix?: string;
1213
}
1314

1415
export function extractModulesAndAssets(params: ExtractParams) {
15-
const { html, htmlFilePath, rootDir, absolutePathPrefix } = params;
16+
const { html, htmlFilePath, rootDir, externalAssets, absolutePathPrefix } = params;
1617
const htmlDir = path.dirname(htmlFilePath);
1718
const document = parse(html);
1819

@@ -24,7 +25,14 @@ export function extractModulesAndAssets(params: ExtractParams) {
2425
absolutePathPrefix,
2526
});
2627
const assets = params.extractAssets
27-
? extractAssets({ document, htmlDir, htmlFilePath, rootDir, absolutePathPrefix })
28+
? extractAssets({
29+
document,
30+
htmlDir,
31+
htmlFilePath,
32+
rootDir,
33+
externalAssets,
34+
absolutePathPrefix,
35+
})
2836
: [];
2937

3038
// turn mutated AST back to a string

packages/rollup-plugin-html/src/input/getInputData.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,20 @@ export interface CreateInputDataParams {
3131
rootDir: string;
3232
filePath?: string;
3333
extractAssets: boolean;
34+
externalAssets?: string | string[];
3435
absolutePathPrefix?: string;
3536
}
3637

3738
function createInputData(params: CreateInputDataParams): InputData {
38-
const { name, html, rootDir, filePath, extractAssets, absolutePathPrefix } = params;
39+
const { name, html, rootDir, filePath, extractAssets, externalAssets, absolutePathPrefix } =
40+
params;
3941
const htmlFilePath = filePath ? filePath : path.resolve(rootDir, name);
4042
const result = extractModulesAndAssets({
4143
html,
4244
htmlFilePath,
4345
rootDir,
4446
extractAssets,
47+
externalAssets,
4548
absolutePathPrefix,
4649
});
4750

@@ -63,6 +66,7 @@ export function getInputData(
6366
rootDir = process.cwd(),
6467
flattenOutput,
6568
extractAssets = true,
69+
externalAssets,
6670
absolutePathPrefix,
6771
exclude: ignore,
6872
} = pluginOptions;
@@ -77,6 +81,7 @@ export function getInputData(
7781
html: input.html,
7882
rootDir,
7983
extractAssets,
84+
externalAssets,
8085
absolutePathPrefix,
8186
});
8287
result.push(data);
@@ -97,6 +102,7 @@ export function getInputData(
97102
rootDir,
98103
filePath,
99104
extractAssets,
105+
externalAssets,
100106
absolutePathPrefix,
101107
});
102108
result.push(data);

packages/rollup-plugin-html/src/output/emitAssets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { transform } from 'lightningcss';
44
import fs from 'fs';
55

66
import { InputAsset, InputData } from '../input/InputData';
7+
import { createAssetPicomatchMatcher } from '../assets/utils.js';
78
import { RollupPluginHTMLOptions, TransformAssetFunction } from '../RollupPluginHTMLOptions';
89

910
export interface EmittedAssets {
@@ -81,6 +82,7 @@ export async function emitAssets(
8182

8283
let ref: string;
8384
let basename = path.basename(asset.filePath);
85+
const isExternal = createAssetPicomatchMatcher(options.externalAssets);
8486
const emittedExternalAssets = new Map();
8587
if (asset.hashed) {
8688
if (basename.endsWith('.css') && options.bundleAssetsFromCss) {
@@ -95,7 +97,7 @@ export async function emitAssets(
9597
// https://www.w3.org/TR/html4/types.html#:~:text=ID%20and%20NAME%20tokens%20must,tokens%20defined%20by%20other%20attributes.
9698
const [filePath, idRef] = url.url.split('#');
9799

98-
if (shouldHandleAsset(filePath)) {
100+
if (shouldHandleAsset(filePath) && !isExternal(filePath)) {
99101
// Read the asset file, get the asset from the source location on the FS using asset.filePath
100102
const assetLocation = path.resolve(path.dirname(asset.filePath), filePath);
101103
const assetContent = fs.readFileSync(assetLocation);

0 commit comments

Comments
 (0)