Skip to content

Commit

Permalink
feat: ... syntax to extend default tag and attributes (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Aug 25, 2020
1 parent d021e42 commit f02bb48
Show file tree
Hide file tree
Showing 6 changed files with 519 additions and 65 deletions.
61 changes: 14 additions & 47 deletions README.md
Expand Up @@ -75,11 +75,17 @@ Supported tags and attributes:
- the `href` attribute of the `link` tag (only for stylesheets)
- the `data` attribute of the `object` tag
- the `src` attribute of the `script` tag
- the `href` attribute of the `script` tag
- the `xlink:href` attribute of the `script` tag
- the `src` attribute of the `source` tag
- the `srcset` attribute of the `source` tag
- the `src` attribute of the `track` tag
- the `poster` attribute of the `video` tag
- the `src` attribute of the `video` tag
- the `xlink:href` attribute of the `image` tag
- the `href` attribute of the `image` tag
- the `xlink:href` attribute of the `use` tag
- the `href` attribute of the `use` tag

#### `Boolean`

Expand Down Expand Up @@ -107,6 +113,7 @@ module.exports = {
#### `Object`

Allows you to specify which tags and attributes to process, filter them, filter urls and process sources starts with `/`.

For example:

**webpack.config.js**
Expand All @@ -121,16 +128,8 @@ module.exports = {
options: {
attributes: {
list: [
{
tag: 'img',
attribute: 'src',
type: 'src',
},
{
tag: 'img',
attribute: 'srcset',
type: 'srcset',
},
// All default supported tags and attributes
'...',
{
tag: 'img',
attribute: 'data-src',
Expand All @@ -141,26 +140,6 @@ module.exports = {
attribute: 'data-srcset',
type: 'srcset',
},
{
tag: 'link',
attribute: 'href',
type: 'src',
filter: (tag, attribute, attributes) => {
if (!/stylesheet/i.test(attributes.rel)) {
return false;
}

if (
attributes.type &&
attributes.type.trim().toLowerCase() !== 'text/css'
) {
return false;
}

return true;
},
},
// More attributes
],
urlFilter: (attribute, value, resourcePath) => {
// The `attribute` argument contains a name of the HTML attribute.
Expand All @@ -185,10 +164,12 @@ module.exports = {
#### `list`

Type: `Array`
Default: https://github.com/webpack-contrib/html-loader#attributes
Default: [supported tags and attributes](#attributes).

Allows to setup which tags and attributes to process and how, and the ability to filter some of them.

Using `...` syntax allows you to extend [default supported tags and attributes](#attributes).

For example:

**webpack.config.js**
Expand All @@ -203,22 +184,8 @@ module.exports = {
options: {
attributes: {
list: [
{
// Tag name
tag: 'img',
// Attribute name
attribute: 'src',
// Type of processing, can be `src` or `scrset`
type: 'src',
},
{
// Tag name
tag: 'img',
// Attribute name
attribute: 'srcset',
// Type of processing, can be `src` or `scrset`
type: 'srcset',
},
// All default supported tags and attributes
'...',
{
tag: 'img',
attribute: 'data-src',
Expand Down
41 changes: 24 additions & 17 deletions src/options.json
Expand Up @@ -2,25 +2,32 @@
"type": "object",
"definitions": {
"Attribute": {
"type": "object",
"properties": {
"tag": {
"type": "string",
"minLength": 1
},
"attribute": {
"type": "string",
"minLength": 1
},
"type": {
"enum": ["src", "srcset"]
"anyOf": [
{
"type": "object",
"properties": {
"tag": {
"type": "string",
"minLength": 1
},
"attribute": {
"type": "string",
"minLength": 1
},
"type": {
"enum": ["src", "srcset"]
},
"filter": {
"instanceof": "Function"
}
},
"required": ["attribute", "type"],
"additionalProperties": false
},
"filter": {
"instanceof": "Function"
{
"enum": ["..."]
}
},
"required": ["attribute", "type"],
"additionalProperties": false
]
},
"AttributeList": {
"type": "array",
Expand Down
38 changes: 37 additions & 1 deletion src/utils.js
Expand Up @@ -562,6 +562,33 @@ const defaultAttributes = [
},
];

function smartMergeSources(array, factory) {
if (typeof array === 'undefined') {
return factory();
}

const newArray = [];

for (let i = 0; i < array.length; i++) {
const item = array[i];

if (item === '...') {
const items = factory();

if (typeof items !== 'undefined') {
// eslint-disable-next-line no-shadow
for (const item of items) {
newArray.push(item);
}
}
} else if (typeof newArray !== 'undefined') {
newArray.push(item);
}
}

return newArray;
}

function getAttributesOption(rawOptions) {
if (typeof rawOptions.attributes === 'undefined') {
return { list: defaultAttributes };
Expand All @@ -571,7 +598,16 @@ function getAttributesOption(rawOptions) {
return rawOptions.attributes === true ? { list: defaultAttributes } : false;
}

return { ...{ list: defaultAttributes }, ...rawOptions.attributes };
const sources = smartMergeSources(
rawOptions.attributes.list,
() => defaultAttributes
);

return {
list: sources,
urlFilter: rawOptions.attributes.urlFilter,
root: rawOptions.attributes.root,
};
}

export function normalizeOptions(rawOptions, loaderContext) {
Expand Down
411 changes: 411 additions & 0 deletions test/__snapshots__/attributes-option.test.js.snap

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions test/attributes-option.test.js
Expand Up @@ -35,6 +35,29 @@ describe("'attributes' option", () => {
expect(getErrors(stats)).toMatchSnapshot('errors');
});

it('should work with "..." syntax', async () => {
const compiler = getCompiler('simple.js', {
attributes: {
list: [
'...',
{
tag: 'flag-icon',
attribute: 'src',
type: 'src',
},
],
},
});
const stats = await compile(compiler);

expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');
expect(
execute(readAsset('main.bundle.js', compiler, stats))
).toMatchSnapshot('result');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
expect(getErrors(stats)).toMatchSnapshot('errors');
});

it.skip('should handle the "include" tags', async () => {
const compiler = getCompiler('include.js', {
attributes: {
Expand Down
10 changes: 10 additions & 0 deletions test/validate-options.test.js
Expand Up @@ -47,6 +47,16 @@ describe('validate options', () => {
},
],
},
{
list: [
'...',
{
tag: 'img',
attribute: 'srcset',
type: 'srcset',
},
],
},
{ urlFilter: () => true },
{ root: '.' },
{
Expand Down

0 comments on commit f02bb48

Please sign in to comment.