Why the JS ecosystem is awesome !

The Javascript world is today’s the most vibrant development ecosystem. It’s popularity propelled it from a simple scripting gadget to the backbone of today’s web. Browsers are more powerful each passing day, NPM registry grows to whooping 1 million packages and Node has long shown it’s a competent back-end language.
Today, we’re going to create a tiny project from scratch together and take full advantage of all that. I want to show you that you don’t need years of experience to create something cool.
Buckle up, it’s a long ride, but I promise you that by the end you can do it all by yourself.

Act I: the code

Let’s say you have an idea you want to code. No, no, a simpler one. Something that can fit in one function. Something like creating a unique image per username, returning the hour of any timezone or return a random color.
For our purposes, we’re going to create a function that give a blank image given dimensions. No big deal, just create a canvas, color it and return the data. We will called it lorem-pix.
So, I start every project the same way:
$ mkdir lorem-pix
$ cd lorem-pix
$ git init
$ npm init

Then, let’s create that index.js and start coding:
const loremPix = (width, height, color) => {
const canvas = createCanvas(width, height);
const ctx = canvas.getContext(“2d");

ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);

return canvas.toDataURL("image/png");
};
module.exports = loremPix;

At this point, you should note that createCanvas is not defined. If I was in a browser, I’ll just have to do document.createElement("canvas"), but I already know I don’t want to stay in the browser environment and Node has no Canvas support. 😱
What could we do ?

Act II: NPM

With hundreds of thousands of packages, NPM potentially hold a solution for any of your problems. As NPM-cli comes bundled with Node, it’s safe to say that it’s the most influential program in Javascript.

Don’t mix-up NPM and NPM-cli. The former is the public registry holding all the codes while the latter is the utility requesting from the registry.

A bit of research gives me exactly what I need. All left to do is fetching the desired dependency.
$ npm install canvas

And add a require at the top of our index.js file.
const { createCanvas } = require("canvas");

Note that Node sadly don’t support the import statement as of today.

And voilà, our function is now done. We can even publish it at NPM so anyone can use it. Just make sure your package.json is correctly filled and we’re good to go.
$ npm publish

Ok, this is already pretty great. We have a function that rely on someone else code and we published it so anyone can rely on us.
But why not go a little further ?

Act III: CLI

Since NPM-cli 5.2.0, a new command is available: npx. Thanks to it, you can execute code hosted on NPM with a single command line. It magically download, install what need to be and run the required binary file.
But we need to have a binary executable. Our JS function is great, but can only be called by a JS script.
Let’s remedy that by creating a new file named cli.js. Running a plain text file on the operating system is not going to work. We need to tell which program have to parse the code inside it. In our case we need it to be Node (default is bash on unix or cmd.exe on windows). Fortunately, we can do so with a shebang.
#!/usr/bin/env node
const loremPix = require(".");
const { writeFileSync } = require("fs");

const inputs = process.argv.slice(2);

const dataURL = loremPix(…inputs);

writeFileSync("lorem.png", dataURL.split(",")[1], "base64");
console.log("Done creating image.");

On the first line, you can notice the shebang thing. Then we import our own library and the Node file-system utility.
Next, we gather the inputs from the command-line arguments, the first one being the program (node) and the second one the file executed (cli.js). Anything after that is treated as arguments to our function.
Finally, the script write the file using the returned data. Details don’t matter, but it need a file name, some data and the encoding method.
After a chmod to add execution rights, we are now able to run this script like any program installed on your computer.
$ chmod +x cli.js
$ ./cli.js 200 150 red
> Done creating image.

Boom! A new file called lorem.png appeared right next to the cli.js and you guessed it, it’s a red image of 200 by 150 pixels.

Incredible! 😮

It means that anyone with Node installed can call npx to use our fantastic library.
$ npx lorem-pix 200 150 red

So now, what if we want to make it available to user even without Node ?

Act IV: API

Historically, JS was created to be used on back-end and Node is the rightful heir of that history. If our code is deployed on a Node back-end, it can be run with a simple URL call.
I’m going to use ZEIT’s now because I love it. It’s so simple it hurt.
First, we can again add a new file called api.js and fill it according to the documentation.
const loremPix = require(".");
const { parse } = require("url");

module.exports = (request, response) => {
const { query } = parse(request.url, true);
const { width, height, color } = query;

const data = loremPix(width, height, color);

response.writeHead(200, {
"Content-Type": "image/png",
});
response.write(data.split(",")[1], "base64");
response.end();
};

Almost like cli.js: import our library, parse the URL for the right parameters and write the result to the response back to the user.
We also need a now.json file to configure now.
{
"version": 2,
"builds": [
{
"src": "api.js",
"use": "@now/node"
}
],
"routes": [
{
"src": "/api/(?[^/]+)/?(?<height>[^/]*)/?(?<color>[^/]*)",
"dest": "/api.js?width=$width&height=$height&color=$color"
}
]
}

First we tell now to use Node to run api.js. Kind of like the shebang for the cli.js.
The hieroglyphs by the end is a regular expression. Users are lazy and so am I. It’s easier for me to parse URL like api.js?width=200&height=150, but it’s more simple for users to write api/200/150. The regexp do just that by rerouting requests.
Ok, time to deploy the API.
$ npx now login
$ npx now

Once done, the program tells you which URL you can use to execute the code. In my case:
https://lorem-pix-o5fjmzam5.now.sh/api/200/150/red
The API return an image whenever someone request it. It means that any HTML page can use it without any installation.
<img src="https://lorem-pix-o5fjmzam5.now.sh/api/200/150/red" alt="placeholder"/>

Hol’ up a minute !

 Act V: Webservice

Any HTML page can use it ? Why not create our own page ?
We already set now to host the JS code, we can add a static HTML page along side it. More than just a landing page to present our project, we can have user inputs with live preview of the result.
Yet another file, this time of course named index.html.
<h1>Lorem pix</h1>
<form id="form">

</form>
<img src="" alt="live preview" id="preview"/>
<script src="front/live-preview.js"></script>
<script>
const form = document.getElementById("form");
const img = document.getElementById("preview");

form.addEventListener("change", () => {
const { width, height, color } = form;
livePreview(img, width.value, height.value, color.value);
});
</script>

I put the CSS and JS file under the front folder just for organization’s sake. Here’s what our script looks like.
const API_URL = "https://lorem-pix-o5fjmzam5.now.sh/api";

const livePreview = (img, width, height, color) => {
const url = `${API_URL}/${width}/${height}/${encodeURIComponent(color)}`;
img.src = url;
return url;
};

Pretty straightforward!
I just used encodeURIComponent to avoid the # charactere messing with the URL.
Finally, we need tell now to serve the static files in now.json.
"builds": [

{
"src": "index.html",
"use": "@now/html-minifier"
},
{
"src": "/front/*",
"use": "@now/static"
}
]

Let’s not forget to deploy again with npx now and we are live.

Conclusion

What a ride!
Being able to access the same function as a package, a CLI, an API and a front-end webservice is still incredible for me. I highly encourage everyone reading to try and do it’s own. You can access the whole code-base at Github and copy/paste from here.
With a little more creativity than just making a blank image, I’m sure all of you can offer some great product. Be sure to share them in comments below.
Peace 🙏

Link: https://dev.to/gmartigny/why-the-js-ecosystem-is-awesome-48nl