Skip to content

Commit

Permalink
Merge pull request #841 from embroider-build/cache-busting
Browse files Browse the repository at this point in the history
[Fix] Cache busting
  • Loading branch information
rwjblue authored Jun 11, 2021
2 parents f7d8ee7 + e988688 commit 9426ad8
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"lodash": "^4.17.10",
"pkg-up": "^3.1.0",
"resolve": "^1.8.1",
"resolve-package-path": "^1.2.2",
"resolve-package-path": "^4.0.1",
"strip-bom": "^3.0.0",
"typescript-memoize": "^1.0.0",
"walk-sync": "^1.1.3",
Expand Down
45 changes: 42 additions & 3 deletions packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import partition from 'lodash/partition';
import mergeWith from 'lodash/mergeWith';
import cloneDeep from 'lodash/cloneDeep';
import type { Params as InlineBabelParams } from './babel-plugin-inline-hbs-node';
import { PortableHint } from './portable';
import { PortableHint, maybeNodeModuleVersion } from './portable';
import escapeRegExp from 'escape-string-regexp';
import { getEmberExports } from './load-ember-template-compiler';

Expand Down Expand Up @@ -144,6 +144,38 @@ 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(`${__dirname}/../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}`);
}

plugins[absolutePathToPlugin] = maybeNodeModuleVersion(absolutePathToPlugin);
}

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

class ParsedEmberAsset {
kind: 'parsed-ember' = 'parsed-ember';
relativePath: string;
Expand Down Expand Up @@ -383,7 +415,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 Expand Up @@ -922,7 +956,12 @@ export class AppBuilder<TreeNames> {
}
cursor = resolve.sync(target, { basedir: dirname(cursor) });
}
return { requireFile: cursor, useMethod: hint.useMethod };

return {
requireFile: cursor,
useMethod: hint.useMethod,
packageVersion: maybeNodeModuleVersion(cursor),
};
});
}

Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/babel-plugin-cache-busting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function makePlugin(): any {
// Dear future @rwjblue,
//
// This plugin exists as a sentinel plugin which has no behavior, but
// provides a position in the babel configuration to include cache busting
// meta-data about other plugins. Specifically their versions.
//
// Yours sincerely,
// Contributor
return {};
}
19 changes: 19 additions & 0 deletions packages/core/src/portable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import mapValues from 'lodash/mapValues';
import assertNever from 'assert-never';
import { Memoize } from 'typescript-memoize';
import resolvePackagePath from 'resolve-package-path';

export const protocol = '__embroider_portable_values__';
const { globalValues, nonce } = setupGlobals();
Expand All @@ -13,9 +14,22 @@ export interface PortableResult {

export interface PortableHint {
requireFile: string;
packageVersion: string | undefined;
useMethod?: string;
}

const { findUpPackagePath } = resolvePackagePath;

export function maybeNodeModuleVersion(path: string) {
const packagePath = findUpPackagePath(path);

if (packagePath === null) {
throw new Error(`Could not find package.json for '${path}'`);
} else {
return require(packagePath).version; // eslint-disable-line @typescript-eslint/no-require-imports
}
}

export class Portable {
constructor(
private opts: {
Expand Down Expand Up @@ -83,6 +97,7 @@ export class Portable {
embroiderPlaceholder: true,
type: 'broccoli-parallel',
requireFile: found.requireFile,
packageVersion: maybeNodeModuleVersion(found.requireFile),
useMethod: found.useMethod,
},
isParallelSafe: true,
Expand Down Expand Up @@ -154,6 +169,7 @@ interface BroccoliParallelPlaceholder {
embroiderPlaceholder: true;
type: 'broccoli-parallel';
requireFile: string;
packageVersion: string | undefined;
useMethod: string | undefined;
buildUsing: string | undefined;
params: any;
Expand All @@ -162,6 +178,7 @@ interface BroccoliParallelPlaceholder {
interface HTMLBarsParallelPlaceholder {
embroiderPlaceholder: true;
type: 'htmlbars-parallel';
packageVersion: string | undefined;
requireFile: string;
buildUsing: string;
params: any;
Expand Down Expand Up @@ -193,6 +210,7 @@ function maybeBroccoli(object: any): BroccoliParallelPlaceholder | undefined {
embroiderPlaceholder: true,
type: 'broccoli-parallel',
requireFile: object._parallelBabel.requireFile,
packageVersion: maybeNodeModuleVersion(object._parallelBabel.requireFile),
buildUsing: object._parallelBabel.buildUsing,
useMethod: object._parallelBabel.useMethod,
params: object._parallelBabel.params,
Expand Down Expand Up @@ -238,6 +256,7 @@ function maybeHTMLBars(object: any): HTMLBarsParallelPlaceholder | undefined {
embroiderPlaceholder: true,
type: 'htmlbars-parallel',
requireFile: object.parallelBabel.requireFile,
packageVersion: maybeNodeModuleVersion(object.parallelBabel.requireFile),
buildUsing: String(object.parallelBabel.buildUsing),
params: object.parallelBabel.params,
};
Expand Down
45 changes: 44 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,46 @@ 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: [__dirname, [__dirname, []], [`${__dirname}/../`, []], __dirname, [__dirname, []]],
};

addCachablePlugin(input);

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

[
CACHE_BUSTING_PLUGIN.path,
{
plugins: {
[CACHE_BUSTING_PLUGIN.path]: CACHE_BUSTING_PLUGIN.version,
[__dirname]: CACHE_BUSTING_PLUGIN.version,
[`${__dirname}/../`]: CACHE_BUSTING_PLUGIN.version,
},
},
],
],
});
});
});
15 changes: 15 additions & 0 deletions packages/core/tests/portable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { maybeNodeModuleVersion } from '../src/portable';
import { readJSONSync } from 'fs-extra';

const EMBROIDER_CORE_VERSION = readJSONSync(`${__dirname}/../package.json`).version;

describe('maybeNodeModuleVersion', () => {
test('it', () => {
expect(() => maybeNodeModuleVersion('/dev/null')).toThrow(/Could not find package.json for '\/dev\/null'/);
expect(() => maybeNodeModuleVersion('/does/not/exist')).toThrow(
/Could not find package.json for '\/does\/not\/exist'/
);
expect(maybeNodeModuleVersion(__dirname)).toEqual(EMBROIDER_CORE_VERSION);
expect(maybeNodeModuleVersion(__filename)).toEqual(EMBROIDER_CORE_VERSION);
});
});
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16642,6 +16642,13 @@ resolve-package-path@^3.1.0:
path-root "^0.1.1"
resolve "^1.17.0"

resolve-package-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-4.0.1.tgz#0e77271e06c8cc41740d28ef974806a77fdc8880"
integrity sha512-2gb/yU2fSfX22pjDYyevzyOKK9q72XKUFqlAsrfPzZArM4JkIH/Qcme4n3EbaZttObWm/fIFLbPxrXIyiL8wdQ==
dependencies:
path-root "^0.1.1"

resolve-path@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7"
Expand Down

0 comments on commit 9426ad8

Please sign in to comment.