O Deno chegou na versão 1.40 e essa é uma das versões mais legais de todas! Primeiro, porque ela tem a adição da Temporal API que eu estou falando aqui desde 2020! E eu acho que é o primeiro runtime a implementar essa funcionalidade de fato!

Além disso, uma série de outras novidades que eu vou passar por aqui uma por uma!

Temporal API

A temporal API é a nova forma de lidar com as datas no JavaScript, eu falei muito sobre ela neste artigo e mostrei todos os detalhes, então não vou entrar em muitos detalhes aqui, mas essencialmente, o Deno é o primeiro runtime que implementa essa API completamente.

Ela ainda está por trás de uma flag --unstable-temporal mas você já pode utilizar da mesma forma que a documentação oficial informa! Se você rodar um terminal com deno --unstable-temporal, você já pode fazer alguns testes:

console.log(Temporal.Now.instant()) // data e hora de hoje
console.log(Temporal.Now.zonedDateTimeISO()) // equivalente ao toISOString
const birthday = Temporal.PlainMonthDay.from("12-15");
const birthdayIn2030 = birthday.toPlainDate({ year: 2030 });
console.log(birthdayIn2030.toString()); // 2030-12-15
💡
Por algum motivo o método Temporal.Now.timeZoneId não foi implementado.

Import.meta.filename e dirname

Isso aqui era algo que eu queria muito que acontecesse. Desde o advento dos ECMAScript modules, toda a forma de resolução de módulos mudou, o que significa que pegar o nome de um arquivo ou o diretório onde ele existe não são mais tão simples de buscar.

No Node, temos duas variáveis "mágicas" chamadas __dirname e __filename que retornam respectivamente o caminho do diretório e do arquivo que você está executando.

Mas com ESM não podemos usá-las porque elas não são setadas no início da aplicação, então temos que buscar a URL do módulo com import.meta.url, que retorna uma fileURL no modelo file://caminho, e ai temos que usar dirname nessa URL, mas apenas depois de converter essa URL para um caminho!

import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'

const fileurl = import.meta.url
const path = fileURLToPath(fileurl)
const dir = dirname(path)
const filename = path.split('/').pop()

console.log({ fileurl, path, dir, filename })
/*
{
  fileurl: "file:///Users/lucas/repos/deno/teste.ts",
  path: "/Users/lucas/repos/deno/teste.ts",
  dir: "/Users/lucas/repos/deno",
  filename: "teste.ts"
}
*/

Isso era muito chato! Especialmente se você tinha que lidar com caminhos constantemente, então duas propostas foram adicionadas para poder suportar tanto o arquivo quanto a pasta, chamadas import.meta.filename e import.meta.dirname, agora você pode substituir tudo isso por:

console.log(import.meta.dirname) // /Users/lucas/repos/deno
console.log(import.meta.filename) // /Users/lucas/repos/deno/teste.ts

Vem aprender comigo!

Quer aprender mais sobre criptografia e boas práticas com #TypeScript?

Se inscreva na Formação TS!

Decorators

Finalmente vamos ter suporte nativo a decorators, uma proposta que está no estágio final e deve chegar nos browsers logo mais! Depois de mais de 5 anos em espera, a nova proposta junta todas as propostas anteriores em uma só.

Um exemplo clássico que a gente pode dar é o @trace que serve para debugar qualquer função colocando um console antes e depois da execução:

function trace(fn: any, ctx: ClassMethodDecoratorContext) {
  return function (...args: unknown[]) {
    console.log("ENTERED", ctx.name);
    const v = fn(...args);
    console.log("EXITED", ctx.name);
    return v;
  };
}

class App {
  @trace
  static start() {
    console.log("Hello World!");
  }
}

App.start();

Imports mais simples

Essa é outra novidade interessante. Antigamente, quando tínhamos import maps com módulos que tinham subdiretórios, tínhamos que definir dois imports diferentes:

{
  "imports": {
    "preact": "npm:preact@10.5.13",
    "preact/": "npm:/preact@10.5.13/"
  }
}

Isso permitia que a gente pudesse importar tanto o top-level preact com import preact from 'preact', e também os submódulos tipo import hooks from 'preact/hooks'.

Agora a simplificação funciona para que você possa só ter um módulo no import map e consiga importar tudo da mesma raiz só com um map:

{
  "imports": {
    "preact": "npm:preact@10.5.13"
  }
}
Embora eu não goste muito de usar import maps e prefira a abordagem de um arquivo deps.ts

Outras mudanças

  • Uma série de APIs e comandos estão sendo depreciados, em especial o deno.run e deno.serveHttp
  • Suporte ao rejectionHandled, um evento que é disparado sempre que uma exception acontece em uma promise que já foi rejeitada (quando você tem um catch não usado)
  • Suporte a janelas com WebGPU
  • Suporte a novas APIs nativas do Node.js
  • Melhores mensagens no deno lint e deno doc