Skip to content

Commit 8c73761

Browse files
feat: preprocessor option (#263)
1 parent f2ce5b1 commit 8c73761

18 files changed

+441
-45
lines changed

README.md

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,66 @@ module.exports = {
5050

5151
## Options
5252

53-
| Name | Type | Default | Description |
54-
| :-----------------------------: | :------------------------: | :------------------------------------------: | :--------------------------------------- |
55-
| **[`attributes`](#attributes)** | `{Boolean\/Array\/Object}` | `true` | Enables/Disables attributes handling |
56-
| **[`root`](#root)** | `{String}` | `undefiend` | Allow to handle root-relative attributes |
57-
| **[`minimize`](#minimize)** | `{Boolean\|Object}` | `true` in production mode, otherwise `false` | Tell `html-loader` to minimize HTML |
58-
| **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
53+
| Name | Type | Default | Description |
54+
| :---------------------------------: | :------------------------: | :------------------------------------------: | :----------------------------------------------- |
55+
| **[`preprocessor`](#preprocessor)** | `{Function}` | `undefined` | Allows pre-processing of content before handling |
56+
| **[`attributes`](#attributes)** | `{Boolean\/Array\/Object}` | `true` | Enables/Disables attributes handling |
57+
| **[`root`](#root)** | `{String}` | `undefiend` | Allow to handle root-relative attributes |
58+
| **[`minimize`](#minimize)** | `{Boolean\|Object}` | `true` in production mode, otherwise `false` | Tell `html-loader` to minimize HTML |
59+
| **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
60+
61+
### `preprocessor`
62+
63+
Type: `Function`
64+
Default: `undefined`
65+
66+
Allows pre-processing of content before handling.
67+
68+
> ⚠ You should always return valid HTML
69+
70+
**file.hbs**
71+
72+
```hbs
73+
<div>
74+
<p>{{firstname}} {{lastname}}</p>
75+
<img src="image.png" alt="alt" />
76+
<div>
77+
```
78+
79+
**webpack.config.js**
80+
81+
```js
82+
const Handlebars = require('handlebars');
83+
84+
module.exports = {
85+
module: {
86+
rules: [
87+
{
88+
test: /\.hbs$/i,
89+
loader: 'html-loader',
90+
options: {
91+
preprocessor: (content, loaderContext) => {
92+
let result;
93+
94+
try {
95+
result = Handlebars.compile(content)({
96+
firstname: 'Value',
97+
lastname: 'OtherValue',
98+
});
99+
} catch (error) {
100+
loaderContext.emitError(error);
101+
102+
return content;
103+
}
104+
105+
return result;
106+
},
107+
},
108+
},
109+
],
110+
},
111+
};
112+
```
59113

60114
### `attributes`
61115

@@ -501,6 +555,99 @@ require('html-loader?root=.!./file.html');
501555
// => '<img src="http://cdn.example.com/49eba9f/a992ca.jpg">'
502556
```
503557

558+
### Templating
559+
560+
You can use any template system. Below is an example for [handlebars](https://handlebarsjs.com/).
561+
562+
**file.hbs**
563+
564+
```hbs
565+
<div>
566+
<p>{{firstname}} {{lastname}}</p>
567+
<img src="image.png" alt="alt" />
568+
<div>
569+
```
570+
571+
**webpack.config.js**
572+
573+
```js
574+
const Handlebars = require('handlebars');
575+
576+
module.exports = {
577+
module: {
578+
rules: [
579+
{
580+
test: /\.hbs$/i,
581+
loader: 'html-loader',
582+
options: {
583+
preprocessor: (content, loaderContext) => {
584+
let result;
585+
586+
try {
587+
result = Handlebars.compile(content)({
588+
firstname: 'Value',
589+
lastname: 'OtherValue',
590+
});
591+
} catch (error) {
592+
loaderContext.emitError(error);
593+
594+
return content;
595+
}
596+
597+
return result;
598+
},
599+
},
600+
},
601+
],
602+
},
603+
};
604+
```
605+
606+
### PostHTML
607+
608+
You can use [PostHTML](https://github.com/posthtml/posthtml) without any additional loaders.
609+
610+
**file.html**
611+
612+
```html
613+
<img src="image.jpg" />
614+
```
615+
616+
**webpack.config.js**
617+
618+
```js
619+
const posthtml = require('posthtml');
620+
const posthtmlWebp = require('posthtml-webp');
621+
622+
module.exports = {
623+
module: {
624+
rules: [
625+
{
626+
test: /\.hbs$/i,
627+
loader: 'html-loader',
628+
options: {
629+
preprocessor: () => {
630+
let result;
631+
632+
try {
633+
result = posthtml()
634+
.use(plugin)
635+
.process(content, { sync: true });
636+
} catch (error) {
637+
loaderContext.emitError(error);
638+
639+
return content;
640+
}
641+
642+
return result.html;
643+
},
644+
},
645+
},
646+
],
647+
},
648+
};
649+
```
650+
504651
### Export into HTML files
505652

506653
A very common scenario is exporting the HTML into their own _.html_ file, to

package-lock.json

Lines changed: 92 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,15 @@
6767
"eslint-config-prettier": "^6.10.0",
6868
"eslint-plugin-import": "^2.20.1",
6969
"file-loader": "^6.0.0",
70+
"handlebars": "^4.7.3",
7071
"husky": "^4.2.3",
7172
"jest": "^25.1.0",
7273
"jest-junit": "^10.0.0",
7374
"lint-staged": "^10.0.8",
7475
"memfs": "^3.1.2",
7576
"npm-run-all": "^4.1.5",
77+
"posthtml": "^0.12.0",
78+
"posthtml-webp": "^1.5.0",
7679
"prettier": "^1.19.1",
7780
"standard-version": "^7.1.0",
7881
"webpack": "^4.42.0"

src/index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export default function htmlLoader(content) {
2121
baseDataPath: 'options',
2222
});
2323

24+
if (options.preprocessor) {
25+
// eslint-disable-next-line no-param-reassign
26+
content = options.preprocessor(content, this);
27+
}
28+
2429
const plugins = [];
2530

2631
const attributes =
@@ -70,5 +75,12 @@ export default function htmlLoader(content) {
7075
const moduleCode = getModuleCode(html, replaceableMessages, codeOptions);
7176
const exportCode = getExportCode(html, exportedMessages, codeOptions);
7277

73-
return `${importCode}${moduleCode}${exportCode}`;
78+
let code = `${importCode}${moduleCode}${exportCode}`;
79+
80+
if (options.process && options.process.post) {
81+
// eslint-disable-next-line no-param-reassign
82+
code = options.process.post(code, this);
83+
}
84+
85+
return code;
7486
}

src/options.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
22
"type": "object",
33
"properties": {
4+
"preprocessor": {
5+
"instanceof": "Function"
6+
},
47
"attributes": {
58
"anyOf": [
69
{ "type": "boolean" },

src/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,5 @@ export function getExportCode(html, exportedMessages, codeOptions) {
9494
return `// Exports\nexport default code;`;
9595
}
9696

97-
return `// Exports\nmodule.exports = code`;
97+
return `// Exports\nmodule.exports = code;`;
9898
}

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

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

0 commit comments

Comments
 (0)