Skip to content

Commit e59324b

Browse files
authored
feat: add support for async functions to preprocessor option (#272)
1 parent d7cccfa commit e59324b

File tree

4 files changed

+155
-2
lines changed

4 files changed

+155
-2
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ Allows pre-processing of content before handling.
352352
<div>
353353
```
354354

355+
#### `Function`
356+
357+
You can set the `preprocessor` option as a `Function` instance.
358+
355359
**webpack.config.js**
356360

357361
```js
@@ -387,6 +391,45 @@ module.exports = {
387391
};
388392
```
389393

394+
You can also set the `preprocessor` option as an asynchronous function instance.
395+
396+
For example:
397+
398+
**webpack.config.js**
399+
400+
```js
401+
const Handlebars = require('handlebars');
402+
403+
module.exports = {
404+
module: {
405+
rules: [
406+
{
407+
test: /\.hbs$/i,
408+
loader: 'html-loader',
409+
options: {
410+
preprocessor: async (content, loaderContext) => {
411+
let result;
412+
413+
try {
414+
result = await Handlebars.compile(content)({
415+
firstname: 'Value',
416+
lastname: 'OtherValue',
417+
});
418+
} catch (error) {
419+
await loaderContext.emitError(error);
420+
421+
return content;
422+
}
423+
424+
return result;
425+
},
426+
},
427+
},
428+
],
429+
},
430+
};
431+
```
432+
390433
### `minimize`
391434

392435
Type: `Boolean|Object`

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313

1414
import schema from './options.json';
1515

16-
export default function htmlLoader(content) {
16+
export default async function htmlLoader(content) {
1717
const options = getOptions(this);
1818

1919
validateOptions(schema, options, {
@@ -23,7 +23,7 @@ export default function htmlLoader(content) {
2323

2424
if (options.preprocessor) {
2525
// eslint-disable-next-line no-param-reassign
26-
content = options.preprocessor(content, this);
26+
content = await options.preprocessor(content, this);
2727
}
2828

2929
const plugins = [];

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`'process' option should work with Async "preprocessor" Function option: errors 1`] = `Array []`;
4+
5+
exports[`'process' option should work with Async "preprocessor" Function option: module 1`] = `
6+
"// Imports
7+
var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\");
8+
var ___HTML_LOADER_IMPORT_0___ = require(\\"./image.png\\");
9+
// Module
10+
var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);
11+
var code = \\"<div>\\\\n <p>Alexander Krasnoyarov</p>\\\\n <img src=\\\\\\"\\" + ___HTML_LOADER_REPLACER_0___ + \\"\\\\\\" alt=\\\\\\"alt\\\\\\" />\\\\n<div>\\\\n\\";
12+
// Exports
13+
module.exports = code;"
14+
`;
15+
16+
exports[`'process' option should work with Async "preprocessor" Function option: result 1`] = `
17+
"<div>
18+
<p>Alexander Krasnoyarov</p>
19+
<img src=\\"/webpack/public/path/image.png\\" alt=\\"alt\\" />
20+
<div>
21+
"
22+
`;
23+
24+
exports[`'process' option should work with Async "preprocessor" Function option: warnings 1`] = `Array []`;
25+
326
exports[`'process' option should work with the "preprocessor" option #2: errors 1`] = `Array []`;
427
528
exports[`'process' option should work with the "preprocessor" option #2: module 1`] = `
@@ -44,3 +67,25 @@ exports[`'process' option should work with the "preprocessor" option: result 1`]
4467
`;
4568
4669
exports[`'process' option should work with the "preprocessor" option: warnings 1`] = `Array []`;
70+
71+
exports[`'process' option should work with the Async "preprocessor" Function option #2: errors 1`] = `Array []`;
72+
73+
exports[`'process' option should work with the Async "preprocessor" Function option #2: module 1`] = `
74+
"// Imports
75+
var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\");
76+
var ___HTML_LOADER_IMPORT_0___ = require(\\"./image.png.webp\\");
77+
var ___HTML_LOADER_IMPORT_1___ = require(\\"./image.png\\");
78+
// Module
79+
var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);
80+
var ___HTML_LOADER_REPLACER_1___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_1___);
81+
var code = \\"<picture><source type=\\\\\\"image/webp\\\\\\" srcset=\\\\\\"\\" + ___HTML_LOADER_REPLACER_0___ + \\"\\\\\\"><img src=\\\\\\"\\" + ___HTML_LOADER_REPLACER_1___ + \\"\\\\\\"></picture>\\\\n\\";
82+
// Exports
83+
module.exports = code;"
84+
`;
85+
86+
exports[`'process' option should work with the Async "preprocessor" Function option #2: result 1`] = `
87+
"<picture><source type=\\"image/webp\\" srcset=\\"/webpack/public/path/image.png.webp\\"><img src=\\"/webpack/public/path/image.png\\"></picture>
88+
"
89+
`;
90+
91+
exports[`'process' option should work with the Async "preprocessor" Function option #2: warnings 1`] = `Array []`;

test/preprocessor-option.test.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,40 @@ describe("'process' option", () => {
4747
expect(getErrors(stats)).toMatchSnapshot('errors');
4848
});
4949

50+
it('should work with Async "preprocessor" Function option', async () => {
51+
const compiler = getCompiler('preprocessor.hbs', {
52+
preprocessor: async (content, loaderContext) => {
53+
await expect(typeof content).toBe('string');
54+
await expect(loaderContext).toBeDefined();
55+
56+
let result;
57+
58+
try {
59+
result = await Handlebars.compile(content)({
60+
firstname: 'Alexander',
61+
lastname: 'Krasnoyarov',
62+
});
63+
} catch (error) {
64+
await loaderContext.emitError(error);
65+
66+
return content;
67+
}
68+
69+
return result;
70+
},
71+
});
72+
const stats = await compile(compiler);
73+
74+
expect(getModuleSource('./preprocessor.hbs', stats)).toMatchSnapshot(
75+
'module'
76+
);
77+
expect(
78+
execute(readAsset('main.bundle.js', compiler, stats))
79+
).toMatchSnapshot('result');
80+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
81+
expect(getErrors(stats)).toMatchSnapshot('errors');
82+
});
83+
5084
it('should work with the "preprocessor" option #2', async () => {
5185
const plugin = posthtmlWebp();
5286
const compiler = getCompiler('posthtml.html', {
@@ -71,6 +105,37 @@ describe("'process' option", () => {
71105
});
72106
const stats = await compile(compiler);
73107

108+
expect(getModuleSource('./posthtml.html', stats)).toMatchSnapshot('module');
109+
expect(
110+
execute(readAsset('main.bundle.js', compiler, stats))
111+
).toMatchSnapshot('result');
112+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
113+
expect(getErrors(stats)).toMatchSnapshot('errors');
114+
});
115+
it('should work with the Async "preprocessor" Function option #2', async () => {
116+
const plugin = posthtmlWebp();
117+
const compiler = getCompiler('posthtml.html', {
118+
preprocessor: async (content, loaderContext) => {
119+
await expect(typeof content).toBe('string');
120+
await expect(loaderContext).toBeDefined();
121+
122+
let result;
123+
124+
try {
125+
result = await posthtml()
126+
.use(plugin)
127+
.process(content, { sync: true });
128+
} catch (error) {
129+
loaderContext.emitError(error);
130+
131+
return content;
132+
}
133+
134+
return result.html;
135+
},
136+
});
137+
const stats = await compile(compiler);
138+
74139
expect(getModuleSource('./posthtml.html', stats)).toMatchSnapshot('module');
75140
expect(
76141
execute(readAsset('main.bundle.js', compiler, stats))

0 commit comments

Comments
 (0)