On the 13th of this month, version 1.0 of Deno was released, the new JavaScript and TypeScript runtime that is already gaining a lot of popularity among programmers. In recent weeks, questions like: “What is Deno?”, “What are its features?” and “Will it replace Node?” have been popping up on the Web, and you have probably asked yourself these questions. We will discuss them in this article. Let's start by getting to know the creator of Deno a little better.
A Bit of History
Deno was created by Ryan Dahl, who also created Node.js, certainly the most widely used JavaScript runtime in the world today. Notice that these two technologies are very connected. In fact, the name “Deno” is a great pun on “Node.”
During JSConf 2018, Ryan gave a talk titled “10 Things I Regret About Node.js.” During this talk, he announced Deno as his new project. Now, approximately two years later, the first version of Deno is available. When analyzing the structure of Deno, we see some very interesting features. Let's take a look at some of them together.
Features of Deno
Engine
Deno was developed with the Rust language and uses V8, the rendering engine of Google Chrome, in its structure. Can you imagine another technology that uses V8? That's right, Node.js was also developed based on it.
Security
When we start using Deno, we immediately see a small issue: we cannot connect to the Network or even access some hardware resources of the computer by default. Deno does not allow us to do this unless we make it clear what resource we want to access through flags, as we will see shortly.
We may find it strange at first to need to grant permission to access our computer's resources, but this can bring us some benefits, such as reducing the chance of suffering an attack on our server.
Module Import
Like Node, Deno has native modules (Standard Libraries) and third-party modules. However, there is a difference in how they import these modules into our code. Node uses the well-known npm (Node Package Manager) to download packages from the Web. Through npm we store the downloaded tools in the node_modules folder, that is, locally. Deno, on the other hand, performs the import of modules via a URL, externally. If you have ever used a CDN, you know how convenient this is.
This feature can bring us some advantages. For example: some programmers get annoyed with the weight that the node_modules folder brings to the server (some say it's heavier than a black hole ?). With external imports, there will be no need to worry about this issue.
ES6 Imports
While still talking about module import, we see that Deno uses ES6 imports in its structure. This means that if you already have some experience using import/export in your JavaScript code, you won't face difficulties working with Deno.
TypeScript Support
Did you notice that at the beginning of the article we said that Deno is a JavaScript and TypeScript runtime? Deno also supports this superset of JavaScript. We know that TypeScript has grown significantly in recent years and helps us a lot when we need to validate variable types in JavaScript, in addition to other advantages.
If you wish to use only JavaScript with Deno, that's fine, but you can also use TypeScript files if you prefer.
Async/Await and Promises
Deno allows us to work with asynchronous functions and promises easily. We know that using asynchronous code is very useful and JavaScript has a long history with this concept. Don't forget to check out our series on Asynchronous JavaScript here on our Blog.
After looking at some of Deno's features, what do you think about creating a small example with it? Let's start with its installation.
Installation
To install Deno, we will use Chocolatey. You can learn how to install it in this article: Getting to Know Chocolatey: the Windows Package Manager
We will use the following command:
choco install deno
If you have a Mac computer, you can use HomeBrew to perform the installation. If you are using Linux, you can use curl.
To check if Deno has been installed, run the following:
deno --version
The following will be returned:
Now we are ready for our first example.
First Code with Deno - Creating a Web Server
We created a file named first-server.js. To create a server, we will need the serve module from Deno. For that, we'll use the following line:
import { serve } from 'https://deno.land/std/http/server.ts'
In this code, we already see ES6 imports in practice. Additionally, note that we use the concept of destructuring to load only the serve module from the entire server.ts package. Lastly, see that the import came from a URL, from the Deno site servers.
Let's set up the server with the following line:
const server = serve({ port: 8000 });
With this code, we simply applied the serve module to create a Web server and defined that it will be accessible through port 8000. We could set the port to whatever we wanted. We assigned this server to the constant server.
When the server starts, we will want to see a message in the console, as feedback that everything is working fine. To do this, just add a console.log() in the code:
console.log('Server running...');
Now, we need to specify what the server will return to us. For this, Deno uses a for loop, specifically a for of. It will look like this:
for await (const req of server) {
req.respond({
body: '<h1>Hello Hcode</h1>'
});
}
Notice that we used await in this for(). Therefore, we are already working with asynchronous code. This code defines that while there are requests on our server, a welcome message will be returned.
Our code is ready. To test it, let's run the following command:
deno run first-server.js
This structure is quite similar to npm, which has the npm run command. When we run this command, the following is returned to us:
An error occurred. It indicates that Deno does not have permission to access the Network. Remember we mentioned earlier about the security aspect of Deno, that it does not access the Internet by default? It is necessary to grant permission for it to do so. At this moment, we see the importance of flags in Deno. Let's run the command again, but now it will look like this:
deno run --allow-net first-server.js
With the “--allow-net” flag, we granted the necessary permission for Deno to access our Network. Note that we specified the flag before the file name. It is important to remember this order for the command to work well. Additionally, note that we clearly indicated not only the name of the JS file but also its extension. Deno requires that the file name be “complete.” When we run the command again, we see the following:
Now the server is working without any issues. To access the server, we need to type localhost:8000 in our browser. If you set another port, you should indicate it after the colon. When accessing the server, we see the following result:
Our code is working!!! What do you think of the structure of our first file using Deno? It is always very nice to create our first “Hello World” using any technology. But how about we create a second example, delving a bit deeper into Deno's resources? Let's do that now.
Second Code with Deno - Creating a QR Code Generator
Our second example will be named qrcode-generator.js. It will also create a Web server, but we will return an image of a QR code. For this, we will import a third-party module aimed at generating these codes. The first lines of the file will look like this:
import { qrcode } from 'https://deno.land/x/qrcode/mod.ts'
import { serve } from 'https://deno.land/std/http/server.ts'
Next, we will create the server:
const myServer = serve({ port: 8000 });
The next step will be to create the content of the QR code. For this, we will use this code:
let base64 = await qrcode('https://hcode.com.br', {
size: 300
})
The qrcode() method is the call of the module we imported at the beginning of the code. The first parameter it expects is the string that will be embedded in the QR Code. The second parameter is a configuration object, such as the size that the code will have. It returns a promise, so we use await in this line as well.
Finally, we will add the console.log() as a message indicating that the server started without issues and also the for of to wait for the information from the request. We will use this code:
console.log('Server running...');
for await (const request of myServer) {
request.respond({
headers: new Headers({
'Content-Type': 'text/html'
}),
body: `
<div style="display: flex; justify-content: center; margin-top: 30px;">
<img src="${base64}" />
</div>
`
});
}
With this code, we define that the server will return an image, which will be centered on the page and will have as content the value of the generated QR Code. We can see some interesting points in this code. For example: we saw that we can define what the content type of the page will be through the headers option. Additionally, we are returning the body using the template string feature.
Let's start this server with the following command:
deno run --allow-net qrcode-generator.js
Now, when accessing localhost:8000, we see the following:
Our QR Code has been generated correctly. If you wish, you can test scanning this code with your phone ?. Amazing, isn't it? But I think we can improve this example a bit more. The content of the QR Code is static. What if we could inform the URL to be added to the code dynamically? Let's implement this intelligence in the code now.
We can inform this parameter to Deno through the Terminal. If you have worked with Node, you probably know the process.argv variable. We can do the same with Deno using the following code:
let args = Deno.args;
Pretty simple, don't you agree? In this concept, we also see a small difference between Node and Deno. The process.argv identifies the node command and any other necessary command as an argument. Thus, we generally access position 2 or 3 of this returned array. On the other hand, Deno can understand that the deno and run commands are not arguments. Therefore, the first argument we inform will be position 0 of the array, which simplifies our code. Let’s inform the args variable to the qrcode() method, like this:
let base64 = await qrcode(args[0], {
size: 300
})
Now we can specify the URL we want to create. For example, we can execute the following command:
deno run --allow-net qrcode-generator.js https://youtube.com/hcodebrasil
And now when accessing localhost:8000, we will see the following result:
If you scan this code, you will be directed to Hcode's YouTube channel.
You can find the codes developed in this article on our GitHub.
This shows that we can do many interesting things with Deno! After seeing these examples, one question remains to be answered.
After all, will Deno kill Node?
It is common to hear this question when a new tool is released. Even though Deno already shows itself as an excellent development environment, we know that Node has been around for much longer in the market. After all, Node was created in 2009, exactly 11 years ago. It is a very mature and widely used technology. Ryan Dahl himself commented on this difference in development time between the two tools in the launch article for Deno. Moreover, Node is part of the OpenJS Foundation.
We can say that the big question is not whether Deno will kill Node, but rather how this new runtime will help Web Development. We see that Deno has brought us several interesting features that help improve the performance of our applications. As a new “competitor,” the tendency is for Node to also adapt and bring new interesting features. The truth is that those who benefit from this are us, who work with these technologies.
We will still hear a lot about Node and Deno. What remains for us is to continue studying these two amazing runtimes and continue using their features to create modern projects for the Web.
See you next article :)