Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ the loader changes a module from code to a result.
Another way to view `val-loader`, is that it allows a user a way to make their
own custom loader logic, without having to write a custom loader.

The target module is called with two arguments: `(options, loaderContext)`

- `options`: The loader options (for instance provided in the webpack config. See the [example](#examples) below).
- `loaderContext`: [The loader context](https://webpack.js.org/api/loaders/#the-loader-context).

## Getting Started

To begin, you'll need to install `val-loader`:
Expand All @@ -34,7 +39,7 @@ Then add the loader to your `webpack` config. For example:
**target-file.js**

```js
module.exports = () => {
module.exports = (options, loaderContext) => {
return { code: 'module.exports = 42;' };
};
```
Expand Down Expand Up @@ -104,6 +109,8 @@ Default: `[]`
An array of absolute, native paths to file dependencies that should be watched
by webpack for changes.

Dependencies can also be added using [`loaderContext.addDependency(file: string)`](https://webpack.js.org/api/loaders/#thisadddependency).

### `contextDependencies`

Type: `Array[String]`
Expand All @@ -112,6 +119,8 @@ Default: `[]`
An array of absolute, native paths to directory dependencies that should be
watched by webpack for changes.

Context dependencies can also be added using [`loaderContext.addContextDependency(directory: string)`](https://webpack.js.org/api/loaders/#thisaddcontextdependency).

### `cacheable`

Type: `Boolean`
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default function loader(content) {
let result;

try {
result = func(options);
result = func(options, this);
} catch (error) {
throw new Error(`Module "${this.resource}" throw error: ${error}`);
}
Expand Down
45 changes: 45 additions & 0 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`loader should allow adding dependencies and contextDependencies via loader context: errors 1`] = `Array []`;

exports[`loader should allow adding dependencies and contextDependencies via loader context: result 1`] = `
"{
\\"content\\": \\"module.exports = \\\\\\"hello world\\\\\\";\\",
\\"map\\": null,
\\"meta\\": null,
\\"dependencies\\": [
\\"test/fixtures/dependencies-via-context.js\\",
\\"test/fixtures/args.js\\",
\\"test/fixtures/simple.js\\"
],
\\"contextDependencies\\": [
\\"test/fixtures\\"
]
}"
`;

exports[`loader should allow adding dependencies and contextDependencies via loader context: warnings 1`] = `Array []`;

exports[`loader should call the function with the loader options: errors 1`] = `Array []`;

exports[`loader should call the function with the loader options: result 1`] = `
Expand Down Expand Up @@ -101,6 +121,31 @@ exports[`loader should has module.parent: result 1`] = `

exports[`loader should has module.parent: warnings 1`] = `Array []`;

exports[`loader should keep dependencies if errors are emitted: errors 1`] = `
Array [
"ModuleError: Module Error (from /src/index.js):
(Emitted value instead of an instance of Error) Error: Calling the function failed",
]
`;

exports[`loader should keep dependencies if errors are emitted: result 1`] = `
"{
\\"content\\": \\"module.exports = \\\\\\"hello world\\\\\\";\\",
\\"map\\": null,
\\"meta\\": null,
\\"dependencies\\": [
\\"test/fixtures/error-emitted-with-dependencies.js\\",
\\"test/fixtures/args.js\\",
\\"test/fixtures/simple.js\\"
],
\\"contextDependencies\\": [
\\"test/fixtures\\"
]
}"
`;

exports[`loader should keep dependencies if errors are emitted: warnings 1`] = `Array []`;

exports[`loader should not swallow function call errors (async): errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from /src/index.js):
Expand Down
5 changes: 2 additions & 3 deletions test/fixtures/args.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
function args(...args) {
function args(options) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: Without this change, the following test fails: loader › should call the function with the loader options with:
TypeError: Converting circular structure to JSON.

I.e. the loaderContext can't matched with a snapshot as it can't be serialized to JSON.

return {
code: 'module.exports = "hello world";',
// We can't use rest parameters here because this code is not touched by babel
// We use the ast property because it is not validated
ast: args, // eslint-disable-line prefer-rest-params
ast: [options],
};
}

Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/dependencies-via-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function dependencies(options, loaderContext) {
loaderContext.addDependency(require.resolve('./args.js'));
loaderContext.addDependency(require.resolve('./simple.js'));
loaderContext.addContextDependency(__dirname);

return {
code: 'module.exports = "hello world";',
};
}

module.exports = dependencies;
14 changes: 14 additions & 0 deletions test/fixtures/error-emitted-with-dependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function errorEmittedWithDependencies(options, loaderOptions) {
loaderOptions.emitError(new Error('Calling the function failed'));

return {
dependencies: [
require.resolve('./args.js'),
require.resolve('./simple.js'),
],
contextDependencies: [__dirname],
code: 'module.exports = "hello world";',
};
}

module.exports = errorEmittedWithDependencies;
26 changes: 26 additions & 0 deletions test/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ describe('loader', () => {
expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot('errors');
});

it('should allow adding dependencies and contextDependencies via loader context', async () => {
const compiler = getCompiler('dependencies-via-context.js');
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 work the same if a promise is returned', async () => {
const compiler = getCompiler('promise.js');
const stats = await compile(compiler);
Expand Down Expand Up @@ -171,6 +184,19 @@ describe('loader', () => {
expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot('errors');
});

it('should keep dependencies if errors are emitted', async () => {
const compiler = getCompiler('error-emitted-with-dependencies.js');
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 report require() errors with a useful stacktrace', async () => {
const compiler = getCompiler('error-require.js');
const stats = await compile(compiler);
Expand Down