Repository: ember-cli/ember-cli
Pull request #7692 (2018-03-20 22:11:12)

[BUGFIX release] Ensure config() memoizing is considers if the
configPath has changed as part of its cache key.

For addons, we end up hot-swapping configPath. Although this isn't a
great idea, it turns out we relied on it working.

Offending code:
https://github.com/ember-cli/ember-cli/blob/6a1f80efe39f3e87533cfd0ef062ef42cd5899a5/lib/broccoli/ember-app.js#L201-L203

Future config related work should likely tidy this up...


Patch:
diff --git a/lib/models/project.js b/lib/models/project.js
index 6f5f2daa7..4e2033145 100644
--- a/lib/models/project.js
+++ b/lib/models/project.js
@@ -229,12 +229,13 @@ class Project {
     @return {Object}     Merged confiration object
    */
   config(env) {
-    let c = this.configCache.get(env);
-    if (c === undefined) {
-      c = this.configWithoutCache(env);
-      this.configCache.set(env, c);
+    let key = `${this.configPath()}|${env}`;
+    let config = this.configCache.get(key);
+    if (config === undefined) {
+      config = this.configWithoutCache(env);
+      this.configCache.set(key, config);
     }
-    return _.cloneDeep(c);
+    return _.cloneDeep(config);
   }
 
   /**


Test patch:
diff --git a/tests/unit/models/project-test.js b/tests/unit/models/project-test.js
index 0331be5dc..8d028a241 100644
--- a/tests/unit/models/project-test.js
+++ b/tests/unit/models/project-test.js
@@ -49,9 +49,9 @@ describe('models/project.js', function() {
 
   describe('Project.prototype.config', function() {
     let called;
+    projectPath = 'tmp/test-app';
 
     beforeEach(function() {
-      projectPath = 'tmp/test-app';
       called = false;
       return tmp.setup(projectPath)
         .then(function() {
@@ -59,7 +59,16 @@ describe('models/project.js', function() {
             baseURL: '/foo/bar',
           });
 
+          touch(`${projectPath}/config/a.js`, {
+            baseURL: '/a',
+          });
+
+          touch(`${projectPath}/config/b.js`, {
+            baseURL: '/b',
+          });
+
           makeProject();
+
           let discoverFromCli = td.replace(project.addonDiscovery, 'discoverFromCli');
           td.when(discoverFromCli(), { ignoreExtraArgs: true }).thenReturn([]);
           project.require = function() {
@@ -79,6 +88,41 @@ describe('models/project.js', function() {
       expect(called).to.equal(true);
     });
 
+    describe('memoizes', function() {
+      it('memoizes', function() {
+        project.config('development');
+        expect(called).to.equal(true);
+        called = false;
+        project.config('development');
+        expect(called).to.equal(false);
+      });
+
+      it('considers configPath when memoizing', function() {
+        project.configPath = function() { return `${projectPath}/config/a`; };
+        project.config('development');
+
+        expect(called).to.equal(true);
+        called = false;
+
+        project.configPath = function() { return `${projectPath}/config/a`; };
+        project.config('development');
+
+        expect(called).to.equal(false);
+        called = false;
+
+        project.configPath = function() { return `${projectPath}/config/b`; };
+        project.config('development');
+
+        expect(called).to.equal(true);
+        called = false;
+
+        project.config('development');
+
+        expect(called).to.equal(false);
+        called = false;
+      });
+    });
+
     it('configPath() returns tests/dummy/config/environment', function() {
       project.pkg = {
         'ember-addon': {