Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent running babel twice. #6530

Merged
merged 6 commits into from Dec 7, 2016
Merged

Prevent running babel twice. #6530

merged 6 commits into from Dec 7, 2016

Conversation

rwjblue
Copy link
Member

@rwjblue rwjblue commented Dec 5, 2016

We currently transpile the output of all addon's addon/ trees twice. Once inside the addon's treeForAddon step (this one excludes module transpilation by adding es6.modules to babel's blacklist) and the second time in lib/broccoli/ember-app.js.

This was originally done because we didn't require that addon's include their own preprocessors for JS (mostly due to performance reasons IIRC). In the time since that decision was made, we have swapped from a few different systems es6-module-transpiler -> esperanto -> babel. Now that our module transpilation step is using the same thing as we recommend addon's use (ember-cli-babel) what we are doing seems pretty whacky.

This PR removes the double processing of addon's addon/ files through babel, and includes a deprecation message for the scenario that originally prompted the second pass (where an addon didn't include a module transpiling preprocessor).

TODO:

  • Confirm that we have tests that already confirm this is working properly (I believe that our existing nested addon tests cover these changes, but I'd like to confirm).
  • Consider / discuss backporting the deprecation message for addons that do not have a transpiler and are relying on the global processing step.
  • Add helpful error if an addon overrides this.options.babel.compileModules
  • Implement logic to avoid deprecation being added in Move custom options to "ember-cli-babel" options hash emberjs/ember-cli-babel#105.
  • Split out findAddonByName into a utility method to be shared
  • r?

Addresses parts of #5015


this.options = defaultsDeep(this.options, {
babel: {
// TODO: coordinate with @turbo87 on exactly how to do
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @Turbo87

@@ -797,16 +831,23 @@ var Addon = CoreObject.extend({
compileAddon: function(tree) {
this._requireBuildPackages();

var reexported;
if (!this.options.babel.compileModules) {
throw new Error('y u clobber!?!!?!');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this before landing, was using it as a debugging tool

if (!registryHasAddon(this.registry, 'ember-cli-babel')) {
this._warn('Addon files were detected in `' + this._treePathFor('addon') + '`, but `ember-cli-babel` ' +
'is not present as a dependency in `' + this.name + '`. ' +
'Please make sure to add `ember-cli-babel`) ' +
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird ) mid-sentence here

@rwjblue rwjblue force-pushed the avoid-two-pass-babel branch 3 times, most recently from 9098cc5 to 69f4b5d Compare December 6, 2016 04:15
This moves the modules transpilation step to be done completely by
`lib/models/addon.js`, and does not leave additional steps left to
be done by `lib/broccoli/ember-app.js`.
Template preprocessors emit ES modules, and once the two pass babel
transpilation is removed we need to ensure templates get ES -> AMD
processing.
Prior to the changes in this PR, all addon/ files were processed by babel
twice (once by the addon itself excluding modules, then again by ember-cli
including modules). This meant it was possible to "forget" to include
an ember-cli-babel dep when you really needed one (because you have JS files
in `addon/`).
Newer versions of ember-cli-babel will begin deprecating passing
any options in `babel` config hash that are not destined for `babel`
itself (this includes `compileModules` and `includePolyfill`).

This detects the newer version and uses the appropriate (non-deprecated)
configuration property.

It also moves `findAddonByName` into a shared utility method (to ensure
both project and addon use the same mechanism).
srcDir: 'modules',
allowEmpty: true,
annotation: 'Funnel: Addon JS'
});

var transpiledAddonTree = new Babel(addonES6, this._prunedBabelOptions());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

var transpiledAddonTree = new Babel(addonES6, this._prunedBabelOptions());
var trees = [ transpiledAddonTree ];

var reexportsAndTranspiledAddonTree = mergeTrees(trees, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:🔥

this._warn('Addon files were detected in `' + this._treePathFor('addon') + '`, but no JavaScript ' +
'preprocessors were found for `' + this.name + '`. Please make sure to add a preprocessor ' +
'(most likely `ember-cli-babel`) to in `dependencies` (NOT `devDependencies`) in ' +
'`' + this.name + '`\'s `package.json`.');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as it may be possible to have more then 1 addon by this name, should we also print its path on disk?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The full path absolute path to the addon's addon/ directory is printed in this message, so I don't think changes are needed in this one for that purpose...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return new Babel(tree, {
modules: 'amdStrict',
moduleIds: true,
whitelist: ['es6.modules']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to provide the amd-name-resolver? As this doesn't seem to get the config from 146

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirm, will update

// if used in the older way
//
// see: https://github.com/babel/ember-cli-babel/pull/105
var emberCLIBabelInstance = findAddonByName(this.addons, 'ember-cli-babel');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be reason to add this.findOwnAddonByName('ember-cli-babel') as an API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but I wanted to decouple new public API's from this PR.

Technically, project.findAddonByName is also private (per YUIDocs IIRC), I'd suggest a future RFC to make that method public on both Project and Addon.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds very reasonable.

@@ -730,7 +777,7 @@ var Addon = CoreObject.extend({
if (addonTemplates) {
standardTemplates = new Funnel(addonTemplates, {
srcDir: '/',
destDir: 'modules/' + this.name + '/templates'
destDir: this.name + '/templates'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanhammond mentioned some add-ons accidentally depend on this, we should likely see if any very popular ones absolutely do. And inform said authors to address.

Copy link
Member Author

@rwjblue rwjblue Dec 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stefanpenner - The modules/ funneling is done a tad bit later (at the end of compileAddon method). In this case, we need the paths on disk to match what we expect the named AMD moduleIds will be.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done around L865 in this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both ember-a11y and liquid-fire depend on this

if (!this.options[emberCLIBabelConfigKey].compileModules) {
throw new SilentError(
'Ember CLI addons manage their own module transpilation during the `treeForAddon` processing. ' +
'`' + this.name + '` has overridden the `this.options.' + emberCLIBabelConfigKey + '.compileModules` ' +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as there may be more then one addon by this name in node_modules, should we print out its whole path?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, will do

* Use amd-name-resolver for modules only transpilation.
* Share babel config between modules only transpilation and default
  babel config.
* Add path to addon in error message (in case multiple share the same
  addon name).
@rwjblue
Copy link
Member Author

rwjblue commented Dec 6, 2016

Updated from initial round of review...

}

function registryHasPreprocessor(registry, type) {
return !!registry.load(type).length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will return registry.load(type).length > 0 be clearer and easier to parse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good idea!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

@@ -730,7 +777,7 @@ var Addon = CoreObject.extend({
if (addonTemplates) {
standardTemplates = new Funnel(addonTemplates, {
srcDir: '/',
destDir: 'modules/' + this.name + '/templates'
destDir: this.name + '/templates'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both ember-a11y and liquid-fire depend on this

@rwjblue
Copy link
Member Author

rwjblue commented Dec 6, 2016

@twokul - RE:

I think both ember-a11y and liquid-fire depend on this

Yes, modules/ shifting isn't removed here, just moved around (now its done at the very end of compileAddon (called from treeForAddon). There should be no semantic change here...

@Turbo87 Turbo87 added the bug label Dec 7, 2016
@rwjblue
Copy link
Member Author

rwjblue commented Dec 7, 2016

@homu r+

@homu
Copy link
Contributor

homu commented Dec 7, 2016

📌 Commit f2e7c3e has been approved by rwjblue

@homu
Copy link
Contributor

homu commented Dec 7, 2016

⚡ Test exempted - status

@homu homu merged commit f2e7c3e into master Dec 7, 2016
homu added a commit that referenced this pull request Dec 7, 2016
Prevent running babel twice.

We currently transpile the output of all addon's `addon/` trees twice.  Once inside the addon's `treeForAddon` step (this one excludes module transpilation by adding `es6.modules` to babel's blacklist) and the second time in [lib/broccoli/ember-app.js](https://github.com/ember-cli/ember-cli/blob/2df251ce018fd12570bdce72c167ff14a427fa74/lib/broccoli/ember-app.js#L929).

This was originally done because we didn't require that addon's include their own preprocessors for JS (mostly due to performance reasons IIRC).  In the time since that decision was made, we have swapped from a few different systems `es6-module-transpiler` -> `esperanto` -> `babel`.  Now that our module transpilation step is using the same thing as we recommend addon's use (`ember-cli-babel`) what we are doing seems pretty whacky.

This PR removes the double processing of addon's `addon/` files through babel, and includes a deprecation message for the scenario that originally prompted the second pass (where an addon didn't include a module transpiling preprocessor).

TODO:

- [x] Confirm that we have tests that already confirm this is working properly (I believe that our existing nested addon tests cover these changes, but I'd like to confirm).
- [ ] Consider / discuss backporting the deprecation message for addons that do not have a transpiler and are relying on the global processing step.
- [X] Add helpful error if an addon overrides `this.options.babel.compileModules`
- [X] Implement logic to avoid deprecation being added in emberjs/ember-cli-babel#105.
- [X] Split out `findAddonByName` into a utility method to be shared
- [ ] r?

Addresses parts of #5015
@Turbo87 Turbo87 deleted the avoid-two-pass-babel branch December 7, 2016 17:08
homu added a commit that referenced this pull request Dec 7, 2016
…jblue

Fixups for recent two pass babel changes.

We started testing out master in a very large app at work, and ran into a few small issues with the changes in #6530.

This PR makes the following changes:

* Makes the warnings much more useful (and prevents an error that was occurring just when reading config to determine if we should warn).
* Cherry pick change from #6480, as it is now manifesting (due to internal changes in `modules/` shimming, the `overwrite` that was happening at a later stage, is now happening in `compileAddon`).
* Ensure a full pass of babel transpilation is done in the fallback case (when an addon with `addon/**/*.js` files has no JS preprocessors). This is required due to the way the migration from esperanto to babel occurred where the second pass (that was intended for only modules transpilation) was actually implemented as a full babel transpile step.
@mfazekas
Copy link

@rwjblue the issue with ember-lodash seems to be the condition added in the PR:

if (this._fileSystemInfo().hasJSFiles) {
      var processedJsFiles = this.preprocessJs(this.addonJsFiles(tree), '/', this.name, {
       ...
}

ember-lodash itself has no JSFiles, but it's generating it's tree from .js files in other modules -
see
https://github.com/mike-north/ember-lodash/blob/master/index.js#L15

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants