From cda754b5619e8e5f31fb82b9fb23944137e1f8df Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Fri, 26 Jun 2020 17:54:17 +0300 Subject: [PATCH] feat: `name` option --- README.md | 71 ++++++++++++++++++- src/index.js | 12 +++- src/options.json | 10 +++ .../validate-options.test.js.snap | 34 ++++++--- test/loader.test.js | 5 +- test/validate-options.test.js | 10 +++ 6 files changed, 127 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 78d69d1..5c8166b 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,10 @@ And run `webpack` via your preferred method. ## Options -| Name | Type | Default | Description | -| :-------------------: | :--------: | :---------: | :---------------------------------------------------- | -| **[`flags`](#flags)** | `{Number}` | `undefined` | Enables/Disables `url`/`image-set` functions handling | +| Name | Type | Default | Description | +| :-------------------: | :------------------: | :---------------------: | :----------------------------------------------------------- | +| **[`flags`](#flags)** | `{Number}` | `undefined` | Enables/Disables `url`/`image-set` functions handling | +| **[`name`](#name)** | `{String\|Function}` | `'[contenthash].[ext]'` | Specifies a custom filename template for the target file(s). | ### `flags` @@ -134,6 +135,70 @@ module.exports = { }; ``` +### `name` + +Type: `String|Function` +Default: `'[contenthash].[ext]'` + +Specifies a custom filename template for the target file(s). + +#### `String` + +**webpack.config.js** + +```js +module.exports = { + target: 'node', + node: { + __dirname: false, + }, + module: { + rules: [ + { + test: /\.node$/, + loader: 'node-loader', + options: { + name: '[path][name].[ext]', + }, + }, + ], + }, +}; +``` + +#### `Function` + +**webpack.config.js** + +```js +module.exports = { + target: 'node', + node: { + __dirname: false, + }, + module: { + rules: [ + { + test: /\.node$/, + loader: 'node-loader', + options: { + name(resourcePath, resourceQuery) { + // `resourcePath` - `/absolute/path/to/file.js` + // `resourceQuery` - `?foo=bar` + + if (process.env.NODE_ENV === 'development') { + return '[path][name].[ext]'; + } + + return '[contenthash].[ext]'; + }, + }, + }, + ], + }, +}; +``` + ## Contributing Please take a moment to read our contributing guidelines if you haven't yet done so. diff --git a/src/index.js b/src/index.js index 76e8d6d..fd6cfc7 100644 --- a/src/index.js +++ b/src/index.js @@ -2,9 +2,8 @@ MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ -import path from 'path'; -import { getOptions } from 'loader-utils'; +import { getOptions, interpolateName } from 'loader-utils'; import validateOptions from 'schema-utils'; import schema from './options.json'; @@ -17,7 +16,14 @@ export default function loader(content) { baseDataPath: 'options', }); - const name = path.basename(this.resourcePath); + const name = interpolateName( + this, + typeof options.name !== 'undefined' ? options.name : '[contenthash].[ext]', + { + context: this.rootContext, + content, + } + ); this.emitFile(name, content); diff --git a/src/options.json b/src/options.json index c28f605..b0b21ca 100644 --- a/src/options.json +++ b/src/options.json @@ -1,6 +1,16 @@ { "type": "object", "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "instanceof": "Function" + } + ] + }, "flags": { "type": "integer" } diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap index d86b94c..f70287f 100644 --- a/test/__snapshots__/validate-options.test.js.snap +++ b/test/__snapshots__/validate-options.test.js.snap @@ -15,50 +15,68 @@ exports[`validate options should throw an error on the "flags" option with "true - options.flags should be a integer." `; +exports[`validate options should throw an error on the "name" option with "false" value 1`] = ` +"Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. + - options.name should be one of these: + string | function + Details: + * options.name should be a string. + * options.name should be an instance of function." +`; + +exports[`validate options should throw an error on the "name" option with "true" value 1`] = ` +"Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. + - options.name should be one of these: + string | function + Details: + * options.name should be a string. + * options.name should be an instance of function." +`; + exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = ` "Invalid options object. Node Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'unknown'. These properties are valid: - object { flags? }" + object { name?, flags? }" `; diff --git a/test/loader.test.js b/test/loader.test.js index 25a110f..2749f3a 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -14,6 +14,7 @@ import { describe('loader', () => { it('should work', async () => { const compiler = getCompiler('simple.js', { + name: '[name].[ext]', flags: 1, }); const stats = await compile(compiler); @@ -29,7 +30,9 @@ describe('loader', () => { }); it('should throw an error on broken "node" addon', async () => { - const compiler = getCompiler('broken.js'); + const compiler = getCompiler('broken.js', { + name: '[name].[ext]', + }); const stats = await compile(compiler); expect(getModuleSource('./broken.node', stats)).toMatchSnapshot('module'); diff --git a/test/validate-options.test.js b/test/validate-options.test.js index 4118a76..f2995a2 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -2,12 +2,22 @@ * @jest-environment node */ +import path from 'path'; import os from 'os'; import { getCompiler, compile } from './helpers'; describe('validate options', () => { const tests = { + name: { + success: [ + '[name].[ext]', + (resourcePath) => { + return path.basename(resourcePath); + }, + ], + failure: [true, false], + }, flags: { success: [os.constants.dlopen.RTLD_NOW], failure: [true, false, 'test'],