Skip to content

Commit

Permalink
feat: add support for async functions to preprocessor option (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
EslamHiko committed Mar 31, 2020
1 parent d7cccfa commit e59324b
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 2 deletions.
43 changes: 43 additions & 0 deletions README.md
Expand Up @@ -352,6 +352,10 @@ Allows pre-processing of content before handling.
<div>
```

#### `Function`

You can set the `preprocessor` option as a `Function` instance.

**webpack.config.js**

```js
Expand Down Expand Up @@ -387,6 +391,45 @@ module.exports = {
};
```

You can also set the `preprocessor` option as an asynchronous function instance.

For example:

**webpack.config.js**

```js
const Handlebars = require('handlebars');

module.exports = {
module: {
rules: [
{
test: /\.hbs$/i,
loader: 'html-loader',
options: {
preprocessor: async (content, loaderContext) => {
let result;

try {
result = await Handlebars.compile(content)({
firstname: 'Value',
lastname: 'OtherValue',
});
} catch (error) {
await loaderContext.emitError(error);

return content;
}

return result;
},
},
},
],
},
};
```

### `minimize`

Type: `Boolean|Object`
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Expand Up @@ -13,7 +13,7 @@ import {

import schema from './options.json';

export default function htmlLoader(content) {
export default async function htmlLoader(content) {
const options = getOptions(this);

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

if (options.preprocessor) {
// eslint-disable-next-line no-param-reassign
content = options.preprocessor(content, this);
content = await options.preprocessor(content, this);
}

const plugins = [];
Expand Down
45 changes: 45 additions & 0 deletions test/__snapshots__/preprocessor-option.test.js.snap
@@ -1,5 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`'process' option should work with Async "preprocessor" Function option: errors 1`] = `Array []`;

exports[`'process' option should work with Async "preprocessor" Function option: module 1`] = `
"// Imports
var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\");
var ___HTML_LOADER_IMPORT_0___ = require(\\"./image.png\\");
// Module
var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);
var code = \\"<div>\\\\n <p>Alexander Krasnoyarov</p>\\\\n <img src=\\\\\\"\\" + ___HTML_LOADER_REPLACER_0___ + \\"\\\\\\" alt=\\\\\\"alt\\\\\\" />\\\\n<div>\\\\n\\";
// Exports
module.exports = code;"
`;
exports[`'process' option should work with Async "preprocessor" Function option: result 1`] = `
"<div>
<p>Alexander Krasnoyarov</p>
<img src=\\"/webpack/public/path/image.png\\" alt=\\"alt\\" />
<div>
"
`;
exports[`'process' option should work with Async "preprocessor" Function option: warnings 1`] = `Array []`;
exports[`'process' option should work with the "preprocessor" option #2: errors 1`] = `Array []`;
exports[`'process' option should work with the "preprocessor" option #2: module 1`] = `
Expand Down Expand Up @@ -44,3 +67,25 @@ exports[`'process' option should work with the "preprocessor" option: result 1`]
`;
exports[`'process' option should work with the "preprocessor" option: warnings 1`] = `Array []`;
exports[`'process' option should work with the Async "preprocessor" Function option #2: errors 1`] = `Array []`;
exports[`'process' option should work with the Async "preprocessor" Function option #2: module 1`] = `
"// Imports
var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\");
var ___HTML_LOADER_IMPORT_0___ = require(\\"./image.png.webp\\");
var ___HTML_LOADER_IMPORT_1___ = require(\\"./image.png\\");
// Module
var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);
var ___HTML_LOADER_REPLACER_1___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_1___);
var code = \\"<picture><source type=\\\\\\"image/webp\\\\\\" srcset=\\\\\\"\\" + ___HTML_LOADER_REPLACER_0___ + \\"\\\\\\"><img src=\\\\\\"\\" + ___HTML_LOADER_REPLACER_1___ + \\"\\\\\\"></picture>\\\\n\\";
// Exports
module.exports = code;"
`;
exports[`'process' option should work with the Async "preprocessor" Function option #2: result 1`] = `
"<picture><source type=\\"image/webp\\" srcset=\\"/webpack/public/path/image.png.webp\\"><img src=\\"/webpack/public/path/image.png\\"></picture>
"
`;
exports[`'process' option should work with the Async "preprocessor" Function option #2: warnings 1`] = `Array []`;
65 changes: 65 additions & 0 deletions test/preprocessor-option.test.js
Expand Up @@ -47,6 +47,40 @@ describe("'process' option", () => {
expect(getErrors(stats)).toMatchSnapshot('errors');
});

it('should work with Async "preprocessor" Function option', async () => {
const compiler = getCompiler('preprocessor.hbs', {
preprocessor: async (content, loaderContext) => {
await expect(typeof content).toBe('string');
await expect(loaderContext).toBeDefined();

let result;

try {
result = await Handlebars.compile(content)({
firstname: 'Alexander',
lastname: 'Krasnoyarov',
});
} catch (error) {
await loaderContext.emitError(error);

return content;
}

return result;
},
});
const stats = await compile(compiler);

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

it('should work with the "preprocessor" option #2', async () => {
const plugin = posthtmlWebp();
const compiler = getCompiler('posthtml.html', {
Expand All @@ -71,6 +105,37 @@ describe("'process' option", () => {
});
const stats = await compile(compiler);

expect(getModuleSource('./posthtml.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('should work with the Async "preprocessor" Function option #2', async () => {
const plugin = posthtmlWebp();
const compiler = getCompiler('posthtml.html', {
preprocessor: async (content, loaderContext) => {
await expect(typeof content).toBe('string');
await expect(loaderContext).toBeDefined();

let result;

try {
result = await posthtml()
.use(plugin)
.process(content, { sync: true });
} catch (error) {
loaderContext.emitError(error);

return content;
}

return result.html;
},
});
const stats = await compile(compiler);

expect(getModuleSource('./posthtml.html', stats)).toMatchSnapshot('module');
expect(
execute(readAsset('main.bundle.js', compiler, stats))
Expand Down

0 comments on commit e59324b

Please sign in to comment.