Skip to content

Commit

Permalink
Merge pull request #118 from halfbyte/prep-2.0.0
Browse files Browse the repository at this point in the history
Prepare 2.0.0 release
  • Loading branch information
calvinlough committed Jul 14, 2023
2 parents 74e0d74 + 9856e07 commit 29b4874
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 53 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Changelog

## 2.0.0

### Breaking changes

The semantics of `includeDirByFlag` have changed and now take a file glob pattern instead of a RegExp. This is because the mechanism for removing files from the build pipeline has changed to work around a bug in broccoli. (#111)

### New features

- Support for external config file to prevent leaking of feature flag names (#110)
- Support for multiple environments (For example to roll out features on a staging environment) (#110)

### Updates/Changes

- Modernised the code and all dependencies to be compatible with Ember 3.x and up (#107)
- Added @ember/string to be compatible with Ember 5.x (#117)
109 changes: 57 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,65 @@ This is an ember-cli addon, so all you need to do is
ember install ember-cli-conditional-compile
```

You should use the `0.3.x` series of releases if you're on Ember 1.13.6 or
older. If you're on Ember 1.13.7 or newer you must use at least the `0.4.x`
version.
# Compatibility

Version 2.x targets Ember 3.x and beyond. It is tested against the latest ember release and the latest beta release (See [config/ember-try.js](config/ember-try.js) for the testing matrix)

# Upgrading to 2.x

Our workaround around a broccoli pipeline bug in newer versions of ember-cli slightly changes the semantics of `includeDirByFlag`. Instead of a RegExp, you now need to specify a Glob-style pattern.

# Usage

To actually use the feature switches you'll need to add some configuration in your `environment.js` file. For example, lets pretend you want to have two feature switches; `ENABLE_FOO` and `ENABLE_BAR`:

```javascript
var ENV = {
// other settings ...

featureFlags: {
ENABLE_FOO: true,
ENABLE_BAR: true
},
includeDirByFlag: {
ENABLE_FOO: ['pods/foos/**', 'pods/foo/**'],
ENABLE_BAR: [],
}
// other settings ...

featureFlags: {
ENABLE_FOO: true,
ENABLE_BAR: true,
},
includeDirByFlag: {
ENABLE_FOO: ["pods/foos/**", "pods/foo/**"],
ENABLE_BAR: [],
},
};

// other environments ...

if (environment === 'production') {
ENV.featureFlags.ENABLE_FOO = false;
if (environment === "production") {
ENV.featureFlags.ENABLE_FOO = false;
}
```

Alternatively, you can define your feature flags in `config/feature-flags.js` looking like this:

```javascript
module.exports = function(environment) {
const GLOBAL_FLAGS = {
featureFlags: {
ENABLE_FOO: true,
ENABLE_BAR: true
},
includeDirByFlag: {
ENABLE_FOO: [/pods\/foos/, /pods\/foo/],
ENABLE_BAR: [],
}
}

if (environment === 'production') {
GLOBAL_FLAGS.featureFlags.ENABLE_FOO = false;
}

return GLOBAL_FLAGS;
}
module.exports = function (environment) {
const GLOBAL_FLAGS = {
featureFlags: {
ENABLE_FOO: true,
ENABLE_BAR: true,
},
includeDirByFlag: {
ENABLE_FOO: [/pods\/foos/, /pods\/foo/],
ENABLE_BAR: [],
},
};

if (environment === "production") {
GLOBAL_FLAGS.featureFlags.ENABLE_FOO = false;
}

return GLOBAL_FLAGS;
};
```

This has two advantages: It declutters `environment.js` a bit, especially if you have many flags, but also prevents your flag names from leaking into the application code under certain circumstances.

We'll look at the two new options in more detail below, but for now we can see that by default both features are enabled, but in the `production` environment `ENABLE_FOO` is disabled, and related code under the `pods/foos` and `pods/foo` directories are excluded from compilation.
We'll look at the two new options in more detail below, but for now we can see that by default both features are enabled, but in the `production` environment `ENABLE_FOO` is disabled, and related code under the `pods/foos` and `pods/foo` directories are excluded from compilation.

## ENV.featureFlags

Expand All @@ -78,16 +84,16 @@ However, since the flag is `false` in production, any code in those directories

# How it works

*ember-cli-conditional-compile* adds itself to the Broccoli compile pipeline for your Ember application. Depending on which environment you're building it acts in two different ways:
_ember-cli-conditional-compile_ adds itself to the Broccoli compile pipeline for your Ember application. Depending on which environment you're building it acts in two different ways:

## Development and test environments

Global variables are injected into the page which have the current state of the feature flags. For example:

```javascript
if (ENABLE_FOO) {
this.route('foo');
console.log('The feature ENABLE_FOO is enabled in this environment');
this.route("foo");
console.log("The feature ENABLE_FOO is enabled in this environment");
}
```

Expand All @@ -97,28 +103,28 @@ will be represented in development and test environments as:
window.ENABLE_FOO = true;

if (ENABLE_FOO) {
this.route('foo');
console.log('The feature ENABLE_FOO is enabled in this environment');
this.route("foo");
console.log("The feature ENABLE_FOO is enabled in this environment");
}
```

In Handlebars/HTMLBars templates, you can also make use of the flags using the `if-flag` block helper:

```hbs
{{#if-flag ENABLE_FOO}}
<p>Foo is enabled! \o/</p>
<p>Foo is enabled! \o/</p>
{{else}}
<p>Foo is disabled</p>
<p>Foo is disabled</p>
{{/if-flag}}
```

You can also use the `unless-flag` style block helper:

```hbs
{{#unless-flag ENABLE_FOO}}
<p>Foo is disabled</p>
<p>Foo is disabled</p>
{{else}}
<p>Foo is enabled! \o/</p>
<p>Foo is enabled! \o/</p>
{{/unless-flag}}
```

Expand All @@ -128,16 +134,16 @@ We use UglifyJS's `global_defs` feature to replace the value of feature flags wi

```javascript
if (ENABLE_FOO) {
this.route('foo');
console.log('The feature ENABLE_FOO is enabled in this environment');
this.route("foo");
console.log("The feature ENABLE_FOO is enabled in this environment");
}
```

will be represented in the production environment as the following if `ENABLE_FOO` is configured to be `true`:

```javascript
this.route('foo');
console.log('The feature ENABLE_FOO is enabled in this environment');
this.route("foo");
console.log("The feature ENABLE_FOO is enabled in this environment");
```

or the following if `ENABLE_FOO` is configured to be `false`;
Expand All @@ -151,9 +157,9 @@ out and remove impossible-to-reach sides of the condition:

```hbs
{{#if-flag ENABLE_FOO}}
<p>Foo is enabled</p>
<p>Foo is enabled</p>
{{else}}
<p>This won't be reached, because ENABLE_FOO is true</p>
<p>This won't be reached, because ENABLE_FOO is true</p>
{{/if-flag}}
```

Expand All @@ -167,11 +173,10 @@ This is really handy, since it vastly cuts down on the amount of precompiled
template code that your users need to download even though it'll never be
executed!


## Defining additional environments

By defining `ENV.featureFlagsEnvironment` you can separate your feature flags by more than just test/development/production, for example to have a beta environment that is identical to production but has a couple more flags activated. This only works if you have your flags in `config.featureFlags` - The `environment` passed in into the wrapper function will be `ENV.featureFlagsEnvironment` if set.

# Licence

This library is lovingly brought to you by the FreshBooks developers. We've released it under the MIT license.
This library is lovingly brought to you by the FreshBooks developers. We've released it under the MIT license.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ember-cli-conditional-compile",
"version": "1.2.0",
"version": "2.0.0",
"description": "Conditional compilation (feature-flags) for Ember apps",
"keywords": [
"ember-addon",
Expand Down

0 comments on commit 29b4874

Please sign in to comment.