From ac4109646876d377ed5bcb7a786ce7292d6a0b2e Mon Sep 17 00:00:00 2001 From: Travis Hoover Date: Thu, 29 Jul 2021 15:06:35 -0700 Subject: [PATCH] Rerun macros babel plugins if dependencies change dependencySatisfies can become invalid if babel caches the macros plugin + the dependency that is being checked for changes its package version. This adds a cache busting plugin that tracks a hash of the contents of the apps lock file so any changes to dependencies will bust the cache. Fixes: #906 --- .../macros/src/babel-plugin-cache-busting.ts | 3 +++ packages/macros/src/ember-addon-main.ts | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 packages/macros/src/babel-plugin-cache-busting.ts diff --git a/packages/macros/src/babel-plugin-cache-busting.ts b/packages/macros/src/babel-plugin-cache-busting.ts new file mode 100644 index 000000000..ec7a51b05 --- /dev/null +++ b/packages/macros/src/babel-plugin-cache-busting.ts @@ -0,0 +1,3 @@ +export default function makePlugin(): any { + return {}; +} diff --git a/packages/macros/src/ember-addon-main.ts b/packages/macros/src/ember-addon-main.ts index bdd019146..735424646 100644 --- a/packages/macros/src/ember-addon-main.ts +++ b/packages/macros/src/ember-addon-main.ts @@ -1,4 +1,6 @@ +import fs from 'fs'; import { join } from 'path'; +import crypto from 'crypto'; import { MacrosConfig, isEmbroiderMacrosPlugin } from './node'; export = { @@ -70,6 +72,30 @@ export = { let appInstance = this._findHost(); let source = appOrAddonInstance.root || appOrAddonInstance.project.root; babelPlugins.unshift(MacrosConfig.for(appInstance).babelPluginConfig(source)); + + let yarnLockPath = join(appInstance.project.root, 'yarn.lock'); + let npmLockPath = join(appInstance.project.root, 'package-lock.json'); + let packagePath = join(appInstance.project.root, 'package.json'); + let lockFileBuffer; + + if (fs.existsSync(yarnLockPath)) { + lockFileBuffer = fs.readFileSync(yarnLockPath); + } else if (fs.existsSync(npmLockPath)) { + lockFileBuffer = fs.readFileSync(npmLockPath); + } else { + // no lock file found, using package.json as a fall back + lockFileBuffer = fs.readFileSync(packagePath); + } + + // @embroider/macros provides a macro called dependencySatisfies which checks if a given + // package name satisfies a given semver version range. Due to the way babel caches this can + // cause a problem where the macro plugin does not run (because it has been cached) but the version + // of the dependency being checked for changes (due to installing a different version). This will lead to + // the old evaluated state being used which might be invalid. This cache busting plugin keeps track of a + // hash representing the lock file of the app and if it ever changes forces babel to rerun its plugins. + // more information in issue #906 + let cacheKey = crypto.createHash('sha256').update(lockFileBuffer).digest('hex'); + babelPlugins.push([require.resolve('./babel-plugin-cache-busting'), { version: cacheKey }]); } },