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/(?<width>[^/]+)/?(?<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 🙏
Top comments (25)
I agree to some extent that some things about the JS ecosystem are a mess, but not these examples.
ES6 is now widely supported in every browser with Internet Explorer being the only exception; just take a look at caniuse.com/#search=es6, where's that "used by nobody but Node"?
Secondly: TypeScript is a complete optional language for those who want types in their JS experience and it's definitely not suitable for someone who's a complete JS beginner. And Babel, as you said, is a transpiler but it's just that, if anyone mistakes Babel as a language they need to check what Babel does. So we just have one language, JavaScript, and two versions. Any confusion with this is the same as saying: "Oh, well, I get confused with C# not having support for Generics in C# 1.0 but having them in C# 2.0!"
I don't understand why you consider that React, Vue or Angular are not optional. You can just make any kind of development with pure JS the same way you can do it with PHP. React, Vue or Angular are the same as Laravel, .NET MVC, Flask or Spring: libraries to make your life easier, but if you want you can go ahead and do it without them.
Maybe in React it's hard to start a project (though given that it's the most famous view framework right now I highly doubt that there's no project like Spring Initilizr for it), I don't have experience with it, but in Angular or Vue here's how hard it is to start a new project.
Angular:
Vue:
And voilà, you just got yourself everything you need to start developing with a nice architecture and some example files. You DON'T need to learn Node if you're developing a front-end app, you DON'T need to use Yarn (it's the same as NPM, so what's the point if you don't want?), so what's your complaint here? That you need to learn some library to use that library?
Again, I agree that some parts of the JS ecosystem are a mess, the amount of libraries that are published in NPM for such trivial things like padding a string just because the developers are lazy enough to write a few couple of lines is awful, but your complaints here seem more like a problem with not knowing the ecosystem enough rather than a problem with the ecosystem itself.
Are you joking? This is a good thing? With packages like is-odd and is-even? It's a complete and utter mess
Node isn't a language and honestly anything can do the job, once you get used to it. Node lacks a lot of things, but simplicity attracts people, not it's features or anything related to being competent or mature or anything else as language, because it's not.
This is nice indeed, but nothing that new or amazing. We were sharing code between different platforms, operating systems, etc even in the 90s and this is only how far I remember, so probably much longer.
No I'm not. I know it's a very dividing subject and I agree
is-odd
and alike are a stretch. However, modules should be trusted black-boxes. If you don't want to trust others, you still have the choice to code you own.I don't get why JS still has such a bad rap. At the same time I don't care if people like it or not. I just pick the language that allow me to do the most, and today it's JS.
No one has the truth. Every word on Internet is subjective. Moreover, once again, if JS is awesome (being true or not) doesn't imply other are not.
NPM - we all know what happened, when the turkish guy got offended and deleted his own package: qz.com/646467/how-one-programmer-b...
So about trust - you will quickly get bored of checking who you trust if you decide to inspect a more complex package. An old joke is that JS developers compete if they can build a meaningful app with less than 100 dependencies. You add 10-15 dependencies and and that quickly escalates to over 300 folders in you node_modules. So theoretically - you can, practically - no way in hell.
OK you MUST be joking this time. Right?
The "this" hell, funny features like parsing numbers in octal format by default, "funny" date functions, assuming months start from 0 etc. Yeah all of this helps the good reputation I guess.
And yes, we get around these parts by using TypeScript or literally anything else but plain old vanilla JS, exactly because of this.
Anyway, keep up the enthusiasm, and don't give up. Learn more and have fun :)
I think that you may continue to develop your applications using php or python if you like them. I've used php and I like it. I've considered also python and I like it. But I think my next project will be with Node. I love to use the same language full-stack. God bless
Well said. Its hard to judge without knowing the environment and core of language itself.
PHP can do like that because it mean to be run on server at the first place. But if you want to serve your PHP file and create a server without server like apache/engineX try that. And serve your image :)
Jorge you could do with your own choiches. There a lot of programming language. And they trying to solve some other problem that they may have. And as always God Bless
There is very little JS here, you are amazed by NPM and now.sh while most code is NodeJS's libraries, JSON or HTML.
You made a good tutorial for beginners but nothing really showing how amazing javascript can be.
Because now.sh supports other langages anyone can make the same article with titles such as "PHP is incredible", "GO is the best"...
It sure is nice to see the existence of all theese tools.
And I would love to read those articles. The fact (being true or not) that JS is great doesn't undermine other languages.
Cool guide!
I think the JS ecosystem got a lot of things really right. And it's still developing at speed. Things I like about the JS ecosystem:
npm
,npx
etcpackage.json
)There's definitely things not to love in the JS ecosystem, but that's a topic for another post :-)
Interesting article, thank you, coming from a novice JS developer.
Primarily I am a PHP developer. I prefer MPAs over SPAs. Using the right tool for the right job is important.
Personally, I don't enjoy JavaScript that much. That's just me. However I will use JS if I'm building a real-time application, or high-load HTTPS RESTful APIs. Many times JS is the perfect route to solving a problem, for me at least.
There are many places where JS excels. And places where it fails. For one, I think NPM and the libraries are a mess! So many packages. So many libraries. Some simple frameworks require 800+ packages! There are also security issues involved including SO MANY packages.
But ya know what? In the end, some of those frameworks make it beautifully easy to deploy applications, which is great. <3 (Looking at you Vue and Next.js)
Lots of upsides and downsides. Weight them out. Decide what's best for you.
I hold very strong to this opinion, that we should not be trashing tools. Programming languages are tools.
The JS ecosystem is awesome, wonderful, but bad too. Nothing is perfect. And perfection is subjective to each individual.
Thanks for that beautiful review. I wholeheartedly agree with everything you said.
Yes, absolutely and that's why I state it's awesome ... not perfect.
Well said.
+10 bonus points for being so polite
You could just start with nodejs itself without hassle if you will. Lib are just options 😊
If you want raw, keep it raw do with nodejs itself. They are just tooling same as spring you got your tooling right ahead with that IDE.
The think is that PHP run on server this makes simpler approach of serving images on server, compare it with other languange like JAVA without JAVA Spring, Or C# without ASP.Net :)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.