Skip to content

Commit

Permalink
Implements a getFeatureFlag to avoid option drilling (#9618)
Browse files Browse the repository at this point in the history
* Implement a simple feature-flag client to avoid option drilling

* Ensure feature flag client is initialised in workers

* Rename featureFlags -> featureFlagValues

* Avoid depending on ephemeral flag in test
  • Loading branch information
marcins authored Apr 4, 2024
1 parent 9d66c19 commit a24a30d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/core/core/src/Parcel.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
fromProjectPathRelative,
} from './projectPath';
import {tracer} from '@parcel/profiler';
import {setFeatureFlags} from '@parcel/feature-flags';

registerCoreWithSerializer();

Expand Down Expand Up @@ -108,6 +109,8 @@ export default class Parcel {
let {config} = await loadParcelConfig(resolvedOptions);
this.#config = new ParcelConfig(config, resolvedOptions);

setFeatureFlags(resolvedOptions.featureFlags);

if (this.#initialOptions.workerFarm) {
if (this.#initialOptions.workerFarm.ending) {
throw new Error('Supplied WorkerFarm is ending');
Expand Down
4 changes: 4 additions & 0 deletions packages/core/core/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {clearBuildCaches} from './buildCache';
import {init as initSourcemaps} from '@parcel/source-map';
import {init as initRust} from '@parcel/rust';
import WorkerFarm from '@parcel/workers';
import {setFeatureFlags} from '@parcel/feature-flags';

import '@parcel/cache'; // register with serializer
import '@parcel/package-manager';
Expand Down Expand Up @@ -78,6 +79,9 @@ async function loadConfig(cachePath, options) {
);
config = new ParcelConfig(processedConfig, options);
parcelConfigCache.set(cachePath, config);

setFeatureFlags(options.featureFlags);

return config;
}

Expand Down
10 changes: 10 additions & 0 deletions packages/core/feature-flags/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ export const DEFAULT_FEATURE_FLAGS: FeatureFlags = {
exampleFeature: false,
configKeyInvalidation: false,
};

let featureFlagValues: FeatureFlags = {...DEFAULT_FEATURE_FLAGS};

export function setFeatureFlags(flags: FeatureFlags) {
featureFlagValues = flags;
}

export function getFeatureFlag(flagName: $Keys<FeatureFlags>): boolean {
return featureFlagValues[flagName];
}
21 changes: 21 additions & 0 deletions packages/core/feature-flags/test/feature-flags.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @flow strict
import assert from 'assert';
import {getFeatureFlag, DEFAULT_FEATURE_FLAGS, setFeatureFlags} from '../src';

describe('feature-flag test', () => {
beforeEach(() => {
setFeatureFlags(DEFAULT_FEATURE_FLAGS);
});

it('has defaults', () => {
assert.equal(
getFeatureFlag('exampleFeature'),
DEFAULT_FEATURE_FLAGS.exampleFeature,
);
});

it('can override', () => {
setFeatureFlags({...DEFAULT_FEATURE_FLAGS, exampleFeature: true});
assert.equal(getFeatureFlag('exampleFeature'), true);
});
});
39 changes: 38 additions & 1 deletion packages/core/integration-tests/test/feature-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ describe('feature flags', () => {
'*.js': ['./transformer.js', '...']
},
}
.parcelrc-2:
{
extends: "@parcel/config-default",
transformers: {
'*.js': ['./transformer-client.js', '...']
},
}
transformer.js:
const {Transformer} = require('@parcel/plugin');
module.exports = new Transformer({
Expand All @@ -40,6 +48,19 @@ describe('feature flags', () => {
return [asset];
}
});
transformer-client.js:
const {Transformer} = require('@parcel/plugin');
const {getFeatureFlag} = require('@parcel/feature-flags');
module.exports = new Transformer({
async transform({asset, options}) {
const code = await asset.getCode();
if (code.includes('MARKER') && getFeatureFlag('exampleFeature')) {
asset.setCode(code.replace('MARKER', 'REPLACED'));
}
return [asset];
}
});
`;
});

Expand Down Expand Up @@ -98,4 +119,20 @@ describe('feature flags', () => {
`Expected ${output} to NOT contain 'REPLACED'`,
);
});

it('flag should be available in plugins via client', async () => {
await overlayFS.mkdirp(dir);

const b = await bundle(path.join(dir, 'index.js'), {
inputFS: overlayFS,
featureFlags: {exampleFeature: true},
config: path.join(dir, '.parcelrc-2'),
});
const output = await run(b);

assert(
output.includes('REPLACED'),
`Expected ${output} to contain 'REPLACED'`,
);
});
});

0 comments on commit a24a30d

Please sign in to comment.