Skip to content

Commit 16c0f12

Browse files
committed
Updating images and fonts to use Webpack 5 Asset modules
1 parent 7a4794d commit 16c0f12

12 files changed

+458
-457
lines changed

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
# CHANGELOG
22

3+
## 1.0.0
4+
5+
* [DEPENDENCY UPGRADE] Webpack was upgraded from version 4 to 5.
6+
7+
* [BC BREAK] Image and font processing was changed from using `file-loader`
8+
(and optionally `url-loader` via `configureUrlLoader()`) to Webpack 5's
9+
new [Asset Modules](https://webpack.js.org/guides/asset-modules/).
10+
In practice, unless you have a highly-configured system, this should
11+
not cause significant changes. You will notice that smaller images
12+
and fonts (smaller than 8kb) will be "inlined" in CSS files instead
13+
of being extracted to independent files for performance. This is
14+
configurable - see the new `configureImageRule()` and `configureFontRule()`
15+
methods.
16+
17+
* [BC BREAK] The `configureUrlLoader()` method was removed. See
18+
`configureImageRule()` and `configureFontRule()` - specifically the
19+
`maxSize` option. The `url-loader` is no longer used.
20+
21+
* [BC BREAK] The `disableImagesLoader()` and `disableFontsLoader()` methods
22+
have been removed. See `configureImageRule()` and `configureFontRule()`
23+
for a new option to disable these.
24+
25+
* [BC BREAK] The `configureFilenames()` method no longer accepts paths
26+
for `images` or `fonts`. See `configureImageRule()` and `configureFontRule()`
27+
for how to configure these filenames. The `configureFilenames()` method
28+
*does* now accept an `assets` option, but out-of-the-box, this will not
29+
result in any filename changes. See `configureFilenames()` for more details.
30+
31+
* [BC BREAK] The `file-loader` package is no longer required by Encore. If
32+
you use `copyFiles()`, you will need to install it manually (you
33+
will receive a clear error about this).
34+
35+
336
## 0.33.0
437

538
* [disableCssExtraction()] Added boolean argument to `disableCssExtraction()`

index.js

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,30 +1299,6 @@ class Encore {
12991299
return this;
13001300
}
13011301

1302-
/**
1303-
* Call this if you wish to disable the default
1304-
* images loader.
1305-
*
1306-
* @returns {Encore}
1307-
*/
1308-
disableImagesLoader() {
1309-
webpackConfig.disableImagesLoader();
1310-
1311-
return this;
1312-
}
1313-
1314-
/**
1315-
* Call this if you wish to disable the default
1316-
* fonts loader.
1317-
*
1318-
* @returns {Encore}
1319-
*/
1320-
disableFontsLoader() {
1321-
webpackConfig.disableFontsLoader();
1322-
1323-
return this;
1324-
}
1325-
13261302
/**
13271303
* Call this if you don't want imported CSS to be extracted
13281304
* into a .css file. All your styles will then be injected
@@ -1377,8 +1353,7 @@ class Encore {
13771353
* Encore.configureFilenames({
13781354
* js: '[name].[contenthash].js',
13791355
* css: '[name].[contenthash].css',
1380-
* images: 'images/[name].[hash:8].[ext]',
1381-
* fonts: 'fonts/[name].[hash:8].[ext]'
1356+
* assets: 'assets/[name].[hash:8][ext]',
13821357
* });
13831358
* ```
13841359
*
@@ -1389,6 +1364,10 @@ class Encore {
13891364
* make sure that your "js" and "css" filenames contain
13901365
* "[contenthash]".
13911366
*
1367+
* The "assets" key is used for the output.assetModuleFilename option,
1368+
* which is overridden for both fonts and images. See configureImageRule()
1369+
* and configureFontRule() to control those filenames.
1370+
*
13921371
* @param {object} filenames
13931372
* @returns {Encore}
13941373
*/
@@ -1399,30 +1378,71 @@ class Encore {
13991378
}
14001379

14011380
/**
1402-
* Allows to configure the URL loader.
1381+
* Configure how images are loaded/processed under module.rules.
1382+
*
1383+
* https://webpack.js.org/guides/asset-modules/
14031384
*
1404-
* https://github.com/webpack-contrib/url-loader
1385+
* The most important things can be controlled by passing
1386+
* an options object to the first argument:
14051387
*
14061388
* ```
1407-
* Encore.configureUrlLoader({
1408-
* images: {
1409-
* limit: 8192,
1410-
* mimetype: 'image/png'
1411-
* },
1412-
* fonts: {
1413-
* limit: 4096
1414-
* }
1389+
* Encore.configureImageRule({
1390+
* // common values: asset, asset/resource, asset/inline
1391+
* // or javascript/auto to disable asset images (see next example)
1392+
* type: 'asset',
1393+
*
1394+
* // applicable when for "type: asset": files smaller than this
1395+
* // size will be "inlined" into CSS, larer files will be extracted
1396+
* // into independent files
1397+
* maxSize: 4 * 1024, // 4 kb
1398+
*
1399+
* // control the output filename of images
1400+
* filename: 'images/[name].[hash:8][ext]',
1401+
*
1402+
* // you can also fully disable the image rule if you want
1403+
* // to control things yourself
1404+
* enabled: true,
14151405
* });
14161406
* ```
14171407
*
1418-
* If a key (e.g. fonts) doesn't exists or contains a
1419-
* falsy value the file-loader will be used instead.
1408+
* If you need more control, you can also pass a callback to the
1409+
* 2nd argument. This will be passed the specific Rule object,
1410+
* which you can modify:
14201411
*
1421-
* @param {object} urlLoaderOptions
1422-
* @return {Encore}
1412+
* https://webpack.js.org/configuration/module/#rule
1413+
*
1414+
* ```
1415+
* Encore.configureImageRule({}, function(rule) {
1416+
* // if you set "type: 'javascript/auto'" in the first argument,
1417+
* // then you can now specify a loader manually
1418+
* // rule.loader = 'file-loader';
1419+
* // rule.options = { filename: 'images/[name].[hash:8][ext]' }
1420+
* });
1421+
* ```
1422+
*
1423+
* @param {object} options
1424+
* @param {string|object|function} ruleCallback
1425+
* @returns {Encore}
1426+
*/
1427+
configureImageRule(options = {}, ruleCallback = (rule) => {}) {
1428+
webpackConfig.configureImageRule(options, ruleCallback);
1429+
1430+
return this;
1431+
}
1432+
1433+
/**
1434+
* Configure how fonts are processed/loaded under module.rules.
1435+
*
1436+
* https://webpack.js.org/guides/asset-modules/
1437+
*
1438+
* See configureImageRule() for more details.
1439+
*
1440+
* @param {object} options
1441+
* @param {string|object|function} ruleCallback
1442+
* @returns {Encore}
14231443
*/
1424-
configureUrlLoader(urlLoaderOptions = {}) {
1425-
webpackConfig.configureUrlLoader(urlLoaderOptions);
1444+
configureFontRule(options = {}, ruleCallback = (rule) => {}) {
1445+
webpackConfig.configureFontRule(options, ruleCallback);
14261446

14271447
return this;
14281448
}
@@ -1597,9 +1617,10 @@ class Encore {
15971617
*
15981618
* @param {string} environment
15991619
* @param {object} options
1620+
* @param {boolean} enablePackageJsonCheck
16001621
* @returns {Encore}
16011622
*/
1602-
configureRuntimeEnvironment(environment, options = {}) {
1623+
configureRuntimeEnvironment(environment, options = {}, enablePackageJsonCheck = true) {
16031624
runtimeConfig = parseRuntime(
16041625
Object.assign(
16051626
{},
@@ -1609,7 +1630,7 @@ class Encore {
16091630
process.cwd()
16101631
);
16111632

1612-
webpackConfig = new WebpackConfig(runtimeConfig, true);
1633+
webpackConfig = new WebpackConfig(runtimeConfig, enablePackageJsonCheck);
16131634

16141635
return this;
16151636
}

lib/WebpackConfig.js

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,18 @@ class WebpackConfig {
9797
this.useSourceMaps = false;
9898
this.cleanupOutput = false;
9999
this.extractCss = true;
100-
this.useImagesLoader = true;
101-
this.useFontsLoader = true;
100+
this.imageRuleOptions = {
101+
type: 'asset',
102+
maxSize: null,
103+
filename: 'images/[name].[hash:8][ext]',
104+
enabled: true,
105+
};
106+
this.fontRuleOptions = {
107+
type: 'asset',
108+
maxSize: null,
109+
filename: 'fonts/[name].[hash:8][ext]',
110+
enabled: true,
111+
};
102112
this.usePostCssLoader = false;
103113
this.useLessLoader = false;
104114
this.useStylusLoader = false;
@@ -126,10 +136,6 @@ class WebpackConfig {
126136
this.preactOptions = {
127137
preactCompat: false
128138
};
129-
this.urlLoaderOptions = {
130-
images: false,
131-
fonts: false
132-
};
133139
this.babelOptions = {
134140
exclude: /(node_modules|bower_components)/,
135141
useBuiltIns: false,
@@ -146,6 +152,8 @@ class WebpackConfig {
146152
};
147153

148154
// Features/Loaders options callbacks
155+
this.imageRuleCallback = () => {};
156+
this.fontRuleCallback = () => {};
149157
this.postCssLoaderOptionsCallback = () => {};
150158
this.sassLoaderOptionsCallback = () => {};
151159
this.lessLoaderOptionsCallback = () => {};
@@ -813,14 +821,6 @@ class WebpackConfig {
813821
this.handlebarsConfigurationCallback = callback;
814822
}
815823

816-
disableImagesLoader() {
817-
this.useImagesLoader = false;
818-
}
819-
820-
disableFontsLoader() {
821-
this.useFontsLoader = false;
822-
}
823-
824824
disableCssExtraction(disabled = true) {
825825
this.extractCss = !disabled;
826826
}
@@ -831,30 +831,54 @@ class WebpackConfig {
831831
}
832832

833833
// Check allowed keys
834-
const validKeys = ['js', 'css', 'images', 'fonts'];
834+
const validKeys = ['js', 'css', 'assets'];
835835
for (const key of Object.keys(configuredFilenames)) {
836836
if (!validKeys.includes(key)) {
837-
throw new Error(`"${key}" is not a valid key for configureFilenames(). Valid keys: ${validKeys.join(', ')}.`);
837+
throw new Error(`"${key}" is not a valid key for configureFilenames(). Valid keys: ${validKeys.join(', ')}. Use configureImageRule() or configureFontRule() to control image or font filenames.`);
838838
}
839839
}
840840

841841
this.configuredFilenames = configuredFilenames;
842842
}
843843

844-
configureUrlLoader(urlLoaderOptions = {}) {
845-
if (typeof urlLoaderOptions !== 'object') {
846-
throw new Error('Argument 1 to configureUrlLoader() must be an object.');
844+
configureImageRule(options = {}, ruleCallback = () => {}) {
845+
for (const optionKey of Object.keys(options)) {
846+
if (!(optionKey in this.imageRuleOptions)) {
847+
throw new Error(`Invalid option "${optionKey}" passed to configureImageRule(). Valid keys are ${Object.keys(this.imageRuleOptions).join(', ')}`);
848+
}
849+
850+
this.imageRuleOptions[optionKey] = options[optionKey];
847851
}
848852

849-
// Check allowed keys
850-
const validKeys = ['images', 'fonts'];
851-
for (const key of Object.keys(urlLoaderOptions)) {
852-
if (!validKeys.includes(key)) {
853-
throw new Error(`"${key}" is not a valid key for configureUrlLoader(). Valid keys: ${validKeys.join(', ')}.`);
853+
if (this.imageRuleOptions.maxSize && this.imageRuleOptions.type !== 'asset') {
854+
throw new Error('Invalid option "maxSize" passed to configureImageRule(): this option is only valid when "type" is set to "asset".');
855+
}
856+
857+
if (typeof ruleCallback !== 'function') {
858+
throw new Error('Argument 2 to configureImageRule() must be a callback function.');
859+
}
860+
861+
this.imageRuleCallback = ruleCallback;
862+
}
863+
864+
configureFontRule(options = {}, ruleCallback = () => {}) {
865+
for (const optionKey of Object.keys(options)) {
866+
if (!(optionKey in this.fontRuleOptions)) {
867+
throw new Error(`Invalid option "${optionKey}" passed to configureFontRule(). Valid keys are ${Object.keys(this.fontRuleOptions).join(', ')}`);
854868
}
869+
870+
this.fontRuleOptions[optionKey] = options[optionKey];
871+
}
872+
873+
if (this.fontRuleOptions.maxSize && this.fontRuleOptions.type !== 'asset') {
874+
throw new Error('Invalid option "maxSize" passed to configureFontRule(): this option is only valid when "type" is set to "asset".');
875+
}
876+
877+
if (typeof ruleCallback !== 'function') {
878+
throw new Error('Argument 2 to configureFontRule() must be a callback function.');
855879
}
856880

857-
this.urlLoaderOptions = urlLoaderOptions;
881+
this.fontRuleCallback = ruleCallback;
858882
}
859883

860884
cleanupOutputBeforeBuild(paths = ['**/*'], cleanWebpackPluginOptionsCallback = () => {}) {

0 commit comments

Comments
 (0)