Skip to content

Commit 0807667

Browse files
committed
Adding new enableBuildCache() method for Webpack 5 persistent caching
1 parent 7a4794d commit 0807667

8 files changed

+181
-0
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## 1.0.0
4+
5+
* [enableBuildCache()] Added `enableBuildCache()` to enable the new
6+
Webpack 5 build caching. https://webpack.js.org/blog/2020-10-10-webpack-5-release/
7+
This feature should be considered experimental.
8+
39
## 0.33.0
410

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

index.js

+31
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,37 @@ class Encore {
10051005
return this;
10061006
}
10071007

1008+
/**
1009+
* Enables & configures persistent build caching.
1010+
*
1011+
* https://webpack.js.org/blog/2020-10-10-webpack-5-release/#persistent-caching
1012+
*
1013+
* ```
1014+
* Encore.enableBuildCache({
1015+
* // object of "buildDependencies"
1016+
* // https://webpack.js.org/configuration/other-options/#cachebuilddependencies
1017+
* // __filename means that changes to webpack.config.js should invalidate the cache
1018+
* config: [__filename],
1019+
* });
1020+
**
1021+
* // also configure other options the Webpack "cache" key
1022+
* Encore.enableBuildCache({ config: [__filename] }, (cache) => {
1023+
* cache.version: `${process.env.GIT_REV}`;
1024+
*
1025+
* cache.name: `${env.target}`
1026+
* });
1027+
* ```
1028+
*
1029+
* @param {object} buildDependencies
1030+
* @param {function} cacheCallback
1031+
* @returns {Encore}
1032+
*/
1033+
enableBuildCache(buildDependencies, cacheCallback = (cache) => {}) {
1034+
webpackConfig.enableBuildCache(buildDependencies, cacheCallback);
1035+
1036+
return this;
1037+
}
1038+
10081039
/**
10091040
* Configure the mini-css-extract-plugin.
10101041
*

lib/WebpackConfig.js

+22
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class WebpackConfig {
9696
this.useVersioning = false;
9797
this.useSourceMaps = false;
9898
this.cleanupOutput = false;
99+
this.usePersistentCache = false;
99100
this.extractCss = true;
100101
this.useImagesLoader = true;
101102
this.useFontsLoader = true;
@@ -144,6 +145,7 @@ class WebpackConfig {
144145
this.eslintOptions = {
145146
lintVue: false,
146147
};
148+
this.persistentCacheBuildDependencies = {};
147149

148150
// Features/Loaders options callbacks
149151
this.postCssLoaderOptionsCallback = () => {};
@@ -189,6 +191,7 @@ class WebpackConfig {
189191
this.terserPluginOptionsCallback = () => {};
190192
this.cssMinimizerPluginOptionsCallback = () => {};
191193
this.notifierPluginOptionsCallback = () => {};
194+
this.persistentCacheCallback = () => {};
192195
}
193196

194197
getContext() {
@@ -677,6 +680,25 @@ class WebpackConfig {
677680
this.stimulusOptions.controllersJsonPath = controllerJsonPath;
678681
}
679682

683+
enableBuildCache(buildDependencies, callback = (cache) => {}) {
684+
if (typeof buildDependencies !== 'object') {
685+
throw new Error('Argument 1 to enableBuildCache() must be an object.');
686+
}
687+
688+
if (!buildDependencies.config) {
689+
throw new Error('Argument 1 to enableBuildCache() should contain an object with at least a "config" key. See the documentation for this method.');
690+
}
691+
692+
this.usePersistentCache = true;
693+
this.persistentCacheBuildDependencies = buildDependencies;
694+
695+
if (typeof callback !== 'function') {
696+
throw new Error('Argument 2 to enableBuildCache() must be a callback function.');
697+
}
698+
699+
this.persistentCacheCallback = callback;
700+
}
701+
680702
enableReactPreset() {
681703
this.useReact = true;
682704
}

lib/config-generator.js

+19
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class ConfigGenerator {
6767
},
6868
plugins: this.buildPluginsConfig(),
6969
optimization: this.buildOptimizationConfig(),
70+
cache: this.buildCacheConfig(),
7071
watchOptions: this.buildWatchOptionsConfig(),
7172
devtool: false,
7273
};
@@ -513,6 +514,24 @@ class ConfigGenerator {
513514
return optimization;
514515
}
515516

517+
buildCacheConfig() {
518+
if (!this.webpackConfig.usePersistentCache) {
519+
return false;
520+
}
521+
522+
const cache = {};
523+
524+
cache.type = 'filesystem';
525+
cache.buildDependencies = this.webpackConfig.persistentCacheBuildDependencies;
526+
527+
applyOptionsCallback(
528+
this.webpackConfig.persistentCacheCallback,
529+
cache
530+
);
531+
532+
return cache;
533+
}
534+
516535
buildStatsConfig() {
517536
// try to silence as much as possible: the output is rarely helpful
518537
// this still doesn't remove all output

test/WebpackConfig.js

+34
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,40 @@ describe('WebpackConfig object', () => {
906906
});
907907
});
908908

909+
describe('enableBuildCache', () => {
910+
it('Calling method enables it', () => {
911+
const config = createConfig();
912+
config.enableBuildCache({ config: ['foo.js'] });
913+
914+
expect(config.usePersistentCache).to.be.true;
915+
expect(config.persistentCacheBuildDependencies).to.eql({ config: ['foo.js'] });
916+
});
917+
918+
it('Calling with callback', () => {
919+
const config = createConfig();
920+
const callback = (cache) => {};
921+
config.enableBuildCache({ config: ['foo.js'] }, callback);
922+
923+
expect(config.persistentCacheCallback).to.equal(callback);
924+
});
925+
926+
it('Calling without config key throws an error', () => {
927+
const config = createConfig();
928+
929+
expect(() => {
930+
config.enableBuildCache({});
931+
}).to.throw('should contain an object with at least a "config" key');
932+
});
933+
934+
it('Calling with non-callback throws an error', () => {
935+
const config = createConfig();
936+
937+
expect(() => {
938+
config.enableBuildCache({ config: ['foo.js'] }, 'FOO');
939+
}).to.throw('must be a callback function');
940+
});
941+
});
942+
909943
describe('enablePreactPreset', () => {
910944
it('Without preact-compat', () => {
911945
const config = createConfig();

test/config-generator.js

+32
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,38 @@ describe('The config-generator function', () => {
973973
});
974974
});
975975

976+
describe('Test enableBuildCache()', () => {
977+
it('with full arguments', () => {
978+
const config = createConfig();
979+
config.outputPath = '/tmp/public-path';
980+
config.publicPath = '/public-path';
981+
config.addEntry('main', './main');
982+
config.enableBuildCache({ config: ['foo.js'] }, (cache) => {
983+
cache.version = 5;
984+
});
985+
986+
const actualConfig = configGenerator(config);
987+
expect(actualConfig.cache).to.eql({
988+
type: 'filesystem',
989+
buildDependencies: { config: ['foo.js'] },
990+
version: 5
991+
});
992+
});
993+
994+
it('with sourcemaps', () => {
995+
const config = createConfig();
996+
config.outputPath = '/tmp/public-path';
997+
config.publicPath = '/public-path';
998+
config.addEntry('main', './main');
999+
config.useSourceMaps = true;
1000+
1001+
const actualConfig = configGenerator(config);
1002+
expect(actualConfig.devtool).to.equal('inline-source-map');
1003+
1004+
expect(JSON.stringify(actualConfig.module.rules)).to.contain('"sourceMap":true');
1005+
});
1006+
});
1007+
9761008
describe('Test configureBabel()', () => {
9771009
it('without configureBabel()', () => {
9781010
const config = createConfig();

test/functional.js

+17
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,23 @@ describe('Functional tests using webpack', function() {
737737
});
738738
});
739739

740+
it('Persistent caching does not cause problems', (done) => {
741+
const config = createWebpackConfig('www/build', 'dev');
742+
config.setPublicPath('/build');
743+
config.addEntry('main', './js/code_splitting');
744+
config.enableBuildCache({ config: [__filename] });
745+
746+
testSetup.runWebpack(config, (webpackAssert) => {
747+
// sanity check
748+
webpackAssert.assertManifestPath(
749+
'build/main.js',
750+
'/build/main.js'
751+
);
752+
753+
done();
754+
});
755+
});
756+
740757
describe('addCacheGroup()', () => {
741758
it('addCacheGroup() to extract a vendor into its own chunk', (done) => {
742759
const config = createWebpackConfig('www/build', 'dev');

test/index.js

+20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
const expect = require('chai').expect;
1313
const api = require('../index');
14+
const path = require('path');
1415

1516
describe('Public API', () => {
1617
beforeEach(() => {
@@ -425,6 +426,25 @@ describe('Public API', () => {
425426

426427
});
427428

429+
describe('enableStimulusBridge', () => {
430+
431+
it('should return the API object', () => {
432+
const returnedValue = api.enableStimulusBridge(path.resolve(__dirname, '../', 'package.json'));
433+
expect(returnedValue).to.equal(api);
434+
});
435+
436+
});
437+
438+
describe('enableBuildCache', () => {
439+
440+
it('should return the API object', () => {
441+
const returnedValue = api.enableBuildCache({});
442+
expect(returnedValue).to.equal(api);
443+
});
444+
445+
});
446+
447+
428448
describe('configureMiniCssExtractPlugin', () => {
429449

430450
it('should return the API object', () => {

0 commit comments

Comments
 (0)