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

Commit c136f44

Browse files
fabbevilebottnawi
authored andcommitted
feat: postTransformPublicPath option (#334)
1 parent d441daa commit c136f44

File tree

5 files changed

+357
-0
lines changed

5 files changed

+357
-0
lines changed

Diff for: README.md

+94
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,32 @@ module.exports = {
269269
};
270270
```
271271

272+
### `postTransformPublicPath`
273+
274+
Type: `Function`
275+
Default: `undefined`
276+
277+
Specifies a custom function to post-process the generated public path. This can be used to prepend or append dynamic global variables that are only available at runtime, like `__webpack_public_path__`. This would not be possible with just `publicPath`, since it stringifies the values.
278+
279+
**webpack.config.js**
280+
281+
```js
282+
module.exports = {
283+
module: {
284+
rules: [
285+
{
286+
test: /\.(png|jpg|gif)$/,
287+
loader: 'file-loader',
288+
options: {
289+
publicPath: '/some/path/',
290+
postTransformPublicPath: (p) => `__webpack_public_path__ + ${p}`,
291+
},
292+
},
293+
],
294+
},
295+
};
296+
```
297+
272298
### `context`
273299

274300
Type: `String`
@@ -577,6 +603,74 @@ Result:
577603
path/to/file.png?e43b20c069c4a01867c31e98cbce33c9
578604
```
579605

606+
### Dynamic public path depending on environment variable at run time
607+
608+
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__`.
609+
610+
**main.js**
611+
612+
```js
613+
const namespace = process.env.NAMESPACE;
614+
const assetPrefixForNamespace = (namespace) => {
615+
switch (namespace) {
616+
case 'prod':
617+
return 'https://cache.myserver.net/web';
618+
case 'uat':
619+
return 'https://cache-uat.myserver.net/web';
620+
case 'st':
621+
return 'https://cache-st.myserver.net/web';
622+
case 'dev':
623+
return 'https://cache-dev.myserver.net/web';
624+
default:
625+
return '';
626+
}
627+
};
628+
__webpack_public_path__ = `${assetPrefixForNamespace(namespace)}/`;
629+
```
630+
631+
**file.js**
632+
633+
```js
634+
import png from './image.png';
635+
```
636+
637+
**webpack.config.js**
638+
639+
```js
640+
module.exports = {
641+
module: {
642+
rules: [
643+
{
644+
test: /\.(png|jpg|gif)$/,
645+
loader: 'file-loader',
646+
options: {
647+
context: '',
648+
emitFile: true,
649+
name: '[name].[hash].[ext]',
650+
publicPath: 'static/assets/',
651+
postTransformPublicPath: (p) => `__webpack_public_path__ + ${p}`,
652+
outputPath: 'static/assets/',
653+
},
654+
},
655+
],
656+
},
657+
};
658+
```
659+
660+
Result when run with `NAMESPACE=prod` env variable:
661+
662+
```bash
663+
# result
664+
https://cache.myserver.net/web/static/assets/image.somehash.png
665+
```
666+
667+
Result when run with `NAMESPACE=dev` env variable:
668+
669+
```bash
670+
# result
671+
https://cache-dev.myserver.net/web/static/assets/image.somehash.png
672+
```
673+
580674
## Contributing
581675

582676
Please take a moment to read our contributing guidelines if you haven't yet done so.

Diff for: src/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ export default function loader(content) {
4747
publicPath = JSON.stringify(publicPath);
4848
}
4949

50+
if (options.postTransformPublicPath) {
51+
publicPath = options.postTransformPublicPath(publicPath);
52+
}
53+
5054
if (typeof options.emitFile === 'undefined' || options.emitFile) {
5155
this.emitFile(outputPath, content);
5256
}

Diff for: src/options.json

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
}
3535
]
3636
},
37+
"postTransformPublicPath": {
38+
"description": "A custom transformation function for post-processing the publicPath (https://github.com/webpack-contrib/file-loader#posttransformpublicpath).",
39+
"instanceof": "Function"
40+
},
3741
"context": {
3842
"description": "A custom file context (https://github.com/webpack-contrib/file-loader#context).",
3943
"type": "string"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`when applied with \`postTransformPublicPath\` option matches snapshot for appending to input parameter value 1`] = `
4+
Object {
5+
"assets": Array [
6+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
7+
],
8+
"source": "module.exports = __webpack_public_path__ + \\"9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\" + \\"/test\\";",
9+
}
10+
`;
11+
12+
exports[`when applied with \`postTransformPublicPath\` option matches snapshot for returned input parameter value without modification 1`] = `
13+
Object {
14+
"assets": Array [
15+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
16+
],
17+
"source": "module.exports = __webpack_public_path__ + \\"9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
18+
}
19+
`;
20+
21+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{Function}\` value matches snapshot for appending to input parameter value 1`] = `
22+
Object {
23+
"assets": Array [
24+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
25+
],
26+
"source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\" + \\"?test=test\\";",
27+
}
28+
`;
29+
30+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{Function}\` value matches snapshot for prefixing with __webpack_public_path__ 1`] = `
31+
Object {
32+
"assets": Array [
33+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
34+
],
35+
"source": "module.exports = __webpack_public_path__ + \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
36+
}
37+
`;
38+
39+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{Function}\` value matches snapshot for prefixing with string 1`] = `
40+
Object {
41+
"assets": Array [
42+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
43+
],
44+
"source": "module.exports = \\"path_prefix/\\" + \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
45+
}
46+
`;
47+
48+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{Function}\` value matches snapshot for returned input parameter value without modification 1`] = `
49+
Object {
50+
"assets": Array [
51+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
52+
],
53+
"source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
54+
}
55+
`;
56+
57+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{String}\` value matches snapshot for appending to input parameter value 1`] = `
58+
Object {
59+
"assets": Array [
60+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
61+
],
62+
"source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\" + \\"?test=test\\";",
63+
}
64+
`;
65+
66+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{String}\` value matches snapshot for prefixing with __webpack_public_path__ 1`] = `
67+
Object {
68+
"assets": Array [
69+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
70+
],
71+
"source": "module.exports = __webpack_public_path__ + \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
72+
}
73+
`;
74+
75+
exports[`when applied with \`publicPath\` and \`postTransformPublicPath\` option \`{String}\` value matches snapshot for returned input parameter value without modification 1`] = `
76+
Object {
77+
"assets": Array [
78+
"9c87cbf3ba33126ffd25ae7f2f6bbafb.png",
79+
],
80+
"source": "module.exports = \\"public_path/9c87cbf3ba33126ffd25ae7f2f6bbafb.png\\";",
81+
}
82+
`;

Diff for: test/postTransformPublicPath-option.test.js

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import webpack from './helpers/compiler';
2+
3+
describe('when applied with `postTransformPublicPath` option', () => {
4+
it('matches snapshot for returned input parameter value without modification', async () => {
5+
const config = {
6+
loader: {
7+
test: /(png|jpg|svg)/,
8+
options: {
9+
postTransformPublicPath: (p) => p,
10+
},
11+
},
12+
};
13+
14+
const stats = await webpack('fixture.js', config);
15+
const [module] = stats.toJson().modules;
16+
const { assets, source } = module;
17+
18+
expect({ assets, source }).toMatchSnapshot();
19+
});
20+
21+
it('matches snapshot for appending to input parameter value', async () => {
22+
const config = {
23+
loader: {
24+
test: /(png|jpg|svg)/,
25+
options: {
26+
postTransformPublicPath: (p) => `${p} + "/test"`,
27+
},
28+
},
29+
};
30+
31+
const stats = await webpack('fixture.js', config);
32+
const [module] = stats.toJson().modules;
33+
const { assets, source } = module;
34+
35+
expect({ assets, source }).toMatchSnapshot();
36+
});
37+
});
38+
39+
describe('when applied with `publicPath` and `postTransformPublicPath` option', () => {
40+
describe('`{String}` value', () => {
41+
it('matches snapshot for returned input parameter value without modification', async () => {
42+
const config = {
43+
loader: {
44+
test: /(png|jpg|svg)/,
45+
options: {
46+
publicPath: 'public_path/',
47+
postTransformPublicPath: (p) => p,
48+
},
49+
},
50+
};
51+
52+
const stats = await webpack('fixture.js', config);
53+
const [module] = stats.toJson().modules;
54+
const { assets, source } = module;
55+
56+
expect({ assets, source }).toMatchSnapshot();
57+
});
58+
59+
it('matches snapshot for appending to input parameter value', async () => {
60+
const config = {
61+
loader: {
62+
test: /(png|jpg|svg)/,
63+
options: {
64+
publicPath: 'public_path/',
65+
postTransformPublicPath: (p) => `${p} + "?test=test"`,
66+
},
67+
},
68+
};
69+
70+
const stats = await webpack('fixture.js', config);
71+
const [module] = stats.toJson().modules;
72+
const { assets, source } = module;
73+
74+
expect({ assets, source }).toMatchSnapshot();
75+
});
76+
77+
it('matches snapshot for prefixing with __webpack_public_path__', async () => {
78+
const config = {
79+
loader: {
80+
test: /(png|jpg|svg)/,
81+
options: {
82+
publicPath: 'public_path/',
83+
postTransformPublicPath: (p) => `__webpack_public_path__ + ${p}`,
84+
},
85+
},
86+
};
87+
88+
const stats = await webpack('fixture.js', config);
89+
const [module] = stats.toJson().modules;
90+
const { assets, source } = module;
91+
92+
expect({ assets, source }).toMatchSnapshot();
93+
});
94+
});
95+
96+
describe('`{Function}` value', () => {
97+
it('matches snapshot for returned input parameter value without modification', async () => {
98+
const config = {
99+
loader: {
100+
test: /(png|jpg|svg)/,
101+
options: {
102+
publicPath(url) {
103+
return `public_path/${url}`;
104+
},
105+
postTransformPublicPath: (p) => p,
106+
},
107+
},
108+
};
109+
110+
const stats = await webpack('fixture.js', config);
111+
const [module] = stats.toJson().modules;
112+
const { assets, source } = module;
113+
114+
expect({ assets, source }).toMatchSnapshot();
115+
});
116+
117+
it('matches snapshot for appending to input parameter value', async () => {
118+
const config = {
119+
loader: {
120+
test: /(png|jpg|svg)/,
121+
options: {
122+
publicPath(url) {
123+
return `public_path/${url}`;
124+
},
125+
postTransformPublicPath: (p) => `${p} + "?test=test"`,
126+
},
127+
},
128+
};
129+
130+
const stats = await webpack('fixture.js', config);
131+
const [module] = stats.toJson().modules;
132+
const { assets, source } = module;
133+
134+
expect({ assets, source }).toMatchSnapshot();
135+
});
136+
137+
it('matches snapshot for prefixing with string', async () => {
138+
const config = {
139+
loader: {
140+
test: /(png|jpg|svg)/,
141+
options: {
142+
publicPath: 'public_path/',
143+
postTransformPublicPath: (p) => `"path_prefix/" + ${p}`,
144+
},
145+
},
146+
};
147+
148+
const stats = await webpack('fixture.js', config);
149+
const [module] = stats.toJson().modules;
150+
const { assets, source } = module;
151+
152+
expect({ assets, source }).toMatchSnapshot();
153+
});
154+
155+
it('matches snapshot for prefixing with __webpack_public_path__', async () => {
156+
const config = {
157+
loader: {
158+
test: /(png|jpg|svg)/,
159+
options: {
160+
publicPath: 'public_path/',
161+
postTransformPublicPath: (p) => `__webpack_public_path__ + ${p}`,
162+
},
163+
},
164+
};
165+
166+
const stats = await webpack('fixture.js', config);
167+
const [module] = stats.toJson().modules;
168+
const { assets, source } = module;
169+
170+
expect({ assets, source }).toMatchSnapshot();
171+
});
172+
});
173+
});

0 commit comments

Comments
 (0)