diff --git a/src/index.js b/src/index.js index af9eb78..23edabe 100644 --- a/src/index.js +++ b/src/index.js @@ -12,20 +12,15 @@ export default function loader(content) { const context = options.context || this.rootContext || (this.options && this.options.context); - let url = loaderUtils.interpolateName(this, options.name, { + const url = loaderUtils.interpolateName(this, options.name, { context, content, regExp: options.regExp, }); - let outputPath = ''; - - if (options.outputPath) { - // support functions as outputPath to generate them dynamically - outputPath = ( - typeof options.outputPath === 'function' ? options.outputPath(url) : options.outputPath - ); - } + let outputPath = ( + typeof options.outputPath === 'function' ? options.outputPath(url) : path.join(options.outputPath || '', url) + ); if (options.useRelativePath) { const filePath = this.resourcePath; @@ -41,19 +36,17 @@ export default function loader(content) { } else { outputPath = relativePath + url; } - - url = relativePath + url; - } else { - outputPath += url; } - let publicPath = `__webpack_public_path__ + ${JSON.stringify(url)}`; + let publicPath = null; if (options.publicPath !== undefined) { // support functions as publicPath to generate them dynamically publicPath = JSON.stringify( typeof options.publicPath === 'function' ? options.publicPath(url) : options.publicPath + url, ); + } else { + publicPath = `__webpack_public_path__ + ${JSON.stringify(outputPath)}`; } if (options.emitFile === undefined || options.emitFile) { diff --git a/test/fixtures/fixture-nested.js b/test/fixtures/fixture-nested.js new file mode 100644 index 0000000..bd8db2f --- /dev/null +++ b/test/fixtures/fixture-nested.js @@ -0,0 +1,4 @@ +/* eslint-disable */ +import png from './nested/file.png'; + +export default png; diff --git a/test/fixtures/nested/file.png b/test/fixtures/nested/file.png new file mode 100644 index 0000000..02d7a6b Binary files /dev/null and b/test/fixtures/nested/file.png differ diff --git a/test/options/__snapshots__/outputPath.test.js.snap b/test/options/__snapshots__/outputPath.test.js.snap index fe81dd6..23b27e8 100644 --- a/test/options/__snapshots__/outputPath.test.js.snap +++ b/test/options/__snapshots__/outputPath.test.js.snap @@ -3,25 +3,34 @@ exports[`Options outputPath {Function} 1`] = ` Object { "assets": Array [ - "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + "output_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], - "source": "module.exports = __webpack_public_path__ + \\"9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", + "source": "module.exports = __webpack_public_path__ + \\"output_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", +} +`; + +exports[`Options outputPath {Function} with \`options.name\` 1`] = ` +Object { + "assets": Array [ + "output_path_func/file.png", + ], + "source": "module.exports = __webpack_public_path__ + \\"output_path_func/file.png\\";", } `; exports[`Options outputPath {Function} with \`publicPath\` {Function} 1`] = ` Object { "assets": Array [ - "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + "output_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], - "source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", + "source": "module.exports = \\"public_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } `; exports[`Options outputPath {Function} with \`publicPath\` {String} 1`] = ` Object { "assets": Array [ - "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + "output_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], "source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } @@ -32,7 +41,16 @@ Object { "assets": Array [ "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], - "source": "module.exports = __webpack_public_path__ + \\"9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", + "source": "module.exports = __webpack_public_path__ + \\"output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", +} +`; + +exports[`Options outputPath {String} with \`options.name\` 1`] = ` +Object { + "assets": Array [ + "output_path/file.png", + ], + "source": "module.exports = __webpack_public_path__ + \\"output_path/file.png\\";", } `; @@ -41,7 +59,7 @@ Object { "assets": Array [ "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], - "source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", + "source": "module.exports = \\"public_path_func/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } `; @@ -53,3 +71,21 @@ Object { "source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } `; + +exports[`Options outputPath {String} with \`publicPath\` {String} without trailing slash 1`] = ` +Object { + "assets": Array [ + "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + ], + "source": "module.exports = \\"public_path9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", +} +`; + +exports[`Options outputPath {String} without trailing slash 1`] = ` +Object { + "assets": Array [ + "output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + ], + "source": "module.exports = __webpack_public_path__ + \\"output_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", +} +`; diff --git a/test/options/__snapshots__/publicPath.test.js.snap b/test/options/__snapshots__/publicPath.test.js.snap index d4fce73..55bbb1a 100644 --- a/test/options/__snapshots__/publicPath.test.js.snap +++ b/test/options/__snapshots__/publicPath.test.js.snap @@ -17,3 +17,12 @@ Object { "source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } `; + +exports[`Options publicPath {String} without trailing slash 1`] = ` +Object { + "assets": Array [ + "9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + ], + "source": "module.exports = \\"public_path9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", +} +`; diff --git a/test/options/__snapshots__/useRelativePath.test.js.snap b/test/options/__snapshots__/useRelativePath.test.js.snap index bd70c4f..afc3e3d 100644 --- a/test/options/__snapshots__/useRelativePath.test.js.snap +++ b/test/options/__snapshots__/useRelativePath.test.js.snap @@ -21,9 +21,9 @@ Object { exports[`Options useRelativePath \`true\` with absolute \`context\` 1`] = ` Object { "assets": Array [ - "../file-loader/test/fixtures/nested/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", + "file-loader/test/fixtures/nested/9c87cbf3ba33126ffd25ae7f2f6bbafb.png", ], - "source": "module.exports = __webpack_public_path__ + \\"../file-loader/test/fixtures/nested/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", + "source": "module.exports = __webpack_public_path__ + \\"file-loader/test/fixtures/nested/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";", } `; diff --git a/test/options/outputPath.test.js b/test/options/outputPath.test.js index 4d3db82..01602a2 100644 --- a/test/options/outputPath.test.js +++ b/test/options/outputPath.test.js @@ -21,13 +21,65 @@ describe('Options', () => { expect({ assets, source }).toMatchSnapshot(); }); + test('{String} without trailing slash', async () => { + const config = { + loader: { + test: /(png|jpg|svg)/, + options: { + outputPath: 'output_path', + }, + }, + }; + + const stats = await webpack('fixture.js', config); + const { assets, source } = stats.toJson().modules[1]; + + expect({ assets, source }).toMatchSnapshot(); + }); + + test('{String} with `options.name`', async () => { + const config = { + loader: { + test: /(png|jpg|svg)/, + options: { + name: '[path][name].[ext]', + outputPath: 'output_path/', + }, + }, + }; + + const stats = await webpack('fixture.js', config); + const { assets, source } = stats.toJson().modules[1]; + + expect({ assets, source }).toMatchSnapshot(); + }); + test('{Function}', async () => { const config = { loader: { test: /(png|jpg|svg)/, options: { outputPath(url) { - return `output_path/${url}`; + return `output_path_func/${url}`; + }, + }, + }, + }; + + const stats = await webpack('fixture.js', config); + const { assets, source } = stats.toJson().modules[1]; + + expect({ assets, source }).toMatchSnapshot(); + }); + + test('{Function} with `options.name`', async () => { + const config = { + loader: { + test: /(png|jpg|svg)/, + options: { + name: '[name].[ext]', + outputPath(url) { + return `output_path_func/${url}`; }, }, }, @@ -56,6 +108,23 @@ describe('Options', () => { expect({ assets, source }).toMatchSnapshot(); }); + test('{String} with `publicPath` {String} without trailing slash', async () => { + const config = { + loader: { + test: /(png|jpg|svg)/, + options: { + outputPath: 'output_path', + publicPath: 'public_path', + }, + }, + }; + + const stats = await webpack('fixture.js', config); + const { assets, source } = stats.toJson().modules[1]; + + expect({ assets, source }).toMatchSnapshot(); + }); + test('{Function} with `publicPath` {String}', async () => { const config = { loader: { @@ -63,7 +132,7 @@ describe('Options', () => { options: { publicPath: 'public_path/', outputPath(url) { - return `output_path/${url}`; + return `output_path_func/${url}`; }, }, }, @@ -82,7 +151,7 @@ describe('Options', () => { options: { outputPath: 'output_path/', publicPath(url) { - return `public_path/${url}`; + return `public_path_func/${url}`; }, }, }, @@ -100,10 +169,10 @@ describe('Options', () => { test: /(png|jpg|svg)/, options: { outputPath(url) { - return `output_path/${url}`; + return `output_path_func/${url}`; }, publicPath(url) { - return `public_path/${url}`; + return `public_path_func/${url}`; }, }, }, diff --git a/test/options/publicPath.test.js b/test/options/publicPath.test.js index 8f574f3..e70d1f8 100644 --- a/test/options/publicPath.test.js +++ b/test/options/publicPath.test.js @@ -21,6 +21,22 @@ describe('Options', () => { expect({ assets, source }).toMatchSnapshot(); }); + test('{String} without trailing slash', async () => { + const config = { + loader: { + test: /(png|jpg|svg)/, + options: { + publicPath: 'public_path', + }, + }, + }; + + const stats = await webpack('fixture.js', config); + const { assets, source } = stats.toJson().modules[1]; + + expect({ assets, source }).toMatchSnapshot(); + }); + test('{Function}', async () => { const config = { loader: {