Skip to content

[Webpack 5] Adding new enableBuildCache() method for Webpack 5 persistent caching #884

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 23, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
added to allow the `MiniCssExtractPlugin.loader` and `MiniCssExtractPlugin`
to be configured.

* [enableBuildCache()] Added `enableBuildCache()` to enable the new
Webpack 5 build caching. https://webpack.js.org/blog/2020-10-10-webpack-5-release/
This feature should be considered experimental.

## 0.33.0

* [disableCssExtraction()] Added boolean argument to `disableCssExtraction()`
Expand Down
31 changes: 31 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,37 @@ class Encore {
return this;
}

/**
* Enables & configures persistent build caching.
*
* https://webpack.js.org/blog/2020-10-10-webpack-5-release/#persistent-caching
*
* ```
* Encore.enableBuildCache({
* // object of "buildDependencies"
* // https://webpack.js.org/configuration/other-options/#cachebuilddependencies
* // __filename means that changes to webpack.config.js should invalidate the cache
* config: [__filename],
* });
**
* // also configure other options the Webpack "cache" key
* Encore.enableBuildCache({ config: [__filename] }, (cache) => {
* cache.version: `${process.env.GIT_REV}`;
*
* cache.name: `${env.target}`
* });
* ```
*
* @param {object} buildDependencies
* @param {function} cacheCallback
* @returns {Encore}
*/
enableBuildCache(buildDependencies, cacheCallback = (cache) => {}) {
webpackConfig.enableBuildCache(buildDependencies, cacheCallback);

return this;
}

/**
* Configure the mini-css-extract-plugin.
*
Expand Down
22 changes: 22 additions & 0 deletions lib/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class WebpackConfig {
this.useVersioning = false;
this.useSourceMaps = false;
this.cleanupOutput = false;
this.usePersistentCache = false;
this.extractCss = true;
this.imageRuleOptions = {
type: 'asset/resource',
Expand Down Expand Up @@ -150,6 +151,7 @@ class WebpackConfig {
this.eslintOptions = {
lintVue: false,
};
this.persistentCacheBuildDependencies = {};

// Features/Loaders options callbacks
this.imageRuleCallback = () => {};
Expand Down Expand Up @@ -197,6 +199,7 @@ class WebpackConfig {
this.terserPluginOptionsCallback = () => {};
this.cssMinimizerPluginOptionsCallback = () => {};
this.notifierPluginOptionsCallback = () => {};
this.persistentCacheCallback = () => {};
}

getContext() {
Expand Down Expand Up @@ -685,6 +688,25 @@ class WebpackConfig {
this.stimulusOptions.controllersJsonPath = controllerJsonPath;
}

enableBuildCache(buildDependencies, callback = (cache) => {}) {
if (typeof buildDependencies !== 'object') {
throw new Error('Argument 1 to enableBuildCache() must be an object.');
}

if (!buildDependencies.config) {
throw new Error('Argument 1 to enableBuildCache() should contain an object with at least a "config" key. See the documentation for this method.');
}

this.usePersistentCache = true;
this.persistentCacheBuildDependencies = buildDependencies;

if (typeof callback !== 'function') {
throw new Error('Argument 2 to enableBuildCache() must be a callback function.');
}

this.persistentCacheCallback = callback;
}

enableReactPreset() {
this.useReact = true;
}
Expand Down
19 changes: 19 additions & 0 deletions lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class ConfigGenerator {
},
plugins: this.buildPluginsConfig(),
optimization: this.buildOptimizationConfig(),
cache: this.buildCacheConfig(),
watchOptions: this.buildWatchOptionsConfig(),
devtool: false,
};
Expand Down Expand Up @@ -509,6 +510,24 @@ class ConfigGenerator {
return optimization;
}

buildCacheConfig() {
if (!this.webpackConfig.usePersistentCache) {
return false;
}

const cache = {};

cache.type = 'filesystem';
cache.buildDependencies = this.webpackConfig.persistentCacheBuildDependencies;

applyOptionsCallback(
this.webpackConfig.persistentCacheCallback,
cache
);

return cache;
}

buildStatsConfig() {
// try to silence as much as possible: the output is rarely helpful
// this still doesn't remove all output
Expand Down
34 changes: 34 additions & 0 deletions test/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,40 @@ describe('WebpackConfig object', () => {
});
});

describe('enableBuildCache', () => {
it('Calling method enables it', () => {
const config = createConfig();
config.enableBuildCache({ config: ['foo.js'] });

expect(config.usePersistentCache).to.be.true;
expect(config.persistentCacheBuildDependencies).to.eql({ config: ['foo.js'] });
});

it('Calling with callback', () => {
const config = createConfig();
const callback = (cache) => {};
config.enableBuildCache({ config: ['foo.js'] }, callback);

expect(config.persistentCacheCallback).to.equal(callback);
});

it('Calling without config key throws an error', () => {
const config = createConfig();

expect(() => {
config.enableBuildCache({});
}).to.throw('should contain an object with at least a "config" key');
});

it('Calling with non-callback throws an error', () => {
const config = createConfig();

expect(() => {
config.enableBuildCache({ config: ['foo.js'] }, 'FOO');
}).to.throw('must be a callback function');
});
});

describe('enablePreactPreset', () => {
it('Without preact-compat', () => {
const config = createConfig();
Expand Down
32 changes: 32 additions & 0 deletions test/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,38 @@ describe('The config-generator function', () => {
});
});

describe('Test enableBuildCache()', () => {
it('with full arguments', () => {
const config = createConfig();
config.outputPath = '/tmp/public-path';
config.publicPath = '/public-path';
config.addEntry('main', './main');
config.enableBuildCache({ config: ['foo.js'] }, (cache) => {
cache.version = 5;
});

const actualConfig = configGenerator(config);
expect(actualConfig.cache).to.eql({
type: 'filesystem',
buildDependencies: { config: ['foo.js'] },
version: 5
});
});

it('with sourcemaps', () => {
const config = createConfig();
config.outputPath = '/tmp/public-path';
config.publicPath = '/public-path';
config.addEntry('main', './main');
config.useSourceMaps = true;

const actualConfig = configGenerator(config);
expect(actualConfig.devtool).to.equal('inline-source-map');

expect(JSON.stringify(actualConfig.module.rules)).to.contain('"sourceMap":true');
});
});

describe('Test configureBabel()', () => {
it('without configureBabel()', () => {
const config = createConfig();
Expand Down
17 changes: 17 additions & 0 deletions test/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,23 @@ describe('Functional tests using webpack', function() {
});
});

it('Persistent caching does not cause problems', (done) => {
const config = createWebpackConfig('www/build', 'dev');
config.setPublicPath('/build');
config.addEntry('main', './js/code_splitting');
config.enableBuildCache({ config: [__filename] });

testSetup.runWebpack(config, (webpackAssert) => {
// sanity check
webpackAssert.assertManifestPath(
'build/main.js',
'/build/main.js'
);

done();
});
});

describe('addCacheGroup()', () => {
it('addCacheGroup() to extract a vendor into its own chunk', (done) => {
const config = createWebpackConfig('www/build', 'dev');
Expand Down
20 changes: 20 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

const expect = require('chai').expect;
const api = require('../index');
const path = require('path');

describe('Public API', () => {
beforeEach(() => {
Expand Down Expand Up @@ -416,6 +417,25 @@ describe('Public API', () => {

});

describe('enableStimulusBridge', () => {

it('should return the API object', () => {
const returnedValue = api.enableStimulusBridge(path.resolve(__dirname, '../', 'package.json'));
expect(returnedValue).to.equal(api);
});

});

describe('enableBuildCache', () => {

it('should return the API object', () => {
const returnedValue = api.enableBuildCache({ config: [__filename] });
expect(returnedValue).to.equal(api);
});

});


describe('configureMiniCssExtractPlugin', () => {

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