Skip to content
This repository has been archived by the owner on Mar 17, 2021. It is now read-only.

feat: support the query template for the name option #366

Merged
merged 1 commit into from Feb 19, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 55 additions & 2 deletions README.md
Expand Up @@ -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]';
}
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -619,14 +629,55 @@ 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__`.

**main.js**

```js
const namespace = process.env.NAMESPACE;
const assetPrefixForNamespace = (namespace) => {
switch (namespace) {
case 'prod':
Expand All @@ -641,6 +692,8 @@ const assetPrefixForNamespace = (namespace) => {
return '';
}
};
const namespace = process.env.NAMESPACE;

__webpack_public_path__ = `${assetPrefixForNamespace(namespace)}/`;
```

Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -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": {
Expand Down
10 changes: 8 additions & 2 deletions 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 []`;

Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/cdn.js
@@ -0,0 +1,6 @@
/* eslint-disable */
import png from './nested/file.png?foo=bar#hash';

__export__ = png;

export default png;
Binary file added test/fixtures/nested/file.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/fixtures/simple.js
@@ -1,5 +1,5 @@
/* eslint-disable */
import png from './file.png';
import png from './file.png?foo=bar';

__export__ = png;

Expand Down
37 changes: 34 additions & 3 deletions test/name-option.test.js
@@ -1,3 +1,5 @@
import path from 'path';

import {
compile,
execute,
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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');
});
});