Repository: ember-cli/ember-cli (js)

Issue:
[3.5.0] app.toTree not outputting broccoli-funnel anymore?
Here are the steps:
New project: `ember new xxx`
In project:
`npm i broccoli-funnel --save-dev`
`npm i moment-timezone --save`
Edit ember-cli-build.js:
`const Funnel = require('broccoli-funnel');`
...
```
  const momentTimezone = new Funnel('node_modules/moment-timezone/builds', {
    srcDir: '/',
    include: ['moment-timezone-with-data.min.js'],
    destDir: 'assets'
  });

  return app.toTree([momentTimezone]);
```
Build:
`ember b -dev`
Check dist folder:
![image](https://user-images.githubusercontent.com/3506166/46967096-68e5d580-d064-11e8-9821-d642a4d5d4d2.png)

No `moment-timezone-with-data.min.js`

I tried with other resources (jpegs, css, etc.), same deal.

---

Output from `ember version --verbose && npm --version && yarn --version`:
```
ember-cli: 3.5.0
http_parser: 2.8.0
node: 10.11.0
v8: 6.8.275.32-node.28
uv: 1.23.0
zlib: 1.2.11
ares: 1.14.0
modules: 64
nghttp2: 1.33.0
napi: 3
openssl: 1.1.0i
icu: 62.1
unicode: 11.0
cldr: 33.1
tz: 2018e
os: darwin x64
6.4.1
1.10.1
```


Pull request description:
[BUGFIX release] Fix toTree with custom paths. Closes #8128

Patch:
diff --git a/lib/broccoli/ember-app.js b/lib/broccoli/ember-app.js
index a12580cab..97587feb6 100644
--- a/lib/broccoli/ember-app.js
+++ b/lib/broccoli/ember-app.js
@@ -26,6 +26,7 @@ const ConfigReplace = require('broccoli-config-replace');
 const mergeTrees = require('./merge-trees');
 const WatchedDir = require('broccoli-source').WatchedDir;
 const UnwatchedDir = require('broccoli-source').UnwatchedDir;
+const BroccoliMergeTrees = require('broccoli-merge-trees');
 
 const merge = require('ember-cli-lodash-subset').merge;
 const defaultsDeep = require('ember-cli-lodash-subset').defaultsDeep;
@@ -1744,10 +1745,9 @@ class EmberApp {
    */
   toTree(additionalTrees) {
     let packagedTree;
-    let trees = this.toArray().concat(additionalTrees || []);
     let packageFn = this.options.package;
 
-    let fullTree = mergeTrees(trees, {
+    let fullTree = mergeTrees(this.toArray(), {
       overwrite: true,
       annotation: 'Full Application',
     });
@@ -1762,7 +1762,14 @@ class EmberApp {
       }
     }
 
-    return this.addonPostprocessTree('all', packagedTree || this._legacyPackage(fullTree));
+    if (!packagedTree) {
+      packagedTree = this._legacyPackage(fullTree);
+    }
+
+    let trees = [].concat(packagedTree, additionalTrees).filter(Boolean);
+    let combinedPackageTree = new BroccoliMergeTrees(trees);
+
+    return this.addonPostprocessTree('all', combinedPackageTree);
   }
 }
 


Test patch:
diff --git a/tests/acceptance/brocfile-smoke-test-slow.js b/tests/acceptance/brocfile-smoke-test-slow.js
index c9bd70ef2..9e23fc04b 100644
--- a/tests/acceptance/brocfile-smoke-test-slow.js
+++ b/tests/acceptance/brocfile-smoke-test-slow.js
@@ -406,4 +406,21 @@ describe('Acceptance: brocfile-smoke-test', function() {
         .to.equal('body { background: green; }\n');
     }));
   }
+
+  it('additional trees can be passed to the app', co.wrap(function *() {
+    yield copyFixtureFiles('brocfile-tests/additional-trees');
+    yield runCommand(path.join('.', 'node_modules', 'ember-cli', 'bin', 'ember'), 'build', { verbose: true });
+
+    let files = [
+      '/assets/custom-output-file.js',
+      '/assets/custom-output-file.css',
+      '/assets/vendor.css',
+      '/assets/vendor.js',
+    ];
+
+    let basePath = path.join(appRoot, 'dist');
+    files.forEach(function(f) {
+      expect(file(path.join(basePath, f))).to.exist;
+    });
+  }));
 });
diff --git a/tests/fixtures/brocfile-tests/additional-trees/ember-cli-build.js b/tests/fixtures/brocfile-tests/additional-trees/ember-cli-build.js
new file mode 100644
index 000000000..7b496cd57
--- /dev/null
+++ b/tests/fixtures/brocfile-tests/additional-trees/ember-cli-build.js
@@ -0,0 +1,13 @@
+const EmberApp = require('ember-cli/lib/broccoli/ember-app');
+const Funnel = require('broccoli-funnel');
+
+module.exports = function (defaults) {
+  let app = new EmberApp(defaults, {});
+
+  let funnel = new Funnel('vendor', {
+    srcDir: '/',
+    destDir: '/assets'
+  });
+
+  return app.toTree(funnel);
+};
diff --git a/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.css b/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.css
new file mode 100644
index 000000000..067dada53
--- /dev/null
+++ b/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.css
@@ -0,0 +1,3 @@
+body:after {
+  content: "hello from css custom output file"
+}
diff --git a/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.js b/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.js
new file mode 100644
index 000000000..20c572029
--- /dev/null
+++ b/tests/fixtures/brocfile-tests/additional-trees/vendor/custom-output-file.js
@@ -0,0 +1,1 @@
+console.log("hello from js custom output file");
diff --git a/tests/unit/broccoli/ember-app-test.js b/tests/unit/broccoli/ember-app-test.js
index 08a37dd19..1b6507e6f 100644
--- a/tests/unit/broccoli/ember-app-test.js
+++ b/tests/unit/broccoli/ember-app-test.js
@@ -15,6 +15,7 @@ const createTempDir = broccoliTestHelper.createTempDir;
 const MockCLI = require('../../helpers/mock-cli');
 const { isExperimentEnabled } = require('../../../lib/experiments');
 const mergeTrees = require('../../../lib/broccoli/merge-trees');
+const BroccoliMergeTrees = require('broccoli-merge-trees');
 
 let EmberApp = require('../../../lib/broccoli/ember-app');
 
@@ -989,9 +990,15 @@ describe('EmberApp', function() {
         app.toArray = td.function();
         app._legacyPackage = td.function();
 
-        td.when(app._legacyPackage(), { ignoreExtraArgs: true }).thenReturn('bar');
         td.when(app.toArray(), { ignoreExtraArgs: true }).thenReturn([]);
-        td.when(addon.postprocessTree('all', 'bar')).thenReturn('derp');
+        td.when(app._legacyPackage(), { ignoreExtraArgs: true }).thenReturn('bar');
+        td.when(
+          addon.postprocessTree(
+            'all',
+            td.matchers.argThat(t => t.constructor === BroccoliMergeTrees &&
+                                      t._inputNodes.length === 1 && t._inputNodes[0] === 'bar')
+          )
+        ).thenReturn('derp');
 
         expect(app.toTree()).to.equal('derp');
       });
@@ -1003,7 +1010,13 @@ describe('EmberApp', function() {
 
         td.when(app._legacyPackage(), { ignoreExtraArgs: true }).thenReturn('bar');
         td.when(app.toArray(), { ignoreExtraArgs: true }).thenReturn([]);
-        td.when(app.addonPostprocessTree('all', 'bar')).thenReturn('blap');
+        td.when(
+          app.addonPostprocessTree(
+            'all',
+            td.matchers.argThat(t => t.constructor === BroccoliMergeTrees &&
+                                      t._inputNodes.length === 1 && t._inputNodes[0] === 'bar')
+          )
+        ).thenReturn('blap');
 
         expect(app.toTree()).to.equal('blap');
       });