Skip to content

Commit ff0f44c

Browse files
feat: implement the filter option for filtering some of sources (#255)
1 parent 1c24662 commit ff0f44c

File tree

6 files changed

+543
-204
lines changed

6 files changed

+543
-204
lines changed

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default function htmlLoader(content) {
2828
typeof options.attributes === 'undefined' ? true : options.attributes;
2929

3030
if (attributes) {
31-
plugins.push(sourcePlugin(options));
31+
plugins.push(sourcePlugin({ attributes, resourcePath: this.resourcePath }));
3232
}
3333

3434
const minimize =
@@ -37,7 +37,7 @@ export default function htmlLoader(content) {
3737
: options.minimize;
3838

3939
if (minimize) {
40-
plugins.push(minimizerPlugin(options));
40+
plugins.push(minimizerPlugin({ minimize }));
4141
}
4242

4343
const { html, messages, warnings, errors } = pluginRunner(plugins).process(

src/options.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@
1313
{
1414
"type": "object",
1515
"properties": {
16-
"root": {
17-
"type": "string"
18-
},
1916
"list": {
2017
"type": "array",
2118
"items": {
2219
"type": "string"
2320
}
21+
},
22+
"filter": {
23+
"instanceof": "Function"
24+
},
25+
"root": {
26+
"type": "string"
2427
}
2528
},
2629
"additionalProperties": false

src/plugins/source-plugin.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { parse } from 'url';
33
import { Parser } from 'htmlparser2';
44
import { isUrlRequest, urlToRequest } from 'loader-utils';
55

6+
import { getFilter } from '../utils';
7+
68
function isASCIIWhitespace(character) {
79
return (
810
// Horizontal tab
@@ -389,28 +391,31 @@ const defaultAttributes = [
389391

390392
export default (options) =>
391393
function process(html, result) {
392-
let tagsAndAttributes;
394+
let possibleAttributes;
395+
let maybeFilter;
393396
let root;
394397

395398
if (
396399
typeof options.attributes === 'undefined' ||
397400
options.attributes === true
398401
) {
399-
tagsAndAttributes = defaultAttributes;
402+
possibleAttributes = defaultAttributes;
400403
} else if (Array.isArray(options.attributes)) {
401-
tagsAndAttributes = options.attributes;
404+
possibleAttributes = options.attributes;
402405
} else {
403-
tagsAndAttributes = options.attributes.list || defaultAttributes;
406+
possibleAttributes = options.attributes.list || defaultAttributes;
407+
// eslint-disable-next-line no-undefined
408+
maybeFilter = options.attributes.filter || undefined;
404409
// eslint-disable-next-line no-undefined
405410
root = options.attributes.root ? options.attributes.root : undefined;
406411
}
407412

408413
const sources = [];
409414
const onOpenTagFilter = new RegExp(
410-
`^(${tagsAndAttributes.join('|')})$`,
415+
`^(${possibleAttributes.join('|')})$`,
411416
'i'
412417
);
413-
const filter = (value) => isUrlRequest(value, root);
418+
const filter = getFilter(maybeFilter, (value) => isUrlRequest(value, root));
414419
const parser = new Parser(
415420
{
416421
attributesMeta: {},
@@ -457,7 +462,7 @@ export default (options) =>
457462
sourceSet.forEach((sourceItem) => {
458463
const { source } = sourceItem;
459464

460-
if (!filter(source.value)) {
465+
if (!filter(attribute, source.value, options.resourcePath)) {
461466
return;
462467
}
463468

@@ -483,7 +488,7 @@ export default (options) =>
483488
return;
484489
}
485490

486-
if (!filter(source.value)) {
491+
if (!filter(attribute, source.value, options.resourcePath)) {
487492
return;
488493
}
489494

src/utils.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ export function pluginRunner(plugins) {
1919
};
2020
}
2121

22+
export function getFilter(filter, defaultFilter = null) {
23+
return (attribute, value, resourcePath) => {
24+
if (defaultFilter && !defaultFilter(value)) {
25+
return false;
26+
}
27+
28+
if (typeof filter === 'function') {
29+
return filter(attribute, value, resourcePath);
30+
}
31+
32+
return true;
33+
};
34+
}
35+
2236
export function isProductionMode(loaderContext) {
2337
return loaderContext.mode === 'production' || !loaderContext.mode;
2438
}

test/__snapshots__/attributes-option.test.js.snap

Lines changed: 476 additions & 185 deletions
Large diffs are not rendered by default.

test/attributes-option.test.js

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ describe("'attributes' option", () => {
8686
expect(getErrors(stats)).toMatchSnapshot('errors');
8787
});
8888

89+
it('should work with an empty "object" notations', async () => {
90+
const compiler = getCompiler('simple.js', {
91+
attributes: {},
92+
});
93+
const stats = await compile(compiler);
94+
95+
expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');
96+
expect(
97+
execute(readAsset('main.bundle.js', compiler, stats))
98+
).toMatchSnapshot('result');
99+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
100+
expect(getErrors(stats)).toMatchSnapshot('errors');
101+
});
102+
89103
it('should work with an "object" notations', async () => {
90104
const compiler = getCompiler('simple.js', {
91105
attributes: {
@@ -115,10 +129,8 @@ describe("'attributes' option", () => {
115129
expect(getErrors(stats)).toMatchSnapshot('errors');
116130
});
117131

118-
it('should work with an empty "object" notations', async () => {
119-
const compiler = getCompiler('simple.js', {
120-
attributes: {},
121-
});
132+
it('should work with an "object" notations and translate root-relative sources', async () => {
133+
const compiler = getCompiler('simple.js', { attributes: { root: '.' } });
122134
const stats = await compile(compiler);
123135

124136
expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');
@@ -129,8 +141,22 @@ describe("'attributes' option", () => {
129141
expect(getErrors(stats)).toMatchSnapshot('errors');
130142
});
131143

132-
it('should translate root-relative sources', async () => {
133-
const compiler = getCompiler('simple.js', { attributes: { root: '.' } });
144+
it('should work with an "object" notations and filter some sources', async () => {
145+
const compiler = getCompiler('simple.js', {
146+
attributes: {
147+
filter: (attribute, value, resourcePath) => {
148+
expect(typeof attribute).toBe('string');
149+
expect(typeof value).toBe('string');
150+
expect(typeof resourcePath).toBe('string');
151+
152+
if (value.includes('example')) {
153+
return false;
154+
}
155+
156+
return true;
157+
},
158+
},
159+
});
134160
const stats = await compile(compiler);
135161

136162
expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');

0 commit comments

Comments
 (0)