Skip to content

Commit

Permalink
Add debug tooling babel plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
rwjblue committed Apr 27, 2017
1 parent 12945fb commit bf1c6b5
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 27 deletions.
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,77 @@ treeForAddon(tree) {
}
```

### Debug Tooling

In order to allow apps and addons to easily provide good development mode ergonomics (assertions, deprecations, etc) but
still perform well in production mode ember-cli-babel automatically manages stripping / removing certain debug
statements. This concept was originally proposed in [ember-cli/rfcs#50](https://github.com/ember-cli/rfcs/pull/50),
but has been slightly modified during implementation (after researching what works well and what does not).

#### Debug Macros

To add convienient deprecations and assertions, consumers (in either an app or an addon) can do the following:

```js
import { deprecate, assert } from '@ember/debug';

export default Ember.Component.extend({
init() {
this._super(...arguments);
deprecate(
'Passing a string value or the `sauce` parameter is deprecated, please pass an instance of Sauce instead',
false,
{ until: '1.0.0', id: 'some-addon-sauce' }
);
assert('You must provide sauce for x-awesome.', this.sauce);
}
})
```

In testing and development environments those statements will be executed (and assert or deprecate as appropriate), but
in production builds they will be inert (and stripped during minification).

#### General Purpose Env Flags

In some cases you may have the need to do things in debug builds that isn't related to asserts/deprecations/etc. For
example, you may expose certain API's for debugging only. You can do that via the `DEBUG` environment flag:

```js
import { DEBUG } from '@glimmer/env';

const Component = Ember.Component.extend();

if (DEBUG) {
Component.reopen({
specialMethodForDebugging() {
// do things ;)
}
});
}
```

In testing and development environments `DEBUG` will be replaced by the boolean literal `true`, and in production builds it will be
replaced by `false`. When ran through a minifier (with dead code elimination) the entire section will be stripped.

#### Disabling Debug Tooling Support

If for some reason you need to disable this debug tooling, you can opt-out via configuration.

In an app that would look like:

```js
// ember-cli-build.js
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
'ember-cli-babel': {
disableDebugTooling: true
}
});

return app.toTree();
}
```

### About Modules

Older versions of Ember CLI (`< 2.12`) use its own ES6 module transpiler. Because of that, this plugin disables Babel
Expand Down
27 changes: 27 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ module.exports = {

options.plugins = [].concat(
userPlugins,
this._getDebugMacroPlugins(config),
shouldCompileModules && this._getModulesPlugin(),
this._getPresetEnvPlugins(addonProvidedConfig),
userPostTransformPlugins
Expand All @@ -191,6 +192,32 @@ module.exports = {
return options;
},

_getDebugMacroPlugins(config) {
let addonOptions = config['ember-cli-babel'] || {};

if (addonOptions.disableDebugTooling) { return; }

const DebugMacros = require('babel-plugin-debug-macros').default;
const isProduction = process.env.EMBER_ENV === 'production';

let options = {
envFlags: {
source: '@glimmer/env',
flags: { DEBUG: !isProduction, CI: !!process.env.CI }
},

externalizeHelpers: {
global: 'Ember'
},

debugTools: {
source: '@ember/debug'
}
};

return [[DebugMacros, options]];
},

_getPresetEnvPlugins(config) {
let options = config.options;

Expand Down
144 changes: 141 additions & 3 deletions node-tests/addon-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ const CoreObject = require('core-object');
const AddonMixin = require('../index');
const path = require('path');
const resolve = require('resolve');
const CommonTags = require('common-tags');
const stripIndent = CommonTags.stripIndent;
const BroccoliTestHelper = require('broccoli-test-helper');
const createBuilder = BroccoliTestHelper.createBuilder;
const createTempDir = BroccoliTestHelper.createTempDir;

let Addon = CoreObject.extend(AddonMixin);

describe('ember-cli-babel', function() {
const ORIGINAL_EMBER_ENV = process.env.EMBER_ENV;

beforeEach(function() {
this.ui = new MockUI();
let project = { root: __dirname };
Expand All @@ -24,17 +28,23 @@ describe('ember-cli-babel', function() {
});
});

afterEach(function() {
if (ORIGINAL_EMBER_ENV === undefined) {
delete process.env.EMBER_ENV;
} else {
process.env.EMBER_ENV = ORIGINAL_EMBER_ENV;
}
});

describe('transpileTree', function() {
this.timeout(50000);
this.timeout(100000);

let input;
let output;
let subject;

beforeEach(co.wrap(function* () {
input = yield createTempDir();
subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);
}));

afterEach(co.wrap(function* () {
Expand All @@ -48,6 +58,9 @@ describe('ember-cli-babel', function() {
"bar.js": `let bar = () => {};`
});

subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);

yield output.build();

expect(
Expand All @@ -57,6 +70,131 @@ describe('ember-cli-babel', function() {
"foo.js": `var foo = function foo() {};`,
});
}));

describe('debug macros', function() {
it("can opt-out via ember-cli-babel.disableDebugTooling", co.wrap(function* () {
process.env.EMBER_ENV = 'development';

let contents = stripIndent`
import { DEBUG } from '@glimmer/env';
if (DEBUG) {
console.log('debug mode!');
}
`;

input.write({
"foo.js": contents
});

subject = this.addon.transpileTree(input.path(), {
'ember-cli-babel': {
disableDebugTooling: true
}
});

output = createBuilder(subject);

yield output.build();

expect(
output.read()
).to.deep.equal({
"foo.js": contents
});
}));

describe('in development', function() {
it("should replace env flags by default ", co.wrap(function* () {
process.env.EMBER_ENV = 'development';

input.write({
"foo.js": stripIndent`
import { DEBUG } from '@glimmer/env';
if (DEBUG) { console.log('debug mode!'); }
`
});

subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);

yield output.build();

expect(
output.read()
).to.deep.equal({
"foo.js": `\nif (true) {\n console.log('debug mode!');\n}`
});
}));

it("should replace debug macros by default ", co.wrap(function* () {
process.env.EMBER_ENV = 'development';

input.write({
"foo.js": stripIndent`
import { assert } from '@ember/debug';
assert('stuff here', isNotBad());
`
});

subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);

yield output.build();

expect(
output.read()
).to.deep.equal({
"foo.js": `(true && Ember.assert('stuff here', isNotBad()));`
});
}));
});

describe('in production', function() {
it("should replace env flags by default ", co.wrap(function* () {
process.env.EMBER_ENV = 'production';

input.write({
"foo.js": stripIndent`
import { DEBUG } from '@glimmer/env';
if (DEBUG) { console.log('debug mode!'); }
`
});

subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);

yield output.build();

expect(
output.read()
).to.deep.equal({
"foo.js": `\nif (false) {\n console.log('debug mode!');\n}`
});
}));

it("should replace debug macros by default ", co.wrap(function* () {
process.env.EMBER_ENV = 'production';

input.write({
"foo.js": stripIndent`
import { assert } from '@ember/debug';
assert('stuff here', isNotBad());
`
});

subject = this.addon.transpileTree(input.path());
output = createBuilder(subject);

yield output.build();

expect(
output.read()
).to.deep.equal({
"foo.js": `(false && Ember.assert('stuff here', isNotBad()));`
});
}));
});
});
});

describe('_getAddonOptions', function() {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"amd-name-resolver": "0.0.6",
"babel-plugin-debug-macros": "^0.1.6",
"babel-plugin-transform-es2015-modules-amd": "^6.24.0",
"babel-polyfill": "^6.16.0",
"babel-preset-env": "^1.2.0",
Expand All @@ -49,6 +50,7 @@
"broccoli-test-helper": "^1.1.0",
"chai": "^3.5.0",
"co": "^4.6.0",
"common-tags": "^1.4.0",
"console-ui": "^1.0.2",
"core-object": "^2.0.6",
"ember-cli": "^2.6.2",
Expand Down
Loading

0 comments on commit bf1c6b5

Please sign in to comment.