diff --git a/README.md b/README.md index ca9f27f..3f0187c 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,10 @@ module.exports = { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader', options: { - name(file) { + name(resourcePath, resourceQuery) { + // `resourcePath` - `/absolute/path/to/file.js` + // `resourceQuery` - `?foo=bar` + if (process.env.NODE_ENV === 'development') { return '[path][name].[ext]'; } @@ -439,6 +442,13 @@ Default: `file.folder` The folder of the resource is in. +### `[query]` + +Type: `String` +Default: `file.query` + +The query of the resource, i.e. `?foo=bar`. + ### `[emoji]` Type: `String` @@ -619,6 +629,48 @@ Result: path/to/file.png?e43b20c069c4a01867c31e98cbce33c9 ``` +### CDN + +The following examples show how to use `file-loader` for CDN uses query params. + +**file.js** + +```js +import png from './directory/image.png?width=300&height=300'; +``` + +**webpack.config.js** + +```js +module.exports = { + output: { + publicPath: 'https://cdn.example.com/', + }, + module: { + rules: [ + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: 'file-loader', + options: { + name: '[path][name].[ext][query]', + }, + }, + ], + }, + ], + }, +}; +``` + +Result: + +```bash +# result +https://cdn.example.com/directory/image.png?width=300&height=300 +``` + ### Dynamic public path depending on environment variable at run time An application might want to configure different CDN hosts depending on an environment variable that is only available when running the application. This can be an advantage, as only one build of the application is necessary, which behaves differntly depending on environment variables of the deployment environment. Since file-loader is applied when compiling the application, and not when running it, the environment variable cannot be used in the file-loader configuration. A way around this is setting the `__webpack_public_path__` to the desired CDN host depending on the environment variable at the entrypoint of the application. The option `postTransformPublicPath` can be used to configure a custom path depending on a variable like `__webpack_public_path__`. @@ -626,7 +678,6 @@ An application might want to configure different CDN hosts depending on an envir **main.js** ```js -const namespace = process.env.NAMESPACE; const assetPrefixForNamespace = (namespace) => { switch (namespace) { case 'prod': @@ -641,6 +692,8 @@ const assetPrefixForNamespace = (namespace) => { return ''; } }; +const namespace = process.env.NAMESPACE; + __webpack_public_path__ = `${assetPrefixForNamespace(namespace)}/`; ``` diff --git a/package-lock.json b/package-lock.json index 5bb2aa5..e1098c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4604,9 +4604,9 @@ "dev": true }, "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, "end-of-stream": { "version": "1.4.4", @@ -9705,12 +9705,12 @@ "dev": true }, "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "requires": { "big.js": "^5.2.2", - "emojis-list": "^2.0.0", + "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, diff --git a/package.json b/package.json index 46d9dde..546279c 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "webpack": "^4.0.0 || ^5.0.0" }, "dependencies": { - "loader-utils": "^1.2.3", + "loader-utils": "^1.4.0", "schema-utils": "^2.5.0" }, "devDependencies": { diff --git a/test/__snapshots__/name-option.test.js.snap b/test/__snapshots__/name-option.test.js.snap index f9679db..1968f04 100644 --- a/test/__snapshots__/name-option.test.js.snap +++ b/test/__snapshots__/name-option.test.js.snap @@ -1,14 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`"name" option should work for CDN support query params: errors 1`] = `Array []`; + +exports[`"name" option should work for CDN support query params: result 1`] = `"https://cdn.example.com/nested/file.png?foo=bar"`; + +exports[`"name" option should work for CDN support query params: warnings 1`] = `Array []`; + exports[`"name" option should work with "Function" value: errors 1`] = `Array []`; -exports[`"name" option should work with "Function" value: result 1`] = `"9c87cbf3ba33126ffd25ae7f2f6bbafb.function.png"`; +exports[`"name" option should work with "Function" value: result 1`] = `"9c87cbf3ba33126ffd25ae7f2f6bbafb.function.png?foo=bar"`; exports[`"name" option should work with "Function" value: warnings 1`] = `Array []`; exports[`"name" option should work with "String" value: errors 1`] = `Array []`; -exports[`"name" option should work with "String" value: result 1`] = `"9c87cbf3ba33126ffd25ae7f2f6bbafb.string.png"`; +exports[`"name" option should work with "String" value: result 1`] = `"9c87cbf3ba33126ffd25ae7f2f6bbafb.string.png?foo=bar"`; exports[`"name" option should work with "String" value: warnings 1`] = `Array []`; diff --git a/test/fixtures/cdn.js b/test/fixtures/cdn.js new file mode 100644 index 0000000..2d24fca --- /dev/null +++ b/test/fixtures/cdn.js @@ -0,0 +1,6 @@ +/* eslint-disable */ +import png from './nested/file.png?foo=bar#hash'; + +__export__ = 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/fixtures/simple.js b/test/fixtures/simple.js index f1a0830..b867552 100644 --- a/test/fixtures/simple.js +++ b/test/fixtures/simple.js @@ -1,5 +1,5 @@ /* eslint-disable */ -import png from './file.png'; +import png from './file.png?foo=bar'; __export__ = png; diff --git a/test/name-option.test.js b/test/name-option.test.js index 1f46850..22ca42c 100644 --- a/test/name-option.test.js +++ b/test/name-option.test.js @@ -1,3 +1,5 @@ +import path from 'path'; + import { compile, execute, @@ -22,7 +24,7 @@ describe('"name" option', () => { it('should work with "String" value', async () => { const compiler = getCompiler('simple.js', { - name: '[hash].string.[ext]', + name: '[hash].string.[ext][query]', }); const stats = await compile(compiler); @@ -37,8 +39,11 @@ describe('"name" option', () => { it('should work with "Function" value', async () => { const compiler = getCompiler('simple.js', { - name() { - return '[hash].function.[ext]'; + name(resourcePath, resourceQuery) { + expect(resourcePath).toBeDefined(); + expect(resourceQuery).toBeDefined(); + + return '[hash].function.[ext][query]'; }, }); const stats = await compile(compiler); @@ -51,4 +56,30 @@ describe('"name" option', () => { ); expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot('errors'); }); + + it('should work for CDN support query params', async () => { + const compiler = getCompiler( + 'cdn.js', + { + name: '[path][name].[ext][query]', + }, + { + output: { + path: path.resolve(__dirname, './outputs'), + publicPath: 'https://cdn.example.com/', + filename: '[name].bundle.js', + chunkFilename: '[name].chunk.js', + }, + } + ); + const stats = await compile(compiler); + + expect( + execute(readAsset('main.bundle.js', compiler, stats)) + ).toMatchSnapshot('result'); + expect(normalizeErrors(stats.compilation.warnings)).toMatchSnapshot( + 'warnings' + ); + expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot('errors'); + }); });