Skip to content

Commit

Permalink
Fix babel plugin cache eviction
Browse files Browse the repository at this point in the history
Today, babel’s caches (via babel-loader today) expires caches only if the options passed to it change, unfortunately if you upgrade a plugin without changing the configuration options and the file contents remains the same, the cache will not be evicted. This can lead to spurious caching problems if the associated plugins behavior has changed.

To address this defect we now include (when available) the package.json#version of the babel plugins used in our own no-op babel plugin’s configuration. This new no-op plugin is then inserted at the end of the configuration in question.
  • Loading branch information
stefanpenner committed Jun 9, 2021
1 parent 12ecbc1 commit 03d5d12
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 2 deletions.
35 changes: 34 additions & 1 deletion packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import type { Params as InlineBabelParams } from './babel-plugin-inline-hbs-node
import { PortableHint } from './portable';
import escapeRegExp from 'escape-string-regexp';
import { getEmberExports } from './load-ember-template-compiler';
import resolvePackagePath from 'resolve-package-path';

export type EmberENV = unknown;

Expand Down Expand Up @@ -144,6 +145,36 @@ export function excludeDotFiles(files: string[]) {
return files.filter(file => !file.startsWith('.') && !file.includes('/.'));
}

export const CACHE_BUSTING_PLUGIN = {
path: require.resolve('./babel-plugin-cache-busting'),
version: readJSONSync('../../package.json').version,
};

export function addCachablePlugin(babelConfig: TransformOptions) {
if (Array.isArray(babelConfig.plugins) && babelConfig.plugins.length > 0) {
const plugins = Object.create(null);
plugins[CACHE_BUSTING_PLUGIN.path] = CACHE_BUSTING_PLUGIN.version;

for (const plugin of babelConfig.plugins) {
let absolutePathToPlugin: string;
if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
absolutePathToPlugin = plugin[0] as string;
} else if (typeof plugin === 'string') {
absolutePathToPlugin = plugin
} else {
throw new Error(`[Embroider] a babel plugin without an absolute path was from: ${plugin}`)
}

const pkgPath = resolvePackagePath.findUpPackagePath(absolutePathToPlugin);
plugins[absolutePathToPlugin] = pkgPath ? readJSONSync(pkgPath).version: undefined;
}

babelConfig.plugins.push([CACHE_BUSTING_PLUGIN.path, {
plugins
}]);
}
}

class ParsedEmberAsset {
kind: 'parsed-ember' = 'parsed-ember';
relativePath: string;
Expand Down Expand Up @@ -383,7 +414,9 @@ export class AppBuilder<TreeNames> {
{ absoluteRuntime: __dirname, useESModules: true, regenerator: false },
]);

return makePortable(babel, { basedir: this.root }, this.portableHints);
const portable = makePortable(babel, { basedir: this.root }, this.portableHints)
addCachablePlugin(portable.config);
return portable;
}

private adjustImportsPlugin(engines: Engine[]): PluginItem {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/babel-plugin-cache-busting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export default function makePlugin() : any {
return { };
}
51 changes: 50 additions & 1 deletion packages/core/tests/app.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { excludeDotFiles } from '../src/app';
import { excludeDotFiles, addCachablePlugin, CACHE_BUSTING_PLUGIN } from '../src/app';

describe('dot files can be excluded', () => {
test('excludeDotFiles works', () => {
Expand All @@ -10,3 +10,52 @@ describe('dot files can be excluded', () => {
expect(excludeDotFiles(['foo/bar/baz/.foo.js'])).toEqual([]);
});
});

describe('cacheable-plugin', function() {
test('noop', function() {
const input = {};
addCachablePlugin(input)
expect(input).toEqual({});
});

test('no plugins', function() {
const input = { plugins: []};
addCachablePlugin(input)
expect(input).toEqual({ plugins: []});
});

test('some plugins', function() {
const input = {
plugins: [
'/nope/not/found',
__dirname,
[__dirname, []],
[`${__dirname}/../`, []],
__dirname,
[__dirname, []],
]
};

addCachablePlugin(input)

expect(input).toEqual({
plugins: [
'/nope/not/found',
__dirname,
[__dirname, []],
[`${__dirname}/../`, []],
__dirname,
[__dirname, []],

[CACHE_BUSTING_PLUGIN.path, {
plugins: {
[CACHE_BUSTING_PLUGIN.path]: CACHE_BUSTING_PLUGIN.version,
'/nope/not/found': undefined,
[__dirname]: CACHE_BUSTING_PLUGIN.version,
[`${__dirname}/../`]: CACHE_BUSTING_PLUGIN.version,
}
}]
]
});
});
});

0 comments on commit 03d5d12

Please sign in to comment.