JavaScript isolado no Blazor com arquivos JS colocados
Se você já trabalhou com Blazor e JS Interop antes, provavelmente acabou com um enorme arquivo app.js cheio de funções aleatórias para diferentes componentes. Funciona, mas fica confuso rapidamente. Felizmente, existe uma abordagem muito mais limpa: arquivos JavaScript colocados.
A ideia
Assim como o isolamento CSS, o Blazor permite colocar um arquivo .razor.js próximo ao seu componente. O módulo JavaScript é carregado sob demanda, somente quando o componente realmente precisa dele. Sem scripts globais, sem poluição.
#Configurando
Digamos que temos um componente Clipboard.razor que copia texto para a área de transferência. Crie um arquivo chamado Clipboard.razor.js ao lado dele:
export function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
console.log("Copied to clipboard!");
});
}
Observe a palavra-chave export - isso é importante. Blazor carrega-o como um módulo ES padrão.
Carregando o módulo no Blazor
No seu componente, você usa IJSRuntime para importar o módulo. O caminho segue uma convenção: ./_content/{ASSEMBLY_NAME}/{COMPONENT_PATH}.razor.js para bibliotecas, ou apenas o caminho relativo para o projeto atual.
@inject IJSRuntime JS
@implements IAsyncDisposable
<button @onclick="Copy">Copy to clipboard</button>
@code {
[Parameter]
public string Text { get; set; }
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Clipboard.razor.js");
}
}
private async Task Copy()
{
if (module is not null)
{
await module.InvokeVoidAsync("copyToClipboard", Text);
}
}
public async ValueTask DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
Algumas coisas a serem observadas aqui:
- Carregamos o módulo em
OnAfterRenderAsyncporque JS Interop não está disponível durante a pré-renderização do lado do servidor - Mantemos uma referência ao módulo com
IJSObjectReference - Implementamos
IAsyncDisposablepara limpar o módulo quando o componente é destruído
Por que isso é melhor
Antes, eu costumava despejar tudo em um único wwwroot/js/app.js. Funcionou, mas encontrar funções era uma tarefa difícil, e cada página carregava JavaScript desnecessário. Com arquivos JS colocados:
- Cada componente possui seu próprio JavaScript
- Os módulos são carregados lentamente, somente quando necessário
- Sem conflitos de nomes de funções globais
- Mais fácil de manter e excluir — ao excluir o componente, você exclui o JS com ele
Uma pegadinha com o caminho
O caminho que você passa para import depende se você está em um aplicativo Blazor independente ou em uma biblioteca de classes Razor. Para um aplicativo Blazor normal, o caminho é relativo a wwwroot. O arquivo .razor.js é copiado lá no momento da construção, então você faz referência a ele a partir do local do componente no projeto.
Se você receber um 404 ao carregar o módulo, verifique novamente o caminho e certifique-se de que o arquivo termine em .razor.js, não apenas em .js.
Espero que você tenha gostado da postagem! Sinta-se à vontade para entrar em contato comigo em qualquer mídia social em @emimontesdeoca.