TL;DR Search on Kangax' compat-table if a feature is available for your runtime
So you got years of JavaScript experience, and now you want to use these skills on the backend? You're lucky because most JavaScript-based backends use Node.js, which you probably already know from the tooling you used to bundle up your frontend code.
But even if you used Node.js, maybe it's a good idea to look into the differences it brings. With Deno, there is also a new kid on the JS runtime block!
In this article, I'm going over the differences that frontend devs should expect when writing JavaScript for a backend.
ECMAScript Version
The first difference lies in the ECMAScript version of the JS runtime supports. ECMAScript is the standard that defines the JS features a runtime should have. While ECMAScript versions are backward compatible, you can't expect to have a runtime that supports version ES2015 to have ES2019 features.
const z = x?.y ?? 10;
^
SyntaxError: Unexpected token '.'
The process here is as follows: A technical committee takes proposals for language features, they talk about it and refine it, and while that happens, the runtime creators implement the features to see if they work. If they are deemed suitable, they will be included in the next version of the standard.
On the frontend, we have to look at the stats on our servers to find out what version our clients support. On the backend, we usually have the advantage of choosing our runtime and, in turn, our ECMAScript version.
While you can usually "compile down" to a version supported by your runtime, it's nice to write code that runs without any tooling. Look at your Node.js version, and check what features it support.
An important note here: Most runtimes don't support all features of an ECMAScript version, so don't just look for a version, but a feature. Tail call optimization, for example, is an ES2015 feature, but it's only supported on Safari. Still, other browsers support many other >ES2015 features.
Of course, this is the same for all runtimes, Deno, Node.js, and the various browsers.
Browser APIs
The next point is the browser APIs support of your runtime. The ECMAScript version defines some APIs, but not all of them. The most obvious example is the DOM API. Non-browser runtimes like Node.js and Deno don't support the DOM, because there is no UI to render it to.
const y = window.decodeURI(x);
^
ReferenceError: window is not defined
The differences in Node.js and Deno are that Deno tries to use as many browser APIs as possible. This difference means that you have to use the HTTP package in Node.js to send a request, but you can use the fetch
API directly in Deno.
A list of browser APIs available in Deno can be found in their docs.
If you got a list for browser APIs supported by Node.js, please comment!
Access Control
When using a browser, you're limited to what the browser APIs allow you to do, and lately, many of them even ask the user before they are allowed to access hardware. You can only use HTTP network connections, and you can't access servers on other domains by default. Overall the browser is a harsh mistress.
// Browser
document
.getElementById(fileInputElementId)
.addEventListener("change", ({target}) => {
const [file] = target.files;
const reader = new FileReader();
reader.onload = processContent;
reader.readAsText(file);
});
// Node.js
fs.readFile("config.json", processContent);
Access control is different in the backend. If there exists a package that allows access to any hardware or you can implement such a package yourself, you can access it. You are only limited by the permissions of your operating system. Want to send UDP to a domain different from your server? No problem!
Well, at least that is true for Node.js. Deno goes a different route here and requires you to give the runtime permissions via command line parameters. If you don't allow writing files, and a package you use needs to write a file, Deno will tell you.
Module Systems
Many browser vendors finally settled down on a module system after many years and with the help of the ECMA committee. Now it's possible to load JavaScript from within JavaScript without any hacks. All major browsers support ES modules, and if you define your script tag with type="module"
you can import away.
// ES module import
import value from "library";
// CommonJS module import
const value = require("library");
Things look different on the backend, primarily for Node.js, because it couldn't wait years for the standard to be approved. Node.js defined its own module system, called CommonJS. While the current Node.js version has experimental ES-modules support, it will take a while to get things stabilized, and then all CommonJS modules have to be converted too.
Since Deno is a fresh approach to non-browser JS runtimes, it didn't have that problem. Deno supports ES modules out of the box, and you can import an URL that points to an ES module JS file, it will be downloaded and cached.
Summary
JavaScript makes the whole stack more accessible than any other language, and building a backend has never been easier.
While there are still differences that can make a package you know from the frontend unusable on the backend, these gaps are getting smaller every new version. Both Node.js and Deno try to converge with the browser runtimes more and more.
Some "Function as a Service" providers like Cloudflare even go their own way and support the Service Worker standard as their runtime, to make things feel more browser-like.
Top comments (4)
Hello K,
thank you for your article.
I think I found a typo within the third code snippet:
cosnt [file] = target.files;
I assume you meant:
const [file] = target.files;
I also find it interesting that I came across the name Kangax for the second time.
But please, don`t mind me too much. I am a beginner regarding javascript :).
Thanks for the fix! Consider it merged :D
Use TypeScript (or Babel-Node), with correct settings, and you probably can use any features you want in Node.js. You will need to choose compilation target according to node.green/ though. I think Node 10 is around ES2018.
Non-browser runtimes like Node.js can use JSDOM, if you really want to run Browser-side JavaScript, or use DOM, but there won't be any direct visual output.
Deno.js can also have
tsconfig.json
, but you mostly like don't have to create one, or edit it, in the first place.good points.
but why no tsconfig?