Deno é um novo tempo de execução de JavaScript construído com Rust e V8 que permite executar JavaScript fora do navegador. Deno é mais seguro do que Node.js porque limita a rede e acesso ao sistema de arquivos por padrão.

Uma das coisas legais sobre o Deno é que você pode escrever plug-ins no Rust e usá-los dentro do código do Deno. Neste tutorial, mostraremos como criar plug-ins Deno no Rust.

Abordaremos o seguinte:

Por que escrever plug-ins Deno no Rust?

Os plug-ins no Deno geralmente melhoram o desempenho e fornecem acesso a uma gama mais ampla de ferramentas.

Devido à sua natureza de desempenho, os plug-ins são frequentemente usados ​​em cálculos para tarefas pesadas, como processamento de imagem. Os plug-ins também fornecem acesso a uma variedade de bibliotecas escritas em outras linguagens, incluindo caixas Rust de alta qualidade.

Estrutura do projeto do plugin Deno

A estrutura do projeto do plugin é a mesma de qualquer módulo Deno. Para os fins deste tutorial, você pode usar este boilerplate :

 git clone https://github.com/anshulrgoyal/deno-rust-starter.git my_module

Primeiro, crie o padrão Rust para o plug-in:

 cd meu_módulo/nativo
construção de carga

Em seguida, execute um teste para verificar se Deno está pegando a biblioteca correta:

 cd meu_módulo/nativo
deno test--unstable--allow-plugin

O padrão inclui um projeto Rust no diretório native e um módulo Deno na raiz.

Construindo um projeto Rust

O projeto Rust compila uma biblioteca dinâmica que é carregada pelo runtime do Deno. O tipo de arquivo e o nome da biblioteca dependem do sistema operacional. O projeto Rust pode compilar para um arquivo so dylib ou dll -e o nome do arquivo compilado também pode ser diferente. O padrão pode lidar com três plataformas principais: Linux, macOS e Windows.

 [pacote]
nome="nativo"
versão="0.1.0"
autores=["anshul "]
edição="2018" [lib]
nome="nativo"
tipo de caixa=["cdylib"] [dependências]
deno_core="0.75.0" ├── README.md
├── deps.ts
├── mod.ts
├── mod_test.ts
├── nativo
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── src
│ └── lib.rs
├── test.ts
├── test_deps.ts
└── tsconfig.json

O arquivo mod.ts é o arquivo principal importado por outro aplicativo usando o seu módulo.

Adicionando código Rust

Para este tutorial, mostraremos como construir um otimizador PNG usando uma caixa oxipng . Cada plugin Deno deve exportar a função deno_plugin_init e registrar todos os métodos que o plugin exporta.

O atributo # [no_mangle] diz ao compilador para não alterar o nome da função:

 # [no_mangle]
pub fn deno_plugin_init (interface: & interface mut dyn) {
//registra a função. Passe o nome e a função para registrar o método interface.register_op ("hello_world", hello_world);
}

Criação da função do otimizador

Cada função exportada possui a mesma assinatura. Os plug-ins Deno só podem exportar funções. Essas funções podem ser sincronizadas ou assíncronas, dependendo do tipo de retorno.

 fn optimize (_interface: & interface mut dyn, zero_copy: & mut [ZeroCopyBuf],
)-> Op { //obtém o primeiro argumento deixe primeiro=zero_copy.first (). desembrulhar (); let opts: oxipng:: Options=Default:: default (); //converter vetor deixe result=oxipng:: optimize_from_memory (& first.to_vec (), & opts).unwrap (); //mover para o heap para que o deno possa usá-lo Op:: Sync (Box:: from (result))
}

O segundo argumento da função contém uma matriz de buffers. Cada buffer na matriz representa o argumento passado para a função exportada quando chamada. Esses buffers são serializados em strings ou outros tipos de dados com base nos requisitos.

O código acima pega o primeiro elemento de zero_copy e passa para optimize_from_memory . O primeiro elemento do array é o arquivo passado para a função otimizar quando chamado do código Deno. O arquivo é passado como bytes. A função processa o arquivo e retorna o resultado como uma Box . O tipo de retorno é Op enum com duas variantes sync e async .

Crie o código usando o comando cargo build . Agora, este plugin pode ser usado no Deno.

Carregando um plugin Rust no Deno

Agora que o plug-in está compilado, vamos carregá-lo usando o Deno.

O plug-in ainda está em desenvolvimento e faz parte de APIs instáveis, portanto, a sinalização --unstable é necessária, assim como --allow-plugin .

 let path=""
//verifique o tipo de sistema operacional para carregar o arquivo correto
if (Deno.build.os==="linux") {
//arquivo linux emitido pelo compilador rust path="./native/target/debug/libnative.so"
} else if (Deno.build.os==="windows") {
//arquivo do Windows emitido pelo Rust Compiler path="./native/target/debug/native.dll"
} else if (Deno.build.os==="darwin") {
//arquivo macos emitido por rust comipler path="./native/target/debug/libnative.dylib"
}
//carrega o plugin do sistema de arquivos
const rid=Deno.openPlugin (caminho);
//Obter métodos disponíveis no plugin
//@ ts-Expect-Error
const {otimizar: optimise_native}=(Rejeitar como qualquer).core.ops (); otimizar função assíncrona de exportação (fileName: string): Promise  {
//lendo um arquivo const file=await Deno.open (fileName);
//obtendo conteúdo const value=await Deno.readAll (arquivo)
//fechando arquivo aguarde Deno.close (file.rid)
//executando o método de plugin nativo usando o método de despacho Deno return (Deno como qualquer).core.dispatch (optimise_native, value)
}

Cada plugin é carregado usando o método openPlugin . Em seguida, o método ops é usado para obter o identificador do método, que executa o código exportado pelo plug-in.

dispatch é usado para executar o código exportado pelo plugin nativo. O primeiro argumento é o identificador do método; o resto é passado para a função nativa. Nesse caso, o arquivo é passado.

Gravando plug-ins assíncronos

Como o Deno é de thread único, não é aconselhável bloquear o thread principal. Deno permite que você retorne um futuro da função nativa, que você pode usar com threads de sistema operacional para escrever uma função que não bloqueie a thread principal.

 fn optimise_async (_interface: & interface mut dyn, zero_copy: & mut [ZeroCopyBuf],
)-> Op {
//obtém o primeiro argumento deixe primeiro=zero_copy.first (). desembrulhar (); let opts: oxipng:: Options=Default:: default (); deixe arg=first.to_vec ();
//cria um novo futuro deixe fut=async mover {
//cria um canal para enviar o resultado, uma vez feito para o tópico principal let (tx, rx)=futures:: channel:: oneshot:: channel::  >> ();
//cria um novo tópico std:: thread:: spawn (mover || {
//Executar trabalho deixe result=oxipng:: optimize_from_memory (& arg, & opts);
//envia o resultado para o tópico principal tx.send (resultado).unwrap (); });
//receba o resultado deixe resultado=rx.await;
//cria uma fatia em caixa deixe result_box=result.unwrap (). unbrap (). into_boxed_slice ();
//retorna a fatia em caixa do futuro result_box };
//retorna o futuro Op:: Async (fut.boxed ())
}

Um futuro é criado usando o bloco async e retornado como um futuro em caixa. Deno lida com a conclusão do futuro e informa o lado Deno do plugin. Um canal é usado para a comunicação entre o novo tópico e o tópico principal.

O código Deno não precisa de muita atualização-apenas um novo asyncHandler para lidar com a conclusão da tarefa:

 let path=""
if (Deno.build.os==="linux") { path="./native/target/debug/libnative.so"
} else if (Deno.build.os==="windows") { path="./native/target/debug/native.dll"
} else if (Deno.build.os==="darwin") { path="./native/target/debug/libnative.dylib"
}
const rid=Deno.openPlugin (caminho); const {optimise_async}=(Rejeitar como qualquer).core.ops (); exportar função assíncrona otimizar (nome_do_arquivo: string) { const file=await Deno.open (fileName); valor const=espera Deno.readAll (arquivo); aguardar Deno.close (file.rid);
//novo manipulador (Rejeitar como qualquer).core.setAsyncHandler (optimise_async, (resposta: qualquer)=> { Deno.writeFile ("l.png", resposta) });
//executando o código nativo. (Rejeitar como qualquer um).core.dispatch (optimise_async, value);
}
aguardar otimizar ("t.png") aguarde Deno.close (rid);

Conclusão

Neste tutorial, abordamos como construir um plug-in Deno simples usando Rust e também como criar um plug-in assíncrono usando futuros Rust e a caixa deno_core .

A ferrugem tem um grande ecossistema com caixas de alta qualidade. Você pode usar todas essas caixas no Deno criando plug-ins. Seja um plug-in de processamento de imagem, conector de banco de dados etc., o acesso aos plug-ins Rust ajuda a expandir o ecossistema Deno.

A postagem Como criar um plugin Deno em Rust apareceu primeiro no LogRocket Blog .