Skip to content

Commit

Permalink
feat: added the executableFile option (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
cap-Bernardito committed Feb 16, 2021
1 parent 0099efe commit b46090f
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 10 deletions.
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,71 @@ const answer = require("target-file");

And run `webpack` via your preferred method.

## Options

| Name | Type | Default | Description |
| :-------------------------------------: | :--------: | :---------: | :-------------------------------------------- |
| **[`executableFile`](#executableFile)** | `{String}` | `undefined` | Allows to specify path to the executable file |

### executableFile

Type: `String`
Default: `undefined`

Allows to specify path to the executable file

**data.json**

```json
{
"years": "10"
}
```

**executable-file.js**

```js
module.exports = function yearsInMs(options, loaderContext, content) {
const { years } = JSON.parse(content);
const value = years * 365 * 24 * 60 * 60 * 1000;

return {
cacheable: true,
code: "module.exports = " + value,
};
};
```

**webpack.config.js**

```js
module.exports = {
module: {
rules: [
{
test: /\.(json)$/i,
rules: [
{
loader: "val-loader",
options: {
executableFile: path.resolve(
__dirname,
"fixtures",
"executableFile.js"
),
},
},
],
},
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
};
```

## Return Object Properties

Targeted modules of this loader must export a `Function` that returns an object,
Expand Down
35 changes: 25 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,34 +69,49 @@ function processResult(loaderContext, result) {

export default function loader(content) {
const options = this.getOptions(schema);
const { executableFile } = options;
const callback = this.async();

let exports;

try {
exports = exec(content, this);
} catch (error) {
throw new Error(`Unable to execute "${this.resource}": ${error}`);
if (executableFile) {
try {
// eslint-disable-next-line global-require,import/no-dynamic-require
exports = require(executableFile);
} catch (error) {
callback(new Error(`Unable to require "${executableFile}": ${error}`));
return;
}
} else {
try {
exports = exec(content, this);
} catch (error) {
callback(new Error(`Unable to execute "${this.resource}": ${error}`));
return;
}
}

const func = exports && exports.default ? exports.default : exports;

if (typeof func !== "function") {
throw new Error(
`Module "${this.resource}" does not export a function as default`
callback(
new Error(
`Module "${this.resource}" does not export a function as default`
)
);
return;
}

let result;

try {
result = func(options, this);
result = func(options, this, content);
} catch (error) {
throw new Error(`Module "${this.resource}" throw error: ${error}`);
callback(new Error(`Module "${this.resource}" throw error: ${error}`));
return;
}

if (result && typeof result.then === "function") {
const callback = this.async();

result
.then((res) => processResult(this, res))
.catch((error) => {
Expand Down
28 changes: 28 additions & 0 deletions test/__snapshots__/executableFile.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`executableFile option should emit error: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Unable to require \\"/test/fixtures/error-require.js\\": Error: This is a typical require() error",
"ChunkRenderError: Cannot read property 'get' of undefined",
]
`;

exports[`executableFile option should emit error: warnings 1`] = `Array []`;

exports[`executableFile option should work: errors 1`] = `Array []`;

exports[`executableFile option should work: result 1`] = `
"{
\\"content\\": \\"module.exports = 315360000000\\",
\\"map\\": null,
\\"meta\\": null,
\\"dependencies\\": [
\\"test/fixtures/data.json\\"
],
\\"contextDependencies\\": [],
\\"buildDependencies\\": []
}"
`;

exports[`executableFile option should work: warnings 1`] = `Array []`;
90 changes: 90 additions & 0 deletions test/executableFile.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import path from "path";

import { getCompiler, compile, readAsset, normalizeErrors } from "./helpers";

describe("executableFile option", () => {
it("should work", async () => {
const compiler = getCompiler(
"executableFileEntry.js",
{},
{
module: {
rules: [
{
test: /\.(json)$/i,
rules: [
{
loader: require.resolve("./helpers/helperLoader.js"),
},
{
loader: require.resolve("../src"),
options: {
executableFile: path.resolve(
__dirname,
"fixtures",
"executableFile.js"
),
},
},
],
},
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
}
);
const stats = await compile(compiler);

expect(readAsset("val-loader.js", compiler, stats)).toMatchSnapshot(
"result"
);
expect(normalizeErrors(stats.compilation.warnings)).toMatchSnapshot(
"warnings"
);
expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot("errors");
});

it("should emit error", async () => {
const compiler = getCompiler(
"executableFileEntry.js",
{},
{
module: {
rules: [
{
test: /\.(json)$/i,
rules: [
{
loader: require.resolve("./helpers/helperLoader.js"),
},
{
loader: require.resolve("../src"),
options: {
executableFile: path.resolve(
__dirname,
"fixtures",
"error-require.js"
),
},
},
],
},
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
}
);
const stats = await compile(compiler);

expect(normalizeErrors(stats.compilation.warnings)).toMatchSnapshot(
"warnings"
);
expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot("errors");
});
});
3 changes: 3 additions & 0 deletions test/fixtures/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"years": "10"
}
9 changes: 9 additions & 0 deletions test/fixtures/executableFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = function yearsInMs(options, loaderContext, content) {
const {years} = JSON.parse(content);
const value = years * 365 * 24 * 60 * 60 * 1000;

return {
cacheable: true,
code: "module.exports = " + value,
};
};
3 changes: 3 additions & 0 deletions test/fixtures/executableFileEntry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const data = require('./data.json');

module.exports = {data};

0 comments on commit b46090f

Please sign in to comment.