Skip to content

Commit

Permalink
addressing comments
Browse files Browse the repository at this point in the history
  • Loading branch information
thoov committed Aug 6, 2021
1 parent 351f07e commit f830fe4
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 51 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ export class AppBuilder<TreeNames> {
]);

// this is @embroider/macros configured for full stage3 resolution
babel.plugins.push(this.macrosConfig.babelPluginConfig());
babel.plugins = babel.plugins.concat(this.macrosConfig.babelPluginConfig());

babel.plugins.push([require.resolve('./template-colocation-plugin')]);

Expand Down
1 change: 1 addition & 0 deletions packages/macros/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@embroider/shared-internals": "0.43.4",
"assert-never": "^1.2.1",
"ember-cli-babel": "^7.26.6",
"find-up": "^5.0.0",
"lodash": "^4.17.21",
"resolve": "^1.20.0",
"semver": "^7.3.2"
Expand Down
35 changes: 1 addition & 34 deletions packages/macros/src/ember-addon-main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import fs from 'fs';
import { join } from 'path';
import crypto from 'crypto';
import { MacrosConfig, isEmbroiderMacrosPlugin } from './node';

export = {
Expand Down Expand Up @@ -71,38 +69,7 @@ export = {
if (!babelPlugins.some(isEmbroiderMacrosPlugin)) {
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 pnpmLockPath = join(appInstance.project.root, 'pnpm-lock.yaml');
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 if (fs.existsSync(pnpmLockPath)) {
lockFileBuffer = fs.readFileSync(pnpmLockPath);
} 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('@embroider/shared-internals/src/babel-plugin-cache-busting.js'),
{ version: cacheKey },
'@embroider/macros cache buster',
]);
babelOptions.plugins = babelPlugins.concat(MacrosConfig.for(appInstance).babelPluginConfig(source));
}
},

Expand Down
31 changes: 29 additions & 2 deletions packages/macros/src/macros-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import fs from 'fs';
import { join } from 'path';
import crypto from 'crypto';
import findUp from 'find-up';
import type { PluginItem } from '@babel/core';
import { PackageCache, getOrCreate } from '@embroider/shared-internals';
import { makeFirstTransform, makeSecondTransform } from './glimmer/ast-transform';
Expand Down Expand Up @@ -255,7 +258,7 @@ export default class MacrosConfig {
// normal node_modules resolution can find their dependencies. In other words,
// owningPackageRoot is needed when you use this inside classic ember-cli, and
// it's not appropriate inside embroider.
babelPluginConfig(owningPackageRoot?: string): PluginItem {
babelPluginConfig(owningPackageRoot?: string): PluginItem[] {
let self = this;
let opts: State['opts'] = {
// this is deliberately lazy because we want to allow everyone to finish
Expand All @@ -281,7 +284,31 @@ export default class MacrosConfig {

importSyncImplementation: this.importSyncImplementation,
};
return [join(__dirname, 'babel', 'macros-babel-plugin.js'), opts];

let lockFilePath = findUp.sync(['yarn.lock', 'package-lock.json', 'pnpm-lock.yaml']);

if (!lockFilePath) {
lockFilePath = findUp.sync('package.json');
}

let lockFileBuffer = lockFilePath ? fs.readFileSync(lockFilePath) : 'no-cache-key';

// @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');
return [
[join(__dirname, 'babel', 'macros-babel-plugin.js'), opts],
[
require.resolve('@embroider/shared-internals/src/babel-plugin-cache-busting.js'),
{ version: cacheKey },
`@embroider/macros cache buster: ${owningPackageRoot}`,
],
];
}

static astPlugins(owningPackageRoot?: string): {
Expand Down
4 changes: 2 additions & 2 deletions packages/macros/tests/babel/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function makeBabelConfig(_babelVersion: number, macroConfig: MacrosConfig
return {
filename: join(__dirname, 'sample.js'),
presets: [],
plugins: [macroConfig.babelPluginConfig()],
plugins: macroConfig.babelPluginConfig(),
};
}

Expand Down Expand Up @@ -100,7 +100,7 @@ export function allBabelVersions(createTests: CreateTests | CreateTestsWithConfi
return {
filename: join(__dirname, 'sample.js'),
presets: [],
plugins: [config.babelPluginConfig()],
plugins: config.babelPluginConfig(),
};
},

Expand Down
42 changes: 30 additions & 12 deletions tests/scenarios/macro-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import { loadFromFixtureData } from './helpers';
import fs from 'fs-extra';
const { module: Qmodule, test } = QUnit;

function updateLodashVersion(app: PreparedApp, version: string) {
let pkgJson = fs.readJsonSync(join(app.dir, 'package.json'));
let pkgJsonLodash = fs.readJsonSync(join(app.dir, 'node_modules', 'lodash', 'package.json'));

pkgJson.devDependencies.lodash = version;
pkgJsonLodash.version = version;

fs.writeJsonSync(join(app.dir, 'package.json'), pkgJson);
fs.writeJsonSync(join(app.dir, 'node_modules', 'lodash', 'package.json'), pkgJsonLodash);
}

appScenarios
.map('macro-tests', project => {
let macroSampleAddon = Project.fromDir(dirname(require.resolve('../addon-template/package.json')), {
Expand Down Expand Up @@ -36,8 +47,12 @@ appScenarios
.forEachScenario(scenario => {
Qmodule(scenario.name, function (hooks) {
let app: PreparedApp;
let pkgJson: any;
let pkgJsonLodash: any;

hooks.before(async () => {
app = await scenario.prepare();
updateLodashVersion(app, '4.0.0');
});

test(`yarn test`, async function (assert) {
Expand All @@ -56,27 +71,30 @@ appScenarios
assert.equal(result.exitCode, 0, result.output);
});

test(`multiple dependency check`, async function (assert) {
let pkgJson = fs.readJsonSync(join(app.dir, 'package.json'));
let pkgJsonLodash = fs.readJsonSync(join(app.dir, 'node_modules', 'lodash', 'package.json'));
test(`@embroider/macros babel caching plugin works`, async function (assert) {
let lodashFourRun = await app.execute(`yarn test`);
assert.equal(lodashFourRun.exitCode, 0, lodashFourRun.output);

pkgJson.devDependencies.lodash = '4.0.0';
pkgJsonLodash.version = '4.0.0';
// simulate a different version being installed
updateLodashVersion(app, '3.0.0');

fs.writeJsonSync(join(app.dir, 'package.json'), pkgJson);
fs.writeJsonSync(join(app.dir, 'node_modules', 'lodash', 'package.json'), pkgJsonLodash);
let lodashThreeRun = await app.execute(`cross-env LODASH_VERSION=three yarn test`);
assert.equal(lodashThreeRun.exitCode, 0, lodashThreeRun.output);
});

let lodashFourRun = await app.execute(`yarn test`);
test(`CLASSIC=true @embroider/macros babel caching plugin works`, async function (assert) {
updateLodashVersion(app, '4.0.1');

let lodashFourRun = await app.execute(`cross-env CLASSIC=true yarn test`);
assert.equal(lodashFourRun.exitCode, 0, lodashFourRun.output);

// downgrade lodash to 3.0.0
pkgJson.devDependencies.lodash = '3.0.0';
pkgJsonLodash.version = '3.0.0';
// simulate a different version being installed
updateLodashVersion(app, '3.0.0');

fs.writeJsonSync(join(app.dir, 'package.json'), pkgJson);
fs.writeJsonSync(join(app.dir, 'node_modules', 'lodash', 'package.json'), pkgJsonLodash);

let lodashThreeRun = await app.execute(`cross-env LODASH_VERSION=three yarn test`);
let lodashThreeRun = await app.execute(`cross-env LODASH_VERSION=three CLASSIC=true yarn test`);
assert.equal(lodashThreeRun.exitCode, 0, lodashThreeRun.output);
});
});
Expand Down

0 comments on commit f830fe4

Please sign in to comment.