API da HMR
NOTA
Esta é a API da HMR do cliente. Para a manipulação da substituição de módulo instantânea nas extensões, consultar a handleHotUpdate
.
O manual da API da substituição de módulo instantânea é principalmente destinada aos autores de abstrações e ferramentas. Como um utilizador final, é provável que a substituição de módulo instantânea já esteja resolvida para nós nos modelos de ponto de partida de projetos específicos da abstração.
A Vite expõe o manual da sua API de substituição de módulo instantânea através do objeto especial import.meta.hot
:
import type { ModuleNamespace } from 'vite/types/hot.d.ts' import type { InferCustomEventPayload } from 'vite/types/customEvent.d.ts' interface ImportMeta { readonly hot?: ViteHotContext } interface ViteHotContext { readonly data: any accept(): void accept(cb: (mod: ModuleNamespace | undefined) => void): void accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void accept( deps: readonly string[], cb: (mods: Array<ModuleNamespace | undefined>) => void, ): void dispose(cb: (data: any) => void): void prune(cb: (data: any) => void): void invalidate(message?: string): void on<T extends string>( event: T, cb: (payload: InferCustomEventPayload<T>) => void, ): void off<T extends string>( event: T, cb: (payload: InferCustomEventPayload<T>) => void, ): void send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void }
Guarda Condicional Obrigatória
Em primeiro lugar, temos que nos certificar de proteger todos os usos da API de substituição de módulo instantânea com um bloco condicional para o código poder ser agitado em produção:
if (import.meta.hot) { // código da HMR }
Sensor Inteligente para TypeScript
A Vite fornece definições de tipo para a import.meta.hot
no vite/client.d.ts
. Nós podemos criar um env.d.ts
no diretório src
para que a TypeScript pegue as definições de tipo:
/// <reference types="vite/client" />
hot.accept(cb)
Para um módulo aceitar-se a si mesmo, usamos a import.meta.hot.accept
com uma função de resposta que recebe o módulo atualizado:
import 'vite/client' export const count = 1 if (import.meta.hot) { import.meta.hot.accept((newModule) => { if (newModule) { // "newModule" é indefinido quando ocorre "SyntaxError" console.log('updated: count is now ', newModule.count) } }) }
Um módulo que "aceita" atualizações instantâneas é considerado um limite da substituição de módulo instantânea.
A substituição de módulo instantânea da Vite não troca o módulo originalmente importado: se um módulo do limite da substituição de módulo instantânea reexportar novamente as importações duma dependência, então este é responsável por atualizar reexportações (e estas exportações devem estar usando let
). Além disto, os importadores acima da cadeia a partir do módulo de limite não serão notificados da mudança. Esta implementação simplificada da substituição de módulo instantânea é o suficiente para a maioria dos casos de uso de desenvolvimento, enquanto permite-nos saltar o trabalho dispendioso de gerar módulos de delegação.
A Vite exige que a chamada para esta função apareça como import.meta.hot.accept
(sensível a espaços em branco) no código-fonte para o módulo aceitar a atualização. Isto é um requisito da analise estática que a Vite faz para ativar o suporte a substituição de módulo instantânea para um módulo.
hot.accept(deps, cb)
Um módulo também pode aceitar atualizações das dependências diretas sem recarregar-se a si mesmo:
// @filename: /foo.d.ts export declare const foo: () => void // @filename: /example.js import 'vite/client' import { foo } from './foo.js' foo() if (import.meta.hot) { import.meta.hot.accept('./foo.js', (newFoo) => { // a função de resposta recebe o módulo // './foo.js' atualizado newFoo?.foo() }) // Também pode aceitar um vetor de // módulos de dependência: import.meta.hot.accept( ['./foo.js', './bar.js'], ([newFooModule, newBarModule]) => { // A função de resposta recebe um vetor // apenas o módulo atualizado não é nulo. // Se a atualização não foi bem sucedida // (erro de sintaxe por exemplo), // o vetor está vazio } ) }
hot.dispose(cb)
Um módulo que se aceita a si mesmo ou um módulo que espera ser aceito por outros pode usar hot.dispose
para limpar quaisquer efeitos colaterais persistentes criados por sua cópia atualizada:
import 'vite/client' function setupSideEffect() {} setupSideEffect() if (import.meta.hot) { import.meta.hot.dispose((data) => { // limpar o efeito colateral }) }
hot.prune(cb)
Regista uma função de resposta que chamar-se-á quando o módulo não for mais importado na página. Comparado com a hot.dispose
, esta pode ser usada se o código-fonte limpa os efeitos colaterais por si só sobre as atualizações e apenas precisamos limpar quando for removida da página. A Vite atualmente usa isto para as importações de ficheiros .css
:
import 'vite/client' function setupOrReuseSideEffect() {} setupOrReuseSideEffect() if (import.meta.hot) { import.meta.hot.prune((data) => { // limpar o efeito colateral }) }
hot.data
O objeto import.meta.hot.data
é persistido em diferentes instâncias do mesmo módulo atualizado. Este pode ser usado para passar informações duma versão anterior do módulo para a próxima.
Nota que a reatribuição do próprio data
não é suportada. Em vez disso, devemos alterar as propriedades do objeto data
para que as informações adicionados por outros manipuladores sejam preservadas:
import 'vite/client' // ok import.meta.hot.data.someValue = 'hello' // não suportado import.meta.hot.data = { someValue: 'hello' }
hot.decline()
Atualmente, isto é um nulo, e existe para compatibilidade com as versões anteriores. Isto poderia mudar no futuro se existir um novo uso para isto. Para indicar que o módulo não é instantaneamente atualizável, usamos hot.invalidate()
.
hot.invalidate(message?: string)
Um módulo que aceita-se a si mesmo pode aperceber-se, durante a execução, de que não consegue lidar com uma atualização da substituição de módulo instantânea, pelo que a atualização tem que ser propagada à força aos importadores. Ao chamar import.meta.hot.invalidate()
, o servidor da substituição de módulo instantânea invalidará os importadores do chamador, como se o chamador não se aceitasse a si mesmo. Isto registará uma mensagem na consola do navegador e no terminal. Nós podemos passar uma mensagem para dar algum contexto sobre o motivo da invalidação.
Nota que devemos sempre chamar import.meta.hot.accept
mesmo se planeamos chamar invalidate
imediatamente depois, ou então o cliente da substituição de módulo instantânea não ouvirá futuras mudanças no módulo de auto-aceitação. Para comunicar a nossa intenção claramente, recomendamos chamar invalidate
dento da função de resposta de accept
desta maneira:
import 'vite/client' import.meta.hot.accept((module) => { // Podemos usar a nova instância do módulo para // decidir se a invalidação deve ser efetuada. if (cannotHandleUpdate(module)) { import.meta.hot.invalidate() } })
hot.on(event, cb)
Ouve um evento de substituição de módulo instantânea
Os seguintes eventos da substituição de módulo instantânea são despachados pela Vite automaticamente:
'vite:beforeUpdate'
quando uma atualização está prestes a ser aplicada (por exemplo, um módulo será substituído)'vite:afterUpdate'
quando uma atualização acaba de ser aplicada (por exemplo, um módulo foi substituído)'vite:beforeFullReload'
quando uma recarga completa está prestes a ocorrer'vite:beforePrune'
quando os módulos que já não são necessários estão prestes a ser eliminados'vite:invalidate'
quando um módulo é invalidado comimport.meta.hot.invalidate()
'vite:error'
quando ocorre um erro (por exemplo, erro de sintaxe)'vite:ws:disconnect'
quando a conexão da tomada da Web é perdida (tomada da Web, são os "WebSocket")'vite:ws:connect'
quando a conexão da tomada da Web é re(estabelecida)
Os eventos personalizados da substituição de módulo instantânea também podem ser enviados a partir das extensões. Consultar o handleHotUpdate
por mais detalhes.
hot.off(event, cb)
Remove a função de resposta dos ouvintes de evento.
hot.send(event, data)
Envia os eventos personalizados de volta ao servidor de desenvolvimento da Vite.
Se chamada antes da conexão, o dado será amortecido e enviado assim que a conexão for estabelecida.
Consultar a Comunicação cliente-servidor por mais detalhes, incluindo a secção sobre Tipificação de Eventos Personalizados.
Leitura Complementar
Se quisermos saber mais sobre como usar a API da HMR e como funciona nos bastidores. Nós podemos consultar estes recursos: