Ei pessoal,
Tenho algumas novas informações para vocês e encontrei uma solução para esse problema.
Então, hoje estive investigando novamente esse bug e acho que descobri mais detalhes.
Ao examinar o arquivo cmp2ui-fr.js do Quantcast, consegui identificar onde o bug ocorre, que está nesta função (temos apenas a versão minificada):
function(t){for(var n in t){t[n].status=e;}}
Como vocês podem ver, essa função usa um for..in, e a variável t é um array. Já explicamos isso anteriormente: o Ember.js estende o Array nativo do JavaScript. Parece que uma das modificações é a adição de uma entrada _super.
A entrada _super aponta para uma função ROOT(), que parece referenciar _utils.ROOT no Ember.js (talvez isso soe familiar para alguns de vocês, mas não para mim ^^). Essa função ROOT() não é extensível.
Aparentemente, essa propriedade _super é considerada enumerable, o que significa que, ao usar um loop for..in em um array, a entrada _super é tratada como uma entrada “normal” (diferente, por exemplo, de values, bind, valueOf, basicamente todas as funções de um objeto Array).
Acho que isso é um bug do Ember.js e não um comportamento desejável.
Consegui tornar o bug altamente reprodutível. Para isso, basta criar um array de objetos, assim:
var objs = [{'key':'val'},{'key':'val'}];
Em seguida, crie uma função usando strict mode, iterando sobre um array e definindo uma nova propriedade para cada entrada:
var tst_func = function (objs){'use strict';for(var i in objs){objs[i].newproperty = true }};
Por fim, basta chamar essa função no array de objetos:
tst_func(objs);
Você deve receber um erro: Uncaught TypeError: can't define property "newproperty": Function is not extensible.
Analisando isso, acredito que o bug provavelmente já existe em produção e não é específico do Quantcast. Basicamente, qualquer pessoa que tente usar for..in se expõe a comportamentos inconsistentes ou bugs críticos.
Na minha opinião, isso não é responsabilidade direta do Discourse ou do Quantcast, mas claramente do Ember.js. No entanto, isso não muda o fato de que precisamos encontrar uma solução enquanto o bug não for corrigido no Ember.js ^^.
A boa notícia é que acho que encontrei uma maneira de corrigir isso.
Uma maneira é adicionar uma linha if (!objs.hasOwnProperty(i)) {continue}; em todos os loops for..in (provavelmente também em forEach, for...of, etc.). Isso não modifica o comportamento estranho do _super do Array, mas impede localmente o acesso a ele. Obviamente, isso significa que não funciona para qualquer script externo que não temos controle, como no meu caso específico do uso do Quantcast.
Outra maneira, que acredito ser o caminho a seguir, é modificar o protótipo do Array do JavaScript (então, basicamente, sobrescrevemos a própria sobrescrita do Ember.js ^^) para tornar _super não enumerável. Para isso, precisamos executar essa linha de JavaScript DEPOIS que o Ember.js for chamado e avaliado:
//Tornar _super não enumerável para evitar bugs entre Ember.js e for..in
Object.defineProperty(Array.prototype, '_super', {'enumerable': false});
A segunda opção mantém a possibilidade de uso direto de _super, conforme deveria ser, e impede que ele apareça nos loops. No entanto, não posso garantir que esse comportamento estranho não seja utilizado por nenhuma função interna do Ember.js ou plugin externo.
Examinando o arquivo _ember_jquery-189e46ebcb33594b835e782fd1ce916ec750bc0cf980ebc4fb7796649161a18d.js, vi algumas linhas específicas do Discourse, como:
var ALIASES = {
"ember-addons/ember-computed-decorators":
"discourse-common/utils/decorators",
"discourse/lib/raw-templates": "discourse-common/lib/raw-templates",
"preload-store": "discourse/lib/preload-store",
"fixtures/user_fixtures": "discourse/tests/fixtures/user-fixtures",
};
var ALIAS_PREPEND = {
fixtures: "discourse/tests/",
helpers: "discourse/tests/",
};
Talvez pudéssemos adicionar nossa linha Object.defineProperty(Array.prototype, '_super', {'enumerable': false}); aqui?
No momento, corrigi o bug adicionando as linhas:
//Tornar _super não enumerável para evitar bugs entre Ember.js e for..in
Object.defineProperty(Array.prototype, ‘_super’, {‘enumerable’: false});
Antes de chamar o script choice.js do Quantcast.
Acho que alguém pode corrigir o bug localmente criando um arquivo ‘fix_ember.js’ com essas duas linhas, servindo-o estáticamente pelo proxy reverso (por exemplo, Nginx), e adicionando uma linha <script src="/fix_emmber.js"></script> no rodapé do tema usando personalização. Escrever o script diretamente em vez de criar um link não funciona por causa da extração de scripts do Discourse (veja Custom javascript in <head> disappear).
Espero que este tópico ajude outros. Vou abrir um ticket no Ember.js amanhã para verificar se isso é um bug ou um comportamento muito estranho, mas intencional.
Vou mantê-los informados para ver se precisamos incluir uma correção no Discourse.
PS: Muitos agradecimentos a Angus Croll de Extending JavaScript Natives – JavaScript, JavaScript…, seu post me ajudou muito!