Skip to content

Commit

Permalink
Merge pull request #121 from ember-cli/define-exports
Browse files Browse the repository at this point in the history
add define.exports
  • Loading branch information
stefanpenner committed Jun 15, 2017
2 parents 804f111 + d963886 commit f62bc54
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 0 deletions.
71 changes: 71 additions & 0 deletions README.md
Expand Up @@ -17,6 +17,77 @@ loader.noConflict({
});
```

## Extra stuff

### `define.alias('new-name', 'old/path')`

`define.alias` allows creation of a symlink from one module to another, for example:

```js
define('foo/bar/baz', [], () => 'hi');
define.alias('foo', 'foo/bar/baz');

require('foo') // => 'hi';
require('foo') === require('foo/bar/baz');
```

### `define.exports('foo', {})`

`define.exports` enables a fastpath for non-lazy dependency-less modules, for example:

Rather then:

```js
define("my-foo-app/templates/application", ["exports"], function (exports) {
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});

exports.default = Ember.HTMLBars.template({ "id": "VVZNWoRm", "block": "{\"statements\":[[1,[26,[\"welcome-page\"]],false],[0,\"\\n\"],[0,\"\\n\"],[1,[26,[\"outlet\"]],false]],\"locals\":[],\"named\":[],\"yields\":[],\"hasPartials\":false}", "meta": { "moduleName": "my-foo-app/templates/application.hbs" } });
});
```

We can author:

```js
define.exports('my-app/template/apple', { hbs: true, "id": "VVZNWoRm", "block": "{\"statements\":[[1,[26,[\"welcome-page\"]],false],[0,\"\\n\"],[0,\"\\n\"],[1,[26,[\"outlet\"]],false]],\"locals\":[],\"named\":[],\"yields\":[],\"hasPartials\":false}", "meta": { "moduleName": "my-foo-app/templates/application.hbs" }});
```

benefits:

* less bytes
* no reification step
* no need to juggle pre-parse voodoo.

### `require.unsee('foo');`

`require.unsee` allows one to unload a given module. *note* The side-effects of that module cannot be unloaded.
This is quite useful, especially for test suites. Being able to unload run tests, mitigates many common memory leaks:

example:

```js
define('my-app/tests/foo-test.js', ['qunit'], function(qunit) {
let app;

qunit.module('my module', {
beforeEach() {
app = new App();
}

// forgot to `null` out app in the afterEach
});

test('my app exists', function(assert) {
assert.ok(app);
})
})
```

---

Note: To be able to take advantage of alternate `define` method name, you will also need to ensure that your
build tooling generates using the alternate. An example of this is done in the [emberjs-build](https://github.com/emberjs/emberjs-build)
project in the [babel-enifed-module-formatter plugin](https://github.com/emberjs/emberjs-build/blob/v0.4.2/lib/utils/babel-enifed-module-formatter.js).
Expand Down
16 changes: 16 additions & 0 deletions benchmarks/scenarios/define-many-exports.js
@@ -0,0 +1,16 @@
this.heimdall = global.heimdall = require('heimdalljs');
var loader = require('../loader');
var measure = require('../handler').measure;

module.exports = function() {
return measure(function() {
loader.define('foo' + -1, function() {});
for (var i = 0; i < 1000; i++) {
loader.define.exports('foo' + i, {hbs: true, "id": "VVZNWoRm", "block": "{\"statements\":[[1,[26,[\"welcome-page\"]],false],[0,\"\\n\"],[0,\"\\n\"],[1,[26,[\"outlet\"]],false]],\"locals\":[],\"named\":[],\"yields\":[],\"hasPartials\":false}", "meta": { "moduleName": "my-foo-app/templates/application.hbs" }});
}

for (var i = 0; i < 1000; i++) {
loader.require('foo' + i);
}
});
};
32 changes: 32 additions & 0 deletions benchmarks/scenarios/define-many.js
@@ -0,0 +1,32 @@
this.heimdall = global.heimdall = require('heimdalljs');
var loader = require('../loader');
var measure = require('../handler').measure;

module.exports = function() {
return measure(function() {
var Ember = {
HTMLBars: {
template: function(stuff) {

}
}
};

loader.define('foo' + -1, function() {});
for (var i = 0; i < 1000; i++) {
loader.define('foo' + i, ['exports'], function() {
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});

exports.default = Ember.HTMLBars.template({ "id": "VVZNWoRm", "block": "{\"statements\":[[1,[26,[\"welcome-page\"]],false],[0,\"\\n\"],[0,\"\\n\"],[1,[26,[\"outlet\"]],false]],\"locals\":[],\"named\":[],\"yields\":[],\"hasPartials\":false}", "meta": { "moduleName": "my-foo-app/templates/application.hbs" } });
});
}

for (var i = 0; i < 1000; i++) {
loader.require('foo' + i);
}
});
};
22 changes: 22 additions & 0 deletions lib/loader/loader.js
Expand Up @@ -237,6 +237,26 @@ var loader, define, requireModule, require, requirejs;
heimdall.stop(token);
};

define.exports = function(name, defaultExport) {
var module = registry[name];

// If a module for this name has already been defined and is in any state
// other than `new` (meaning it has been or is currently being required),
// then we return early to avoid redefinition.
if (module && module.state !== 'new') {
return;
}

module = new Module(name, [], noop, null);
module.module.exports = defaultExport;
module.state = 'finalized';
registry[name] = module;

return module;

};

function noop() { }
// we don't support all of AMD
// define.amd = {};

Expand Down Expand Up @@ -328,7 +348,9 @@ var loader, define, requireModule, require, requirejs;
define.alias('foo', 'foo/qux');
define('foo/bar', ['foo', './quz', './baz', './asdf', './bar', '../foo'], function() {});
define('foo/main', ['foo/bar'], function() {});
define.exports('foo/exports', {});

require('foo/exports');
require('foo/main');
require.unsee('foo/bar');

Expand Down
6 changes: 6 additions & 0 deletions tests/all.js
Expand Up @@ -1663,3 +1663,9 @@ test('redefining a module when "finalized" should no-op', function(assert) {
require('foo');
assert.notOk(second, 'second module definition never used');
});

test('define.exports', function(assert) {
var defaultExport = { example: 'export' };
define.exports('foo/bar', defaultExport);
assert.equal(require('foo/bar'), defaultExport);
});

0 comments on commit f62bc54

Please sign in to comment.