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 22, 2017
1 parent 12945fb commit 94ce290
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 26 deletions.
52 changes: 52 additions & 0 deletions README.md
Expand Up @@ -95,6 +95,58 @@ treeForAddon(tree) {
}
```

### Debug Tooling

In order to allow 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 (apps and/or addons) 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.

### 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
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
142 changes: 140 additions & 2 deletions node-tests/addon-test.js
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,6 +28,14 @@ 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);

Expand All @@ -33,8 +45,6 @@ describe('ember-cli-babel', function() {

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
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
39 changes: 15 additions & 24 deletions yarn.lock
Expand Up @@ -168,10 +168,6 @@ ast-types@0.8.12:
version "0.8.12"
resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc"

ast-types@0.8.15:
version "0.8.15"
resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52"

ast-types@0.9.6:
version "0.9.6"
resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
Expand Down Expand Up @@ -428,6 +424,12 @@ babel-plugin-dead-code-elimination@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65"

babel-plugin-debug-macros@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.6.tgz#6e0a29c6f3c3e122a8bd6fdb41fc2475d8f894ce"
dependencies:
semver "^5.3.0"

babel-plugin-eval@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da"
Expand Down Expand Up @@ -1395,6 +1397,12 @@ commander@2.9.0, commander@^2.5.0, commander@^2.6.0:
dependencies:
graceful-readlink ">= 1.0.0"

common-tags@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0"
dependencies:
babel-runtime "^6.18.0"

commoner@~0.10.3:
version "0.10.8"
resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5"
Expand Down Expand Up @@ -3807,22 +3815,14 @@ qs@6.4.0, qs@^6.2.0, qs@~6.4.0:
version "6.4.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"

quick-temp@0.1.6:
quick-temp@0.1.6, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5:
version "0.1.6"
resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307"
dependencies:
mktemp "~0.4.0"
rimraf "~2.2.6"
underscore.string "~2.3.3"

quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5:
version "0.1.8"
resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408"
dependencies:
mktemp "~0.4.0"
rimraf "^2.5.4"
underscore.string "~3.3.4"

qunit-notifications@^0.1.1:
version "0.1.1"
resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09"
Expand Down Expand Up @@ -3895,7 +3895,7 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"

recast@0.10.33:
recast@0.10.33, recast@^0.10.10:
version "0.10.33"
resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697"
dependencies:
Expand All @@ -3904,15 +3904,6 @@ recast@0.10.33:
private "~0.1.5"
source-map "~0.5.0"

recast@^0.10.10:
version "0.10.43"
resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f"
dependencies:
ast-types "0.8.15"
esprima-fb "~15001.1001.0-dev-harmony-fb"
private "~0.1.5"
source-map "~0.5.0"

recast@^0.11.17, recast@^0.11.3:
version "0.11.23"
resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
Expand Down Expand Up @@ -4633,7 +4624,7 @@ ultron@1.0.x:
version "1.0.2"
resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"

underscore.string@^3.2.2, underscore.string@~3.3.4:
underscore.string@^3.2.2:
version "3.3.4"
resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db"
dependencies:
Expand Down

0 comments on commit 94ce290

Please sign in to comment.