Queremos atualizar a versão do Ember usada no Discourse.
No momento, estamos na versão 3.15, e gostaríamos de chegar à 4.1.
Definimos como meta concluir esse trabalho até o final deste ano. Por favor, note que este tópico é um roteiro (roadmap), e todos os planos e estimativas são provisórios. Este tópico não tem a intenção de abrigar discussões significativas sobre upgrades ou mudanças específicas. Então, vamos manter a conversa aqui um pouco focada. Perguntas sobre como essas atualizações afetarão seu site/plugin/tema estão fora do assunto. As mudanças planejadas são 100% no front-end (app Ember).
Vamos ser muito cuidadosos com as mudanças que introduzirmos. Todos os plugins/temas oficiais serão atualizados (incluindo qualquer trabalho personalizado que a CDCK tenha feito para seus clientes). Também enviaremos PRs para atualizar todos os plugins/temas não oficiais populares.
Não se preocupe se você tiver um plugin/tema personalizado que construiu para seu site. Adicionaremos avisos de depreciação e faremos os anúncios necessários em tempo hábil para lhe dar tempo suficiente para fazer as mudanças necessárias. Também tentaremos guiá-lo por essas mudanças, se necessário.
Vamos começar com as metas. Obviamente, queremos chegar à versão mais alta disponível, mas precisamos definir metas intermediárias entre agora e nosso destino final.
Planejamos fazer atualizações incrementais. Em vez de uma grande atualização para a 4.1, vamos dividir esse trabalho em seis etapas. Cada etapa foca em uma atualização do Ember.
| Etapa | Tamanho | Atualizações |
|---|---|---|
| 1 | size-l | Ember 3.15 → Ember 3.16 |
| 2 | size-m | Ember 3.16 → Ember 3.25 |
| 3 | size-xl | Ember 3.25 → Ember 3.26 (Parte 1 - Geral) Ember 3.25 → Ember 3.26 (Parte 2 - Templates) Ember 3.25 → Ember 3.26 (Parte 3 - jQuery) Ember 3.25 → Ember 3.26 (Parte 4 - Preparação para Octane) Ember 3.25 → Ember 3.26 (Parte 5 - Octane) |
| 4 | size-l | Ember 3.26 → Ember 3.27 (Parte 1 - Geral) Ember 3.26 → Ember 3.27 (Parte 2 - RenderTemplate) Ember 3.26 → Ember 3.27 (Parte 3 - Componentes embutidos legados) |
| 5 | size-s | Ember 3.27 → Ember 3.28 |
| 6 | size-s | Ember 3.28 → Ember 4.1 |
A escolha dessas versões específicas é baseada inteiramente nas depreciações e na quantidade de trabalho que elas introduzem - e no risco implícito.
Então, vamos detalhar ainda mais para maior clareza.
Depreciações por atualização
Etapa 1 (size-l)
Ember 3.15 → Ember 3.16
Esta atualização introduz apenas uma depreciação.
-
Use o resolver do ember-CLI em vez do resolver global legado
- até: 4.0.0 - size-lO Discourse tem seu próprio resolver personalizado que atualmente estende
Ember.DefaultResolver.A correção recomendada é eliminar qualquer resolver personalizado e usar o resolver do Ember-CLI. É mais fácil dizer do que fazer, pois temos bastante lógica personalizada para lidar com plugins e temas.
Um compromisso que funciona é estender o resolver do Ember-CLI em vez de estender
Ember.DefaultResolver.
Etapa 2 (size-m)
Ember 3.16 → Ember 3.25
Esta atualização introduz oito depreciações.
-
Use getter do Ember e verifique explicitamente por undefined
- até: 4.0.0 - size-sEsta é uma depreciação simples. Precisamos apenas removergetWithDefaultem nossa base de código, e há apenas alguns lugares onde o usamos. -
Extensões de protótipo de String
- até: 4.0.0 - size-mEsta também é uma troca simples e de baixo risco, mas usamos o protótipo de string estendido do Ember em vários lugares. Por uma verificação rápida, acho que temos cerca de < 100 lugares onde fazemos isso entre o núcleo e plugins/temas.Depois de atualizarmos isso, também devemos impedir que o Ember estenda esse protótipo com algo como isso.EXTEND_PROTOTYPES: { String: false }em nosso arquivo environment.
-
ImportandohtmlSafeeisHTMLSafede @ember/string
- até: 4.0.0 - size-mHá muita sobreposição entre isso e #7 nesta atualização, e deve ser direto e de baixo risco.
Etapa 3 (size-xl)
A atualização de 3.25 para 3.26 é bastante complexa. É aqui que fazemos a maior parte do “atraso acumulado”. Há dezesseis depreciações no total. Vamos dividir esta atualização em cinco partes - onde apenas faremos um aumento de versão depois que todas as depreciações forem tratadas.
Ember 3.25 → Ember 3.26 (Parte 1 - Geral)
Esta parte lida com nove depreciações que são relativamente mais fáceis de lidar.
-
Métodos de transição de rotas e controladores
- até: 5.0.0 - size-mEsta depreciação remove alguns métodos de
routesecontrollers. Pode parecer uma mudança complexa, mas deve ser direta. Precisaremos apenas injetar oRoutercomo um serviço e chamá-lo daí - quando necessário. A parte complicada é que usamos isso em muitos lugares, e todos precisam ser atualizados. -
Política de Suporte a Navegadores
- até: 4.0.0 - size-s~~Esta deve ser uma mudança relativamente simples. O Ember não suportará IE11 a partir da 4.0. A boa notícia aqui é que não o suportamos há muito tempo de qualquer maneira. A única coisa que precisamos mudar é parar de transpilar para IE11 em produção.
discourse/app/assets/javascripts/discourse/config/targets.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHubFiz alguns testes básicos, e esta mudança nos economizará cerca de 60kb (gzip) ou ~6% de nossos bundles principais e de vendor em instalações Ember-CLI de produção. -
{{hasBlock}} e {{hasBlockParams}}
- até: 4.0.0 - size-sUsamos isso em alguns lugares. Esta é uma renomeação simples e de baixo risco. -
Helper{{with}}
- até: 4.0.0 - size-sRaramente usamos isso, mas ainda precisa ser corrigido. Precisamos apenas substituí-los e usar{{let}}ou uma combinação de{{if}}/{{else}}
Ember 3.25 → Ember 3.26 (Parte 2 - Templates)
Esta parte focará principalmente em depreciações envolvendo templates .hbs. Há três depreciações nas quais precisamos nos concentrar aqui.
-
Procura de Fallback de Propriedade
- até: 4.0.0 - size-lA partir do Ember 4.0, isso não funcionará mais.
Olá, {{name}}!Se tivermos uma propriedade em um template, precisamos procurá-la com um
thisprecedendo, assim:Olá, {{this.name}}!Precisaremos fazer isso com todos os nossos templates. Há maneiras de reduzir a dor aqui. Podemos tentar o ember-no-implicit-this-codemod e ver até onde nos leva.
Sou a favor de limitar as mudanças a 1 arquivo por PR. Isso facilita a revisão - e a reversão se algo der errado.
-
Acessando args nomeados via {{attrs}}
- até: 4.0.0 size-xlO objeto
{{attrs}}será removido no Ember 4.0. A mudança em si é muito direta, e o exemplo do Ember é bastante bom.Antes:
{{attrs.foo}} {{this.attrs.foo.bar}} {{deeply (nested attrs.foobar.baz)}}Depois:
{{@foo}} {{@foo.bar}} {{deeply (nested @foobar.baz)}}Precisaremos fazer isso para todos os nossos templates. Podemos combinar esta mudança com a conversão dos templates para a sintaxe de colchetes angulares. Sou um grande fã de colchetes angulares porque estão muito mais próximos da sintaxe padrão de componentes web personalizados.
Uma coisa que pode acelerar nosso progresso aqui é o ember-angle-brackets-codemod. Precisaremos experimentar com ele e ver até onde nos leva. Ele lida com a depreciação e nos dá a brilhante sintaxe de colchetes angulares.
Similar ao #1 nesta parte, também sou a favor de corrigir e testar um template por PR.
-
Argumentos posicionais
<LinkTo>
- até: 4.0.0 - size-mEsta também é uma depreciação que visa reduzir a confusão. Há alguns lugares onde usamos argumentos posicionais no link-to. Podemos corrigir isso assim:
Antes:
{{link-to "Sobre Nós" "about"}} {{#link-to "about"}}Sobre Nós{{/link-to}} {{#link-to "post" @post}}Leia {{@post.title}}...{{/link-to}}Depois (com colchetes angulares):
<LinkTo @route="about">Sobre Nós</LinkTo> <LinkTo @route="about">Sobre Nós</LinkTo> <LinkTo @route="post" @model={{@post}}>Leia {{@post.title}}...</LinkTo>
Ember 3.25 → Ember 3.26 (Parte 3 - jQuery)
Não há muito o que eu possa dizer sobre isso que você já não saiba. Novos apps Ember não usam jQuery, e ele será removido no Ember 4.0.
Nesta parte, focaremos em uma depreciação.
-
Recurso Opcional: jquery-integration
- até: 4.0.0 - size-xlNos últimos anos, fizemos um progresso enorme na redução do uso de jQuery. Ainda há lugares onde precisamos dele, particularmente no compositor e como dependência de algumas bibliotecas de vendor que usamos. Não quero entrar em detalhes sobre esta mudança aqui. Em resumo, devemos nos afastar do uso de jQuery.
No entanto, gostaria de destacar que, mesmo que nos livremos do jQuery EM TODO LUGAR, ainda devemos manter essa opção definida como true até estarmos prontos para o Ember 4.0. Precisamos de um plano para facilitar a transição para sites com temas/plugins personalizados que não controlamos. Em outras palavras, vamos fazer o trabalho, mas viver com o aviso de depreciação sobre desligar a opção.
Ember 3.25 → Ember 3.26 (Parte 4 - Preparação para Octane)
Nesta parte, devemos focar em preparar nossos arquivos para o Octane. Lidaremos com duas depreciações.
-
Recurso Opcional: template-only-glimmer-components
- até: 4.0.0 - size-mEsta é uma mudança simples em teoria, mas há trabalho implícito que precisamos fazer antes de podermos alternar essa opção.
Precisamos garantir que nossos componentes atuais apenas de template funcionem com a semântica glimmer. Fiz alguns testes, e nossos testes falharam com essa opção ativada. Aqui está uma lista de exemplo de alguns componentes apenas de template que temos no núcleo:
- app/templates/components/activation-email-form.hbs - app/templates/components/cancel-link.hbs - app/templates/components/categories-with-featured-topics.hbs - app/templates/components/category-name-fields.hbs - app/templates/components/color-input.hbs - app/templates/components/custom-html-container.hbs - app/templates/components/emoji-group-buttons.hbs - app/templates/components/emoji-group-sections.hbs - app/templates/components/empty-state.hbs - app/templates/components/ip-lookup.hbs - app/templates/components/modal-footer-close.hbs - app/templates/components/popup-menu.hbs - app/templates/components/reviewable-created-by-name.hbs - app/templates/components/reviewable-created-by.hbs - app/templates/components/reviewable-field-editor.hbs - app/templates/components/reviewable-field-text.hbs - app/templates/components/reviewable-field-textarea.hbs - app/templates/components/reviewable-field.hbs - app/templates/components/reviewable-flagged-post.hbs - app/templates/components/reviewable-post-header.hbs - app/templates/components/reviewable-post.hbs - app/templates/components/reviewable-scores.hbs - app/templates/components/reviewable-tags.hbs - app/templates/components/reviewable-topic-link.hbs - app/templates/components/score-value.hbs - app/templates/components/selected-posts.hbs - app/templates/components/subcategories-with-featured-topics.hbs - app/templates/components/text-overflow.hbs - app/templates/components/user-fields/confirm.hbs - app/templates/components/user-fields/dropdown.hbs - app/templates/components/user-fields/multiselect.hbs - app/templates/components/user-fields/text.hbs - app/templates/components/user-profile-avatar.hbs - app/templates/components/user-summary-users-list.hbsTambém precisaremos verificar nossos templates de Admin/tema/plugin e garantir que tudo funcione antes de lançar essa opção.
De primeira vista, não tenho certeza de como nossos templates
.hbrbrutos se encaixarão nisso. No entanto, @david tem trabalhado em listas de tópicos baseadas em glimmer. Então, talvez possamos nos livrar dos templates brutos completamente. -
Injeções Implícitas
- até: 4.0.0 size-xlUsamos injeções implícitas em todo lugar. Fazemos isso em um inicializador assim:
discourse/app/assets/javascripts/discourse/app/pre-initializers/inject-discourse-objects.js at ac79c5efc61d259705eeb487ca21d0ec3c535807 · discourse/discourse · GitHubO Ember está se afastando das injeções implícitas. O caminho preferido é converter a maioria de nossos objetos em serviços e injetá-los explicitamente onde forem necessários. Claro, pode haver algumas coisas onde um serviço não é ideal. Nesses casos, podemos procurar esses objetos diretamente quando forem necessários, assim:
getOwner(this).lookup('thing:main')Outra opção que temos (dependendo das implicações de desempenho) é envolver as Classes Ember com nossa própria Classe Discourse. Usaríamos então nossa Classe em todo o app. Algo como fazemos com a
Classe GlimmerComponent
discourse/app/assets/javascripts/discourse/app/components/glimmer.js at fa0c796baf9a7f64a3b27823b1aa4b370a74c3eb · discourse/discourse · GitHub. Isso tornaria esta tarefa um size-l ou até size-mEm qualquer caso, esta mudança precisará de alguma reflexão.
Ember 3.25 → Ember 3.26 (Parte 5 - Octane)
Esta é a reta final da atualização de 3.25 → Ember 3.26. Teremos apenas uma depreciação restante neste ponto, mas é uma grande.
-
Edição: Classic
- até: 4.0.0 - size-xlAntes de alternar nossa versão para Octane, gostaria de gastar tempo convertendo nossas Classes para Classes nativas e nossos componentes para componentes Glimmer. Haverá alguma dor envolvida, mas vale a pena. O ember-native-class-codemod deve aliviar parte dessa dor. Precisaremos ver até onde nos leva.
Há muitas considerações e problemas de fluxo de trabalho a serem lembrados. A única coisa que quero destacar é que seguirá o mesmo fluxo que mencionei para templates - corrigir e testar 1 componente por PR.
Etapa 4
A atualização de Ember 3.26 → Ember 3.27 introduz doze depreciações. Proponho que as dividamos em três partes. Faremos o aumento de versão depois que todas as depreciações forem tratadas.
Ember 3.26 → Ember 3.27 (parte 1 - Geral)
-
Depreciar
Route#disconnectOutlet
- até: 4.0.0 - size-sSó fazemos isso em um lugar. É o
build-category-route, e deve ser direto corrigir. -
Invocar Helpers Sem Argumentos e Parênteses em Posições de Argumento Nomeado
- até: 4.0.0 - size-sNão acho que façamos isso em nenhum lugar, mas confirmarei quando chegar a hora. Essencialmente, chamar um helper sem passar nenhum argumento.
Mesmo que usemos algo assim, precisaríamos apenas adicionar parênteses. Então, isso
<SomeComponent @arg={{someHelper}} />se torna
<SomeComponent @arg={{(someHelper)}} />note os parênteses ao redor de
someHelper -
Acesso por ponto em Run loop e computed
- até: 4.0.0 - size-mUsamos
.para acessar funçõescomputedem nosso addondecorators. Eles se parecem com isso, por exemplo:
discourse/app/assets/javascripts/discourse-common/addon/utils/decorators.js at b05fddaa7ce3968ffc70cd8d4bf290e15d06eb11 · discourse/discourse · GitHubTambém temos alguns isolados aqui e ali. Pelo que posso ver, corrigir isso é principalmente sobre corrigir como os importamos.
Então,
computed.filterdeve ser importado assim, em vez disso.import { filter } from '@ember/object/computed';Nossa versão do addon externo de vendor
buffered-proxyusa.para acessar funçõescomputed; precisaríamos atualizá-lo.Também usamos
.para acessar funçõesrunem alguns lugares. Dito isso, a mesma correção se aplica. Precisamos atualizar a maneira como os importamos. Acho que temas e plugins, em especial, podem ter vários lugares onde fazemos isso comrun. -
Depreciar o Global Ember
- até: 4.0.0 - (#size ?)Embernão estará disponível no contexto global após a 4.0. É difícil estimar a quantidade de trabalho/impacto aqui sem uma análise mais profunda. Dito isso, sei que @cvx tem feito muito trabalho para se livrar desse padrão.
Ember 3.26 → Ember 3.27 (parte 2 - renderTemplate)
Esta parte focará apenas em uma depreciação.
-
Depreciar
Route#renderTemplate
- até: 4.0.0 - size-lEm resumo, não podemos usar outlets nomeados no Ember 4.0. Então, isso não funcionará.
{{outlet "thing"}}Usamos
renderTemplateem quase 30 lugares apenas no núcleo. A atualização em si parece bastante direta. Podemos usar{{#in-element}}e um elemento HTML vazio simples como placeholder para o que costumávamos renderizar em outlets nomeados.
Ember 3.26 → Ember 3.27 (parte 3 - Componentes embutidos legados)
Esta parte focará em componentes embutidos legados e lidará com quatro depreciações.
- Importando Componentes Embutidos Legados
- até: 4.0.0 - Argumentos Legados de Componentes Embutidos
- até: 4.0.0 - Argumentos de Atributo HTML Legados de Componentes Embutidos
- até: 4.0.0 - Reabertura de Componentes Embutidos Legados
- até: 4.0.0
Não adicionei tamanhos a esses porque… realmente depende. Deixe-me explicar.
Componentes embutidos legados como Checkbox, TextField, TextArea e LinkComponent serão removidos no Ember 4.0. Usamos-os em vários lugares, e também usamos alguns padrões depreciados neles.
O Ember oferece um caminho de atualização que nos permite continuar usando-os, mas precisamos importá-los de forma diferente. No entanto, eles não receberão atualizações do Ember e permanecerão congelados. Espero que possamos nos livrar de todos eles; no entanto, isso pode ser um pouco complexo. Esta mudança precisará de mais discussão quando chegar a hora.
Etapa 5
Ember 3.27 → Ember 3.28
Esta é uma size-s, pois é apenas um aumento de versão. 3.28 é a última versão LTS no ciclo de desenvolvimento 3.x. Não introduz novas depreciações após a 3.27, e é uma boa versão para pararmos por algumas semanas enquanto as coisas se estabilizam.
A LTS 3.28 é suportada até agosto de 2022 (correções de bugs e patches de segurança)
Esta “pausa” tem alguns benefícios.
- Nos dá mais tempo para ver se surgem problemas
- quando lançarmos uma versão estável, ela deve ser na 3.28
- nos dá tempo para fazer os anúncios necessários sobre temas e plugins mantidos pelo usuário
- nos dá tempo para garantir que a transição jQuery → sem jQuery seja o mais suave possível.
Etapa 6
Depois de algumas semanas, finalmente podemos aumentar nossa versão para Ember 4
Ember 3.28 → Ember 4.1
Agora podemos desativar a integração opcional do jQuery como a última depreciação do ciclo 3.x.
Esta atualização introduz duas depreciações menores.
-
Depreciar Ember.assign
- até: 5.0.0 - size-sNão usamos isso no núcleo, mas precisaremos verificar temas/plugins. Em qualquer caso, é uma renomeação simples. -
Classe AutoLocation
- até: 5.0.0 - size-sEm teoria, precisaríamos apenas mudar
locationType: 'auto'paralocationType: 'history'em nosso arquivo de ambiente Ember, e deve funcionar.
Fluxo de Trabalho
Como mencionei no início, seremos muito cuidadosos com essas atualizações. Testaremos/corrigiremos/fixaremos todos os plugins/temas oficiais com cada atualização, e também enviaremos PRs para plugins/temas não oficiais populares.
O objetivo aqui não é desacelerar o desenvolvimento ou criar dores de cabeça. Então, os PRs serão estritamente delimitados, com uma mudança por PR e nada muito grande.
Em um mundo ideal, todas as mudanças aconteceriam em segundo plano sem interromper o trabalho de ninguém. É por isso que planejamos manter os PRs curtos e objetivos. Além disso, não gostamos muito de padrões mistos. Então, não queremos ficar presos em um estado intermediário em base de arquivo por arquivo. Um componente é ou clássico ou Glimmer, e um template usa chaves ou colchetes angulares, nada no meio.
Espero que este roteiro tenha sido claro. Como mencionei no início, esta é apenas uma visão geral geral de alto nível. Se algo estiver claro, incorreto ou não parecer certo para você, por favor, nos avise.