Josh Collinsworth – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Wed, 09 Feb 2022 21:42:29 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 Josh Collinsworth – CSS-Tricks https://css-tricks.com 32 32 45537868 A Complete Beginner’s Guide to npm https://css-tricks.com/a-complete-beginners-guide-to-npm/ https://css-tricks.com/a-complete-beginners-guide-to-npm/#comments Thu, 20 Jan 2022 15:07:32 +0000 https://css-tricks.com/?p=361210 (This is a sponsored post.)

I remember vividly a period early in my coding career when I began to feel that things were changing away from what I knew, and headed towards a more complex set of tools and …


A Complete Beginner’s Guide to npm originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
(This is a sponsored post.)

I remember vividly a period early in my coding career when I began to feel that things were changing away from what I knew, and headed towards a more complex set of tools and practices, anchored in the command line and something called npm.

This is the first part of a beginner’s guide where we cover the broad topic of Node Package Manager, or npm. We often take those three little letters—npm—for granted as we type them into the command line, but npm is part of a much larger ecosystem that can often be intimidating or confusing to anyone jumping in for the first time. This guide will help de-mystify that ecosystem and help you not only understand what npm is and does, but ultimately feel comfortable working with it.

Guide chapters

  1. Who the Heck is This Guide For? (You are here!)
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?
The npm logo in white against a gradient background tat goes from bright red to orange from left to right to kick off this npm guide.

Modern “back-of-the-front-end” development—which npm is a part of—seems complex because it’s one name for lots of interconnected tools. When you add in the fact that the front-end world seems to move much more quickly than it actually does, producing a feeling that you will be left behind for not jumping on the newest thing right away, everything about it can seem unapproachable.

That’s why we’re starting this guide—to make the technology more accessible for you to use in your own work.

Who the heck is this guide for?

In my own personal development learning journey, I would read guides about technologies that excited me, then get to a part that said “just npm install” this or that, and I’d heave yet another disappointed sigh and give up on using whatever that cool-looking thing was. Or, on more adventurous days, I might copy the command, but then inevitably end up either at another step I didn’t understand (“just,” they always said, “do [some thing I had no idea about]”), or get an error message the guide didn’t explain that stops me in my tracks.

Whatever npm was—whatever those commands did and wherever you were supposed to type them—nobody had ever taken the time to explain it to me. And the more I read guides written by people who took that knowledge for granted, the more I felt isolated.

If any of that sounds familiar: this series is for you.

You most likely fall well within the group that’s been described in recent years as “front-of-the-front-end.” Like me, you probably know your stuff when it comes to HTML and CSS. Maybe you also know some JavaScript, either “vanilla” JavaScript, or by way of jQuery. Either way is fine, both for the purposes of this article and in general.

Maybe you’ve even tried out a framework like React or Vue, but you mostly just copied and pasted some stuff to get your project up and running, and weren’t exactly sure what that stuff actually did.

  • This post is for you if you sense The Great Divide between the more traditional and “modern” definitions of front-end development—and if you worry that you might be hurting your career if you don’t bridge that chasm.
  • This post is for you if you aren’t really sure what all the fuss about terminals and command lines is about, and you’d much prefer to just never touch one at all.
  • This post is for you if you wonder why other developers seem to love making things so damn complicated, and what the point of all that command line junk is in the first place, when you could just write plain, simple HTML, CSS and JavaScript instead.
  • This post is for you if you feel left out. If you sense there’s some thing, some really big thing, that nobody’s ever really bothered explaining to you, and you’re worried you’re the only one who doesn’t get it.

Know this, my fellow front-end developer: you are not alone. You are far from it. You are exactly where I was not so long ago, and the unsettled memory of that place is still fresh in my mind.

Let me try to answer the questions you probably have—the same ones that I had—in the way I wish somebody would have for me, before I even knew how to ask them.

What is covered in this guide

This guide is a series of articles. That’s not because this stuff is extremely difficult to understand in and of itself; it’s because there are many parts to it, and each one bears explanation on its own. This is wide territory with a number of rabbit holes to explore. Focusing on one solid step at a time allows us to spend time on making things clear and understandable. The goal isn’t to cover everything, but I do want to be more thorough than quick.

We’ll start by talking about the current lay of the land; what npm is, a bit about where it came from, and how we got here. From there, we’ll cover what Node itself is, followed by what package managers are in general, before actually working with npm. We’ll finish by installing Node and npm (if they’re not already), initializing a project to get an idea of how it works, and finally, installing a real-life npm project from GitHub with all its packages and commands.

Some (or all) of that may sound very intimidating right now, but don’t worry. That’s why we’re spending the length of an entire guide together.

What to know before we begin

I’ll do my best to assume as little as possible about you, beyond that you are a web developer who generally knows how to build a website with HTML and CSS. You won’t need to know much about JavaScript or write any for the purposes of following this guide, but it will definitely help if you have at least a foundational understanding of what JavaScript is and how it works.

JSON is the only other bit it might be helpful to know before getting started. If you’re unfamiliar with JSON, it might be worth glancing over this guide to JSON, or at least having it ready for when we do get to that part.

Beyond that, I may reference specific tools, projects, and frameworks like Bootstrap, React, Vue and SvelteKit, but I won’t assume you have any any hands-on experience with them whatsoever, nor will I assume that you’ve ever used npm or the command line before.

Ready to get started? Let’s begin by clarifying what we mean by “npm,” such as what it stands for and how it fits into modern web development.


A Complete Beginner’s Guide to npm originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-complete-beginners-guide-to-npm/feed/ 3 361210
What the Heck Does “npm” Mean? https://css-tricks.com/a-clear-definition-of-npm-and-what-it-does/ https://css-tricks.com/a-clear-definition-of-npm-and-what-it-does/#comments Thu, 20 Jan 2022 15:04:15 +0000 https://css-tricks.com/?p=361214 One of the things that makes this new, tooling-heavy era of front-end development so seemingly hard to understand at first is that, while we often call things by a singular name, they tend to be actually comprised of several different …


What the Heck Does “npm” Mean? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
One of the things that makes this new, tooling-heavy era of front-end development so seemingly hard to understand at first is that, while we often call things by a singular name, they tend to be actually comprised of several different interconnected pieces. The same is true for npm and the ecosystem around it.

For example: Think of how we casually refer to “the internet,” even though the web itself is not a single, unified thing, but a collection of protocols, DNS, servers, browsers, networks, requests and responses, plus lots of other things assembled over years of iterations. For that matter, even the browser itself is one machine with many parts.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean? (You are here!)
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

npm is a collection of technologies

In that same way, what we generally think of as “npm” (yes, all lowercase) and “back-of-the-front-end” in particular is a single name for a collection of many different individual technologies and systems; a sort of Rube Goldberg machine to generate browser-friendly code.

I mentioned the command line already; that’s a big part of the ecosystem because it’s how we interact with it. But more on that in the next chapter.

And then there’s npm, which is in a category known as “package management” software. We’ll cover that as well. In fact, you’ll likely see me refer to npm as a package manager throughout this guide.

And finally, there’s Node itself, which is so tricky to explain succinctly I often describe it by paraphrasing Douglas Adams: it’s a programming language that’s almost—but not quite—entirely like JavaScript.

npm manages project tools

To further muddy the waters, many projects where you type npm install into the command line might come with pre-installed tools to help you do a wide variety of things in your project, like process your code (e.g., turn Sass code into CSS). There are many all-in-one, preconfigured projects out there just waiting for you to install them and get started (Create React App, Next, Nuxt, and SvelteKit, to name a few). This is convenient when done well, of course, but it’s also added complexity—meaning many more names we need to add to our list of back-of-the-front-end things.

This list often includes tools like Babel (for compiling JavaScript), Sass (for compiling CSS), webpack (for asset bundling), Vite (for development servers and other tooling), PostCSS (for transforming one syntax into another); Autoprefixer (which can be a PostCSS plugin for CSS vendor prefixes); TypeScript (for additional JavaScript syntax); ESlint (for checking code quality); Prettier (for formatting code), and testing libraries like Jest or Cypress.

The stark stark white interior of a library building with multiple floors and bookcases filled with brightly colored books, illustrating how npm manages front-end development tools.
npm is like a library building with floors of book collections that are organized, making things easier to find and manage. (Photo: Johannes Mändle on Unsplash)

All those things (and more) fall into this broad, general category of tools that often come with npm-installed projects—or that can be installed and used via npm—but are not actually part of npm itself. They’re just examples of modern tools that help us do nice things with our code, and I mention them here only because it’s worth noting the distinction, to get a sense of where the boundaries lie in this large, new world.

And by the way, if you didn’t know what most (or any) of those tools mentioned above are, that’s ok. Maybe you haven’t come across them yet, or maybe you’ve worked on a project that had them installed without knowing them by name. Either way, all of this is merely for additional context.

Let’s break here

If you’re already feeling a bit overwhelmed at this point: don’t sweat it. The key thing I want you to walk away with after reading this specific chapter is that what we think of as “npm” (or maybe more casually as “all that command line, back-end-y stuff”) is not really one thing, but a collection of things that work together to make development easier for us.

And yes: while all that complication seems intimidating up-front, it does actually make things better. I promise.

While front-end seems to move very quickly, no, you have not been left behind. You may just have a bit of continuing education to get caught up on.


What the Heck Does “npm” Mean? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-clear-definition-of-npm-and-what-it-does/feed/ 2 361214
What the Heck is the Command Line? https://css-tricks.com/a-deep-look-at-the-command-line/ https://css-tricks.com/a-deep-look-at-the-command-line/#respond Thu, 20 Jan 2022 15:04:09 +0000 https://css-tricks.com/?p=361226 Now that we know what npm stands for and have a super general idea of what it does and how it fits into web development, we ought to spend a little bit of time looking at the command line, because …


What the Heck is the Command Line? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Now that we know what npm stands for and have a super general idea of what it does and how it fits into web development, we ought to spend a little bit of time looking at the command line, because it’s how we interact with npm.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line? (You are here!)
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

An overview of the command line

The command line is a place we can type (predictably enough) commands to be executed directly by our computer. It’s extremely fast, and allows greater admin permissions than most apps that attempt to handle the command line for you. Need to install something on your system, or perhaps update it? The command line can do that, not to mention uninstall them, too. Heck, even server-side languages can run on the command line, opening up a wide range of tools and development techniques.

It’s for those reasons the command line is considered an indispensable tool for many developers. Even if you’re not a developer, odds are you’ve encountered the command line at some point. Maybe you’ve accessed it when you opened the Terminal app in MacOS. Maybe you’ve used one built directly into your code editor—VS Code and many other code editors come with integrated terminal. Perhaps you’ve even come across third-party terminal apps like iTerm or Hyper.

A collage of screenshots showing a terminal and the command line in different applications.

If you’ve used the terminal, it’s possible that much of your command line usage to this point has simply been typing (or pasting) commands somebody else gave you. That’s fine; that’s often how we get things done.

But let’s take a moment to understand exactly what the command line is, and why it’s so broadly used.

Command line vs. terminal

The “command line” and the “terminal” are technically two different and distinct things, but are often used interchangeably. You may also hear the command line called a “shell” or see it abbreviated as “CLI” which is short for “command line interface.”

Pedantic distinctions aside, the terms are often used to mean pretty much the same thing. So just to keep things as simple as possible, I’ll be using them interchangeably from here on out.

Opening the command line

Whatever you want to call it, you probably know the command line as that scary-looking window, perhaps with a dark background and white (sometimes greenish) text, where you type commands that your computer seems to understand, even if you do not.

Screenshot of a blank open terminal window with a dark background.
By default, a terminal window probably looks something like this, though its appearance can vary.

Depending on where and how you’re working on the command line, one of the first things you might notice is an inconspicuous dollar sign character, $, that’s displayed on the first line where you’re able to start typing. You may have even seen it in other articles or documentation.

This screenshot of Vue’s documentation for using npm includes the $ character in a command example.

It’s common convention to prefix commands with a $ character—but it’s a confusing convention for sure. That’s because there’s no need to type it. It’s literally not part of the command. Instead, $ signifies a command that’s meant to be run in a terminal.

So here’s the first rule to know about working with the command line: if you find yourself typing or copying an instruction that includes the $ character, know that there is no need to include it in your work; the terminal’s got it covered.

## No need to copy the $
$ npm run build

You may see something else beginning a line instead of $, like >, _ , or even an arrow. Again, whatever it is, it’s almost certainly not meant to be typed or pasted directly into the command line. Whether or not documentation or other tutorials should include the starting character of a line is an entirely different conversation (one that Chris has discussed at length). Either way, it has the potential to be confusing, so I want to make sure that’s called out.

What does the command line do?

Movies and TV shows often portray a terminal as something fast-typing hackers use in a dark, secluded room. That’s partly just because it makes for good entertainment for folks who probably wouldn’t know a real terminal from the cascading letters in The Matrix. (Nor should they; I couldn’t tell if a surgery portrayed on a TV show is accurate, and am perfectly content leaving that distinction to the professionals.)

But the command line isn’t exactly for writing code. As the name “command line” implies, it’s for writing commands. I suppose you could say that all coding is commands to some extent, so this is admittedly a bit of a blurry line. But generally speaking, code in a terminal is written differently than it is in a code editor. Instead, you use the terminal to boss your computer around with commands you want it to run immediately.

The advantages of the command line

You may wonder why developers like to work in the command line in the first place. You might prefer a nice app, or graphical user interface (GUI for short, sometimes pronounced “gooey”) where you can see all your options and find the best one visually. That’s perfectly fine, and we’ll talk a bit about GUIs in this chapter and provide examples of them.

Many developers feel that way, even if it doesn’t seem like it. But working within the command line brings some advantages that aren’t always easy to replicate in a visual app.

It grants you god-like system privileges

The command line is what computer science-y people refer to as a “privileged environment.” That might sound like it refers to a Yale frat house, but it just means it’s a place where there are very few restrictions on what you are allowed to do; a place without guardrails.

This is where the command line’s daunting reputation comes from—whatever command you type, as far as it’s valid, is executed immediately and, often, irreversibly. It’s capable of interacting with the hidden files your operating system tries to prevent you from editing. You have the power to access anything in the system. You even have the power to interact with similar core files on a remote server—and we all know the adage that great responsibility comes with that kind of power.

It might be helpful to think of the command line like a lazy security guard. It assumes you always know what you’re doing and lets you right through the entrance. That makes it a bit risky, yes, but it also makes it very powerful, and the perfect choice for certain tasks and projects.

It’s super fast

Another advantage the command line has over typical apps is: it’s fast.

This isn’t always the case; the command line’s speed tends to be overstated and depends largely on the task in question. But when it is faster, it can often be many times faster. Plus, the place where the command line really shines tends to be exactly the place where code projects need speed the most, which is downloading and creating files.

As we’ll see in other chapters of this guide, a key part of what npm does is install things on your machine (usually in a folder that’s designated for the project you’re working on). That’s what makes the command line great for working with a package manager (we’ll get to what that means, too) like npm—it downloads and transmits files between computers—generally much, much faster than, say, using a browser to do it.

The command line enables npm to generate tons of files with incredible speed. The ability to run a single command that installs, updates, or deletes those files together in one fell swoop at high speed makes the terminal the fastest, most efficient tool for many jobs.

It does what other languages cannot

One more other reason working in the terminal is so advantageous is that it’s the place where many of the tools you might want to use in your project are already available to you without any additional setup.

But let’s back up a bit.

When you hear the phrase “server-side language,” you might think of PHP, Ruby, or Java. Maybe it’s even newer entries into the space, like Rust or Go. You might even already know that Node belongs on that list, but if not, forgive me for jumping ahead just a bit.

Anyway, when most people think of server-side languages like these, they tend to think of a web server waiting for requests and then responding to them. WordPress, for example, sits idle until it receives a request that fires up PHP. When you send a new tweet, that’s a request on Twitter’s servers that eventually hits a Ruby method in Rails.

Server-side languages are rightly considered more powerful, so to speak, than web languages. HTML, CSS, and JavaScript are wonderful, but they can’t work with a file system, send email, process images, issue system commands, interact with the operating system, or run scheduled tasks; among many, many other things an app or website might need to do. By default, JavaScript in the browser can’t even run unless somebody is actively looking at the web page in their browser.

It’s normal to think of server-side languages as the powerful engine behind more robust apps and software. And, in many cases, that’s accurate. But let’s take a moment to recognize that for the purpose of running code, your machine is a server. Not a web server although (it could be one, but that would be weird and probably unwise). But a server, nonetheless.

A photo of a laptop that is half-closed with a sheet of paper from a yellow legal pad that says This 9s a server (yes, really), do not close the lid!
You probably don’t think of your machine as a server—nor should you. But it can run server-side programming languages.

You can install and run any of the server-side languages we’ve mentioned, and perhaps you’ve already even done so at some point (or at least tried to). You might have installed PHP so you can run WordPress (though these days there are much nicer ways to do it), or you may have installed Ruby so that you could follow some tutorials about Rails, just as examples.

Or, maybe not. Maybe you’ve never installed a whole dang programming language before. Either way, just know that these languages run on a server rather than a web browser—and for that purpose, your machine is a server.

Beyond that, many of the tools you might want to use with your development workflow—things like Sass for compiling CSS—actually run on server-side languages. So using the command line puts you in the place where all the most powerful tools are readily available.

Using an app instead of the command line

We briefly touched on GUIs earlier in this article. It’s worth noting that some command line tasks have corresponding GUIs that make working with the command line more visual and programmatic.

Good examples include GitHub Desktop (for managing code repositories) and CodeKit (for processing, bundling and compiling assets), though the Source Control tab in VS Code also qualifies. Even though GUIs like these are generally focused on specific duties, they let you get things done through a nice visual user interface, in an actual app window that’s outside of the terminal window.

Screenshot of the CodeKit app after running ESlint showing how an app can visualize the command line.
CodeKit can execute a command to check code formatting with tools like ESLint without directly using the command line.

A GUI is lovely to have as an option, and even though I’ve become quite comfortable working on the command line over the years, I still wish there were more GUIs to do the things the command line makes possible—both for my own convenience and to lower the barrier to entry for new developers.

I believe the reason there aren’t more such apps, however, is because of speed. It’s much quicker and easier to build a command line interface (CLI) than it is to put together a full-fledged app, often by orders of magnitude. So if we want nice things today, the command line is often the place we need to go for them.

What’s next

We just spent some time getting acquainted with the command line. Even though the command line is not specific to npm, it’s core to working with npm. It’s the interface from which we tell the system what to do, granting us incredible powers at the system or server level to complete tasks in large swaths at breakneck speeds. As a package manager, npm is in the business of installing, updating, and deleting files (among other things) for a web project. The command line is how we communicate with npm to do all of that.

Next up, we’re going to break down what npm is a little more by focusing on the first letter in the abbreviation: “n” for Node. What the heck is that and why is it in the name? That’s where we turn our focus next.


What the Heck is the Command Line? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-deep-look-at-the-command-line/feed/ 0 361226
What the Heck is Node? https://css-tricks.com/node-and-how-it-works-with-npm/ https://css-tricks.com/node-and-how-it-works-with-npm/#comments Thu, 20 Jan 2022 15:04:03 +0000 https://css-tricks.com/?p=361241 (This is a sponsored post.)

Here’s what you need to know about Node.js (or simply Node) and how it relates to npm right off the bat:

  • Node is JavaScript, but as a server-side language.
  • This is possible because of


What the Heck is Node? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
(This is a sponsored post.)

Here’s what you need to know about Node.js (or simply Node) and how it relates to npm right off the bat:

  • Node is JavaScript, but as a server-side language.
  • This is possible because of V8, Chromium’s JavaScript engine, which can run on its own, outside the confines of the browser.
  • Node and browser-based JavaScript can be very different, and have different capabilities, though both are JavaScript at their core.
  • You don’t need to know Node to use npm.

As you may know by now, npm stands for Node Package Manager (even if the official npm website displays amusing alternative names in its header on each page load, like “Ninja Pumpkin Mutants”).

The key thing to understand right away is this: “Node” and “Package Manager” are the two big, distinct pieces that combine to make npm.

We’ll cover what a package manager is and why you might consider using one when we get to the next chapter in this npm guide. For now, though, let’s focus on understanding what Node is, as it’s is a key part to understanding modern web development.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node? (You are here!)
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

Node is JavaScript, but without all the browser

You likely know JavaScript primarily as a language that runs in the browser, similar to HTML and CSS. Yes, each of these languages has abstractions and supersets (like HAML for HTML, Sass for CSS, and TypeScript for JavaScript, as examples), as well as compilers and transpilers and all kinds of things that transform them into this shape or that. But ultimately, what these tools generate is vanilla (i.e., pure) code in the correct syntax, as if the abstractions were never used, to run in the browser and in the browser alone.

That’s the thing that took me the longest time to understand, and which, honestly, might be an even bigger missed memo than the whole npm thing. JavaScript doesn’t need a browser anymore in order to run. So, you’ll sometimes see me refer to Node JavaScript when distinguishing between it and “browser-based” JavaScript.

Server-side vs. client-side languages

At this point, I feel it’s worth taking a moment to explore the distinction between client-side languages (HTML, CSS, JavaScript), and server-side languages (basically all the rest of them). I won’t assume you have any experience with server-side languages, like PHP, Ruby, or Python, but if the concept of server-side languages is entirely new to you, it may be worth reading up on what they are. (To summarize: they’re code languages that run purely on a server instead of the browser, and generally have much broader and more powerful capabilities.)

This is relevant because several years ago, circa 2009, there were some very smart people who really liked JavaScript. In particular, they liked how fast JavaScript is (especially compared to the dominant server-side languages at the time, most notably, PHP and Ruby), and they wanted to have JavaScript everywhere, not just in a browser.

Ryan Dahl is the most prominent figure among them, and is credited with the invention of Node (and more recently, Deno, which is an anagram of Node). That’s a fun thing to know, but otherwise not strictly relevant to this topic.

How Node works

What is relevant, though, is that Node is essentially JavaScript as a server-side language that runs outside of the browser.

How is that possible? Under the hood, each browser has its own individual JavaScript engine. This is the part of the browser that actually runs JavaScript. Yes, that’s apparently a separate piece of the browser and not part of the same bits that do the HTML and CSS—which I guess makes sense when you think about the fact that we have literal APIs between the document and JavaScript. Heck, even the concept of a DOM makes more sense when you think of the department that handles JavaScript as a makeshift office down the hall from the HTML department.

The JavaScript engine in Chromium-based browsers is called V8, presumably after a specific kind of car engine (not the “vegetable drink” made mostly of tomato juice). V8 is by far the most popular JavaScript engine. Thanks to ECMAScript standardization efforts over approximately the last 15 years, there aren’t really any major differences between JavaScript engines anymore as far as browsers go. The engine used in Chrome is a lot like the engine that runs in Firefox, which is a lot like Safari, and so on. V8’s popularity these days has less to do with its distinctions, and more to do with Chrome’s self-sustaining ubiquity.

(Side note: Firefox’s JavaScript engine is named SpiderMonkey. That’s not particularly relevant, but it is further proof that Firefox is the coolest.)

Why does this matter? Well, it turns out, you can take the JavaScript engine out of a browser, and with some modification, run it on its own—kind of like if you decided to pull the stereo out of a car, tinker a bit, and make it into a stereo system for your home instead. V8 (and, presumably, a car’s stereo) can function perfectly fine as a standalone unit in any environment.

In other words: V8 makes it possible to run JavaScript anywhere. That’s why we have “Node” JavaScript and “browser-based” JavaScript.

Node is almost (but not exactly) JavaScript

To recap: JavaScript is a server-side language now! It’s called Node, and it could mean you don’t even need to learn anything about other server-side languages. We are front-end developers, and we have super-powers now.

Having said all this, however, Node and the JavaScript you’re used to running in the browser are both similar and very different from each other.

At the risk of veering too far into the weeds here: while both are JavaScript at their core, and while the language and syntax is the same, many staples of JavaScript in the browser (like the window or document, and even the oft-taken-for-granted alert) are not present in a purely server-side Node environment. There is no window, of course, when the language is just running on its own, and not in a browser. New Node JavaScript developers are often surprised to learn that even fetch is actually a browser API, not “pure” JavaScript.

Fear not, however. console.log is still your best friend, and there are many new, environment-specific features of Node JavaScript that differ from the browser’s implementation of JavaScript, such as the process object, which contains all the details about any processes that are currently running.

Node and its ecosystem have often, out of necessity, grown in a very different direction than browser-based JavaScript over the years. (As an obvious example: the syntax for imports between the two has been different for years, and only now is beginning to merge together again. We’ll talk about that a little more in the final chapter.)

Node long held the privilege of being able to move much faster than browsers when it comes to gaining new features, and has had its own set of concerns to deal with as well. It began to power server-side apps the same way Ruby and PHP had been doing for years, even while browsers were still trying to coalesce on standards. This has resulted in Node JavaScript and browser-based JavaScript becoming more like cousins than clones.

Here’s what I think is a fair analogy to explain the differences between the two JavaScript cousins: consider two similar musical instruments, say an upright bass and a modern electric bass guitar. Both instruments are tuned the same, and play the same notes; if you know one, in many ways, you kind of know the other. But while you’ll find it much easier to learn one after you’ve learned the other, playing the new one will be very different from what you’re used to.

The same, but different (Photos: Wikimedia Commons, Unplash)

Similarly, while one developer might write one type of JavaScript and a second developer writes in another type of JavaScript, their jobs are unlikely to look the same.

Node is JavaScript, with the capabilities of other server-side languages mentioned before—things like reading from and writing to the file system, access to system-level APIs, email, the ability to listen for and respond to requests, scheduled tasks… the list goes on.

I won’t say more on that here, but just know that while both are JavaScript at the end of the day, they run in different environments and are each capable of doing some things the other can’t. Even if you’ve written browser-based JavaScript before, Node will still likely feel a bit foreign to you beyond the foundational syntax, and will often be used in very different ways.

Running Node locally

As is generally the case with server-side languages, you do need to install Node before you can use it.

Node is commonly installed alongside npm, together as one, since the package manager part needs Node, and the Node part is more useful with a package manager. (You could say they’re a package deal. No, I will not apologize for that joke. I am a dad, after all.)

I’d like to stress at this point that you don’t need to know anything about Node to use npm. So, even though I’m about to cover some Node examples here, please consider this entire section something that’s nice to know, but inessential to that end. I feel it’s still useful to get a slightly better idea of how Node works, just for the sake of painting a more complete picture.

We will cover how to install Node and npm in an upcoming chapter of this guide. So, if you don’t have it installed already, you can either just glance over this part, or come back here when you do have it ready. Either way, this won’t be crucial for following along with this npm guide.

If you would like to try it out, you can create a new test.js file and put some generic JavaScript in it. Something contrived like the following code that logs some content to the console should do the trick:

console.log('Look, ma, Node hands!')

const oneThroughFive = [1, 2, 3, 4, 5]

oneThroughFive.forEach(number => {
  console.log(number)
})

Let’s say you save that code, then open the command line in a terminal window, navigate to where the file is (using cd, or “change directory”), and run node test.js to get the following output:

Look, ma, Node hands!
1
2
3
4
5

You can also enter node by itself (no filename afterwards) to open an interactive terminal where you can run arbitrary Node JavaScript. If you’ve ever popped open the console in your browser’s DevTools to type out some code, that’s exactly what this is, just on the command line with Node instead.

Try it out if you’d like to, assuming you do have Node installed. But again, this is all just for illustration and not required for using npm.

A screenshot of an open terminal window showing Node version 17.0.1 running and the output from the previous example under it.

What’s next

Everything we covered in this chapter is nifty and hopefully helps to show you (however simply) the way Node works. Remember, while we didn’t cover any specific example of it, Node is capable of doing anything a server-side language can do. It’s hopefully not too hard to picture how running some JavaScript to do virtually anything you can think of on the system level or even on a remote server is very appealing and advantageous.

The concept of Node started as a way to run JavaScript outside of the browser. As such, we have Node-based packages of scripts that are used to help us with front-end development. So how do we install those packages and make sure they’re not only updated but that they can be uninstalled? That’s contained in the last two letters in the npm abbreviation: package manager.

In other words, npm is a tool that manages packages written in Node JavaScript. What exactly is a package manager and how does npm qualify as one? That’s up next in our npm guide.


What the Heck is Node? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/node-and-how-it-works-with-npm/feed/ 4 361241
What the Heck is a Package Manager? https://css-tricks.com/what-the-heck-is-a-package-manager/ https://css-tricks.com/what-the-heck-is-a-package-manager/#respond Thu, 20 Jan 2022 15:03:59 +0000 https://css-tricks.com/?p=361257 If you’re keeping score, so far in this npm guide we’ve developed a general understanding of what npm is—notably, that it stands for Node Package Manager. In the process, we’ve discussed the importance of the command line and how it’s …


What the Heck is a Package Manager? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
If you’re keeping score, so far in this npm guide we’ve developed a general understanding of what npm is—notably, that it stands for Node Package Manager. In the process, we’ve discussed the importance of the command line and how it’s used with npm.

We also looked specifically at the “n” in npm—Node—and learned that Node is a lot like the JavaScript code we write to run on websites in a browser. In fact, Node is JavaScript; it just runs outside of the browser, and is capable of doing different things than its browser-based counterpart.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager? (You are here!)
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

What we mean by “package”

Now let’s turn our attention to the last two letters in npm, namely the “package manager” part. In order to fully understand what npm is, we need to know what a package manager is. So it naturally follows that in order to understand that, we need to understand what the heck a “package” is.

Package” is a catch-all term for any external code files that you pull into a project and use in some way. Perhaps you’ve used jQuery, Bootstrap, or Axios on a project in the past. Those are common examples of packages.

We call these “packages” because they’re “packaged up” and ready to be used. Some languages call them by other names (Ruby calls them “gems” for example), but the concept is the same. At the risk of oversimplifying, a package is code that you didn’t write but got from some public source to use in your project. You know, third-party code.

Or, if you prefer musical parodies for your mnemonic devices:

🎵 When there’s code that you choose
🎵 That’s not yours, but you use
🎵 That’s a package
🎵 When it’s stuff you install
🎵 That you import and call,
🎵 That’s a package

Packages are also often also referred to as “dependencies,” because the code you write depends on them being present. Code written using jQuery’s $ won’t work right if jQuery itself isn’t already loaded, for instance. (For this reason, package managers are also sometimes called “dependency managers.”)

Packages can be big or small in terms of how much code they contain. A package might do something huge that changes how you write your whole project (like an entire framework), or it might do something very small and focused that you sprinkle in only where needed (like a widget, or a helper for a specific task).

Using packages without a package manager

Most likely, if you have used a package in the past, you’ve simply applied it with a script tag in the HTML that pulls from an external URL (ideally from a CDN). Here’s how you might include jQuery in the HTML of your site:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Another approach is to download a copy of the package, add it to your project’s files, and link to it locally, like this:

<script src="/jquery.min.js"></script>

What package managers solve

These two approaches have worked well for years. It’s simple. It’s clean. It generally lets you “set it and forget it” as far as the package goes. So why would you need something else?

You can probably imagine how owning a car might seem unappealing to somebody who has ready access to convenient transit, or who has no need for long-distance travel. (This will tie back into the package manager talk, I promise. Stick with me.)

If you have easy access to convenient and efficient mass transit, then paying a large price for a massive machine that you have to store somewhere, regularly clean, maintain, and fill with costly fuel probably won’t carry much upside from your perspective. In that specific case, the benefits are negligible; the costs are comparatively overwhelming. Someone in that hypothetical position might even wonder why anybody wants a car at all!

I bring up this analogy because learning about a new technology can be very hard when it solves a problem you don’t have, in very much the same way that buying a car might fail to solve transportation you already have. It might seem like a massive, needless expenditure.

What a package manager solves, then, is more a matter of scaling and handling concerns. Simply linking to a package in a script tag works well, as long as:

  • the number of projects you have is manageable;
  • the number of people working on the projects is manageable;
  • the number of updates that need to be made to the packages are manageable; and, most crucially,
  • every package used in your projects is client-side (browser) JavaScript or CSS.

That last one is the doozy, because there’s a plethora of tooling you can’t ever use if you only run things in the browser (more on that in a moment).

If you do check all of those boxes, you might not ever outgrow this approach. Your development approach might just look like this:

A black and white line illustration showing the diagram of packages with a package manager. A cloud labelled packages is followed by three files, HTML, CSS, and JavaScript, which are followed by the browser.

But even in that case, when you have multiple <script> tags, each linking to a specific version of some script or library, the only way to get any visibility at all into what packages you’re using—and whether they’re up-to-date—is to go manually open up the HTML and look at the code.

That’s not much of an issue in and of itself, but it’s a problem that grows exponentially as the size and scope of a project ramps up. You may be able to keep track of a few packages manually, but how could you possibly do that when we’re talking about hundreds—if not thousands—of packages? And even if you could manually track those, that’s still introducing a high risk of human error.

It’s not HTML’s job to be the source of truth for all of the packages used on a project. Aside from mixing concerns, it also potentially introduces conflicts when trying to merge unrelated work between teammates.

All this is important, but it’s the smallest part of a larger problem. Understand that client-side JavaScript probably isn’t the only type of package you’ll want to include in your projects forever, even if it is at the moment—and that’s where things really start to fall apart.

Many production apps use some combination of the following tools and packages, if not all of them:

  • Sass (makes writing CSS easier)
  • PostCSS (enhances CSS for maximum efficiency and compatibility)
  • Babel (transpiles newer JavaScript to run in older browsers)
  • TypeScript (adds type checking to JavaScript)
  • Hot module reloading by a dev server that auto-refreshes the browser to show your changes
  • Additional utilities for code bundling, minification and/or concatenation
  • Automatic image compression
  • Testing libraries
  • Linters

That all sounds wonderful—and it is!—but notice that you now have multiple dependencies that are not only not present in your script tags, but are not accounted for anywhere in your project at all! There’s no way for anybody—including your future self—to have any idea what tools were used or are required to to get this project running.

And even if you could know exactly what the project needed that way, you’d still need to go locate, download, and install all of those packages yourself… manually. Depending on the project, this could easily be a day-long task, or longer.

All this means your workflow now looks a little more like this:

A black and white line illustration showing the diagram of packages without a package manager. A group that consists of templates, Sass, and TypeScript or followed by static HTML, CSS, and JavaScript files, which are followed by a group that contains PostCSS and Babel, which is followed by a build tool, which is followed by two forks, one the dev server preview and the other the production browser.
Again, this is all good. This toolchain means that what gets shipped to the browser is highly optimized—but it’s also additional overhead and complexity.

Convenient as all the tools above are, you still need to manage them. Dependencies are projects, too, and they ship updates to patch bugs and introduce new features. As such, it’s unrealistic to simply paste a script tag in the HTML with a link that points to package on a CDN then call it good. You have to make sure each thing is installed and working properly not just on your machine, but on every collaborator’s machine, too.

Package managers exist to make the packages—or dependencies—of a project manageable by knowing what is installed, what’s available to update, and whether one package might create conflicts with another. And the beauty of a package manager is that it accomplishes all of this directly from the command line, with minimal effort.

Many package managers, especially npm, also provide additional features that open up even more possibilities to make development more efficient. But managing packages is the main attraction.

There are package managers that aren’t npm

This part isn’t super relevant to npm itself, but for the sake of completeness, I should also mention that npm isn’t the only JavaScript package manager. For example, you may see Yarn referenced in code examples. Yarn and npm work much the same way, to the extent that a great deal of interoperability between the two is purposely built in.

Some folks prefer one package manager over another. Personally, I think the differences between npm and Yarn were more pronounced at first, but the two are now more similar than not.

You may see code examples (including some in CSS-Tricks articles) that reference both yarn and npm together. That’s to let the reader know that either approach is fine, rather than the need to use both of them together.

The syntax for Yarn and npm differ at times, but where only one is present, it’s generally trivial to convert a command or project from one to the other. Functionally, it rarely (if ever) matters which one you use—except, of course, that everybody working on the same project together will want to be using the same one to ensure compatibility and consistency.

While npm and Yarn make up the vast majority of package managers that developers use, there’s another package manager called PnPm that is effectively npm, but more performant and efficient. The tradeoff is that PnPm requires a bit more technical know-how in some cases, so it’s a bit more of an advanced option.

Three examples of installing Vite in terminal via command line. First is npm, then Yarn, then PNPM.
The syntax differences between different package managers are generally minimal. (Source: Vite)

What makes npm the “standard” package manager

Again, I only bring up other package managers to illustrate that npm isn’t the only package manager out there—but it is generally the standard.

What makes it the “standard” among package managers? Other languages, including Ruby and PHP, have had package managers for many years; JavaScript really didn’t have any good ones before npm.

npm started as an independent, open-source project, but was acquired by Microsoft in 2020. It technically has two parts: the actual package manager itself; and the package registry, which is an ever-growing list of nearly two million packages available to install.

You could think of npm as the app store for anything you might want to use on a front-end or Node-based project. Find what you want and install it to your system via the command line. You might update that package when a new version is released, or delete it altogether if the project no longer depends on it.

A note on npx

You may also see npx commands floating out there. npx is actually a part of npm, but by using npx in a command instead of npm , you can execute the code of a package without permanently installing it. NPX just installs what it needs to, runs it, and dumps it.

This is helpful if, for example, you want to run an installer script. Rather than downloading the installer, then running it, npx lets you simply run the installer directly, leaving nothing on your machine afterward. It’s like the house guest that cleans up after themselves.

Another cool example: you could run npx sass (along with the necessary input and output arguments) if you wanted to compile your project’s Sass files just once without going to the trouble of completely installing Sass. This probably isn’t practical in most cases, but if you just needed a quick one-off compilation here and there, npx would be a handy way to do it, as it means fewer installed packages that need to be updated and maintained.

What’s next

Alright, so that’s a deep dive into what we mean when we call something a package manager. In the case of npm, it is used specifically to install and manage Node packages, tools that help add features to a project, add handy developer conveniences… or all of the above!

Next up, we’re going to take our first step into using npm. And to do that, we need to install it to our system. That’s next up in this complete guide to npm.


What the Heck is a Package Manager? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/what-the-heck-is-a-package-manager/feed/ 0 361257
How the Heck Do You Install npm? https://css-tricks.com/how-to-install-npm-node-nvm/ https://css-tricks.com/how-to-install-npm-node-nvm/#comments Thu, 20 Jan 2022 15:03:53 +0000 https://css-tricks.com/?p=361270 Feel like you have a pretty good idea of what a package manager is? We’ve certainly covered a lot of ground getting familiar with all the terms and concepts of package managers, but I’d say it’s high time we actually …


How the Heck Do You Install npm? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Feel like you have a pretty good idea of what a package manager is? We’ve certainly covered a lot of ground getting familiar with all the terms and concepts of package managers, but I’d say it’s high time we actually do something with our newfound knowledge. But first, we need to install npm.

To that end, we’re going to make sure we have Node and npm installed, then make a little sample project to give you real hands-on experience working with the npm basics and what it looks like to use npm in your front-end development workflow.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm? (You are here!)
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

Confirm whether npm is already installed

Before installing npm, we should confirm whether it’s already installed! If you’re unsure whether or not npm is already installed on your system, open your terminal of choice, whether it’s the Terminal app in MacOS, the integrated terminal in a code editor like VS Code, or some other terminal where you have access to the command line.

Ready? Start with this command (notice we’re not including the $ character in these examples):

node -v

That command displays the current version of Node—that is, if it is installed. If Node is installed, the command line will respond with the Node version number that is currently installed:

v16.9.1

Your version may be different, of course. Either way, the fact that you see a version number confirms that npm is installed on your system! Let me stress that the numbers themselves are unimportant, just as long as we get some version number.

If npm or Node is not currently installed, you’ll see a message along the lines of “Command not found” instead. In the unlikely event that npm is installed but Node is not (or vice versa), then it’s probably worth uninstalling it before continuing.

Assuming you do need to install npm and Node (and if you don’t, you’re welcome to skip ahead to the next section), we’re going to take the advice of the official NPM directions and do so via a program called nvm.

Installing Node Version Manager

Node Version Manager, or nvm, allows you to install, update, and uninstall Node on your system, and also to manage multiple versions of Node that you can switch between.

Screenshot of the Node Version Manager repository on GitHub which is closely related to how to install npm in terms of installing Node itself.
The Node Version Manager repository on GitHub

As you may know, server-side languages have their own release versions, e.g., Node 17.1.0, rather than being tied to browser versions, such as Chrome 96. We won’t need any version of Node but the latest, so this won’t be necessary for us right now, although it may be advantageous for you down the road.

I know, it may seem like a lot of extra work to install one program just to install another, but again, this is the recommended path, and doing things the right way from the start makes them much easier in the long run. I’d rather set you up for success than make things briefly easier at the expense of more complexity later.

Installing nvm on Windows

If you’re on Windows, you’ll actually have an easier time here. You’ll need nvm for Windows specifically, but luckily, Windows already has an installer you simply download and run. The directions are in the NVM for Windows repo over at GitHub.

  • Download the latest version of NVM for Windows. It can be installed manually, if you prefer.
  • Open the terminal and run the nvm list available command to see a list of Node versions that are available to download and install.
  • Run the nvm use command, followed by the version number of Node you want to use (e.g. nvm use 16.9.1) to use a specific version. Alternatively, you can use use latest, lts, or newest instead of a specific version number, where newest is the latest installed version.

Once it’s installed, nvm will work the same way on your Windows machine as it does on any other system.

Installing nvm on MacOS

To install nvm on MacOS, the first step is to download it with this command:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

0.39.0 is the latest version at publish time, but it may be worth checking the nvm installation readme and getting the latest, if different.

Once you’ve pasted that command into the terminal and hit Enter, you’ll see your terminal output a bunch of stuff that doesn’t really matter. In fact, I’ll let you in on a little secret: nobody reads the things in their terminals most of the time. All we care about is that…

  1. the command eventually finishes; and
  2. it doesn’t end with an error message.

If you are prompted for a command in the middle of the installation, hit the q key to quit and continue.

You’ll know the command is finished running when the typing cursor starts blinking again, indicating the terminal is waiting for your typed input. You might even see this right after nvm has completed installing:

=> Close and reopen your terminal to start using nvm or run the following to use it now:

Assuming you see no errors at this point, I would recommend the simpler option of quitting and restarting whatever terminal app you’re using before moving on. It’s a nice way to make sure you’re working with a clean slate.

How to install npm via Node

Now that nvm is installed, we’re ready to do what we really wanted to do in the first place: install npm and Node on our system.

It’s not a bad idea to confirm nvm is installed properly, by running nvm -v. If the terminal shows you the installed version number, you’re good to go! If not, remember that you might have to restart your terminal app before the installation fully processes.

Now that we have nvm, installing Node is a super short command:

nvm install node

Simple enough, eh?

You should see a message along the lines of Downloading and installing node v17.1.0, though the version number may not match, which is fine. You’ll get whatever the latest stable version is at runtime. Wait until the command has finished running—again, you’ll know it’s done once you are back at the default prompt and you’re able to type more commands.

After that, you’re all done here! That simple command not only installs Node, but it will install npm as well. Again, you can verify everything is installed and up to date with npm -v and node -v. If all is good, you’ll get a version number.

What’s next

Alright, at this point, we have nvm for installing and managing Node, Node itself, and npm for handling Node packages. Next up in this npm guide, we’re going to install some packages into a project!


How the Heck Do You Install npm? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/how-to-install-npm-node-nvm/feed/ 3 361270
How the Heck Do You Install npm Packages? https://css-tricks.com/how-to-install-npm-packages/ https://css-tricks.com/how-to-install-npm-packages/#comments Thu, 20 Jan 2022 15:03:49 +0000 https://css-tricks.com/?p=361300 By now, you’re becoming quite knowledgeable with npm! So far, we’ve broken down the three letters in “npm” to gain a better understand of Node and package managers. In the previous chapter, we even installed Node and npm while …


How the Heck Do You Install npm Packages? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
By now, you’re becoming quite knowledgeable with npm! So far, we’ve broken down the three letters in “npm” to gain a better understand of Node and package managers. In the previous chapter, we even installed Node and npm while getting acquainted with Node Version Manager, or nvm. Next up in this beginner’s guide to npm is likely why you’re here in the first place: installing npm packages.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages? (You are here!)
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project?

A quick example

We can install our very first package with the npm install command (or npm i for short), followed by the name of the packages we want to add to our project. For example, the Node package for Sass is simply called “sass” which means we can add to a project like this (just be sure you’re in a new folder you created for this little project first):

npm install sass

That’s all you need! Type that and npm goes straight to work:

Screenshot of a dark terminal window with a project called nom-test. The first command is npm install which adds 17 total npm packages with zero vulnerabilities.

What’s happening behind the scenes there is that npm tries to find a package named sass in the npm package registry. If it finds that package (which it does), npm installs it to the project in an automatically generated node_modules folder (more on this in a bit) located in the project root folder, including everything the package needs to run. (This is why you see that npm added 16 packages and audited a total of 17 npm packages, instead of the Sass package alone—it, too, has dependencies!)

Once we’ve run the install command, you may notice that you do not see anything named “sass” in the project folder as you might expect. Oddly, however, we do see a three new items in the project folder: two JSON files named package.json and package-lock.json, plus one entirely new node_modules folder.

Screenshot of the VS Code editor with a package.json file open. The file contains the project name, npm-test, and includes a dependencies section that contains the Sass npm package.

What are these!? We asked npm to install Sass, not all this stuff. That’s not part of Sass… right? Well, that’s correct, but there’s a very good explanation why those new items were generated in the project folder. Let’s look at what just happened.

What happens when you install a package

When you install (or uninstall, or update) a package, npm does most, if not all, of the following four things:

  1. Updates the package.json file in your project, if needed;
  2. updates the package-lock.json file (called the “lockfile”) that contains all of the technical specifics;
  3. installs the actual package files—and any other packages the original package might depend on (inside of the node_modules folder); and
  4. runs an audit of the installed packages.

Let’s step through those one-by-one.

package.json and package-lock.json

These two JSON files work together to ensure an accurate record of all the dependencies in your project (and all of their dependencies, and all of their dependencies’ dependencies, and so on). The difference is a little technical, but loosely explained: the lockfile is the in-depth, precise snapshot of the project’s dependency tree, and package.json is a high level overview, which can also contain other things. The main packages you install may be listed in package.json, but package-lock.json is where the entire dependency tree is tracked.

The lockfile is also never supposed to be updated by hand; only by npm. So be sure to avoid mistaking the lockfile with the package.json file.

When you share or collaborate with others on a project, npm knows where the project came from and exactly what you have installed in the project by these two files. It can replicate that environment precisely on anyone else’s machine, thanks to their info. Both files are meant to be committed to your Git repo, and serve as your project’s dependency blueprint. That way, when another developer on your team clones the repo and runs the npm install command, npm knows exactly which packages to install, keeping you and your colleague in sync.

If you open package.json, you won’t see much, but it’s worth a peek just to see what’s happening:

{
  "dependencies": {
    "sass": "^1.43.4"
  }
}

You probably won’t see that exact version number (since the package has been updated since the time of writing), but you should see sass listed inside a JSON dependencies object. The number itself (1.43.4 in this case) indicates the specific version of Sass that is installed.

As a brief but important side tangent: the carat character (^) at the beginning of the version number lets npm know that it is allowed to install minor updates to the package. In other words, it tells npm that the installed Sass package must be at least version 1.43.4, but can be any higher 1.x.x version, as long as it’s still under 2.0.0. npm generally chooses the latest stable version when a package is installed, but adds this to allow for non-breaking updates. That bit is called “semantic versioning” and it’s a blog post unto itself, but not unique to npm.

Anyway, that covers the two JSON files. Let’s talk about the node_modules folder next.

node_modules

node_modules is where all the actual package code lives; it’s where your installed Node packages and all the stuff that makes them run actually get installed. If you open up the folder right now as you’re following along, you’ll find a sass folder, but alongside several other folders as well.

The reason for the additional folders is that when you install a package, it may need other packages to run properly (as Sass clearly does). So, npm automatically does the hard work of finding and installing all of those dependencies as well. As you may have guessed, those dependencies may also have other dependencies of their own, and so the process repeats, so on and so forth, until we’ve finished crawling the dependency tree to its furthest branches and absolutely everything we need is installed (or until we’ve hit an error of some kind, though hopefully not).

For this reason, it’s common for a project to have node_modules subfolders in the hundreds or more, which add up quickly in terms of disk space. node_modules can often get pretty hefty.

If you’re wondering how you would commit a super large folder like node_modules to a project’s repository, here’s an important note: Unlike the JSON files, the node_modules folder is not meant to be committed to Git, or even shared. In fact, just about every example of a .gitignore file (the file that tells which files Git should skip when tracking files) includes node_modules to ensure Git never touches or tracks it.

So, how does anyone else on your team get those packages? They run npm install (or npm i for short) from the command line to download the dependencies directly from the source. This way, there’s no need to commit (or pull) massive amounts of data to and from the origin repo.

Using caution when installing dependencies

This massive web of dependencies and their great-great-grand-dependencies can lead to situations where a small utility library of some kind that provides a useful service can become adopted by many other packages, which are, in turn, used in many other packages, until eventually the original code winds up quietly installed on a significant percentage of sites and apps.

It might sound wild (if not downright scary) that, in the process of installing your one package, you may actually be letting a whole bunch of other stuff through the door. It can feel like inviting a new friend to your house party, who then shows up with 20 uninvited strangers. But it’s not as weird or scary as it may seem, for a few reasons:

  1. Most npm packages are open source. You and anybody else can easily peek under the hood and see exactly what the package is doing. You can also look the package up on the registry (npmjs.com) to see how many times it’s been installed, when it was last updated, and other relevant info. If a package is fairly popular, you can be reasonably certain it’s safe.
  2. There’s a vast world of functionality that many projects will need. Consider date formatting, handling HTTP requests and responses, throttling, debouncing, or animations, just as quick examples. It doesn’t make sense to keep reinventing the wheel and hand-coding these things every time they’re used in a new project.
  3. Installing a package isn’t really that different than installing an app on your phone, or a plugin on a WordPress site. The difference is that we don’t get the same glimpse into the inner workings of those apps and plugins the way we do with packages, nor what other things those apps and plugins might rely on. Odds are good they pull in many smaller packages, too, in some way or another.

A degree of caution is a good idea in any environment in which one can install and execute arbitrary code, of course. Don’t get me wrong. I’d be lying if I said bad actors have never successfully taken advantage of this system. But know that there are many processes in place to keep things from going awry. When in doubt, stick with the most popular packages and you’ll be fine.

Also know that npm runs automatic security audits for you, which brings us to the final point in this section.

What is npm audit?

When we installed sass earlier, we saw the following message in the terminal once it finished:

found 0 vulnerabilities

However, you may see some warnings instead—like this old project of mine in the following image. I decided to boot it up and run npm install (npm i) after it’s sat for at least a couple of years. Let’s see how it did:

Screenshot of an open terminal window showing the process of installing npm packages with the npm i command. 212 npm packages are installed but the terminal shows there are 93 vulnerabilities, where 46 are moderate, 42 are high, and 5 are critical.
YIKES!

Packages with known vulnerabilities are called out by npm audit, which runs automatically any time you install a package. If you see a message like this, don’t be too alarmed; many vulnerabilities, especially in the “moderate” category, carry very low real-world risk, and may only be relevant in highly specific situations. (For example, it may only be one method in a package, when used in a particular way, that makes it vulnerable.)

Still, it’s best to address what we can, which is what the npm audit fix command is for. Adding fix to the end tells npm to go ahead and update to a new minor version of any package with a known vulnerability of some kind. The “minor version” part is important; minor versions aren’t supposed to contain breaking changes, only updates. That means it should be safe to run an update this way without any risk of breaking your project.

If bumping the package up by a minor version number doesn’t do the trick, you can add the --force flag to the original command:

npm audit fix --force

This is a risky maneuver, however. Giving npm permission to “use the force” means it can now install major version updates to address vulnerabilities—which means it may make breaking changes or introduce incompatibilities. I wouldn’t recommend doing this unless there are critical vulnerabilities that npm audit fix is unable address and you are willing and able to spend significant time afterwards troubleshooting, if necessary.

One last note on this topic: it helps to know that you can sometimes fix some unexpected issues with npm projects by deleting node_modules, and re-running npm install. That’s the npm way of “turning things off and on again,” which is something I’ve done many, many times myself.

What’s next

Now that we’ve thoroughly explored the rabbit hole of how npm works under the hood, let’s get back to actually doing things, shall we?


How the Heck Do You Install npm Packages? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/how-to-install-npm-packages/feed/ 5 361300
What the Heck Are npm Commands? https://css-tricks.com/what-the-heck-are-npm-commands/ https://css-tricks.com/what-the-heck-are-npm-commands/#respond Thu, 20 Jan 2022 15:03:44 +0000 https://css-tricks.com/?p=361320 npm is, as you now know, a package manager. But like similar, earlier tools that run tasks in the command line, such as Grunt and Gulp, npm can also run tasks—which is perfect for us because now that …


What the Heck Are npm Commands? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
npm is, as you now know, a package manager. But like similar, earlier tools that run tasks in the command line, such as Grunt and Gulp, npm can also run tasks—which is perfect for us because now that we installed the Sass package in the previous chapter, we can starting using it!

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands? (You are here!)
  9. How the Heck Do You Install an Existing npm Project?

Jumping into npm commands

Open the package.json file in your test folder, and you won’t see much right now; just a dependencies property, with only one dependency so far:

{
  "dependencies": {
    "sass": "^1.43.4"
  }
}

The package.json file is home to much more than just dependencies, however. It contains lots of meta-info about your project too. One of the most interesting bits is an optional, but extremely useful property called scripts.

Remember, all the sub-dependencies of Sass are tracked in package-lock.json, which is auto-generated, and shouldn’t be edited by hand. package.json generally just contains the top-level dependencies, and we can customize it freely.

The scripts object in your package.json file allows you to create commands you can run in that project to handle various tasks for you, either as a one-shot, or a continuously running process. Generally, these “tasks” are used for things like starting up a dev server for local development, compiling assets, and/or running tests. In fact, there’s often a single start or dev command built into projects to handle all the tasks you might need to run concurrently, like compiling Sass and JavaScript in the same sequence.

We don’t have any scripts to run yet, but let’s fix that!

Example: Compiling Sass into CSS

Inside of the scripts section of the package.json file, we have access to all of our installed packages. Even though we are unable to simply type sass commands in the terminal right now, we can run sass commands as part of an npm script.

We could run sass commands in the terminal if Sass were installed globally, which means system-wide, rather than installed in a specific project folder. So far, we’ve only installed Sass to this folder (that’s what happens by default when you install a package). But a global installation would make sass commands available anywhere on the system.

Start by pasting this block of code into your package.json file, right after the opening { curly brace:

"scripts": {
  "sass:build": "sass style.scss style.css"
},

JSON syntax is very strict. Try running the file’s contents through a JSON validator if you get stuck.

This gives us access to an npm run sass:build script, which will compile Sass into CSS for us!

The name of the command is unimportant, as long as it’s one continuous string. Also worth noting is that the colon (:) doesn’t do anything special here; it’s just convention, since either build or sass on its own would likely be too generic.

If you’ve worked with Sass commands before—or if you were peeking ahead—you probably know this means we also need to create a style.scss file in the root of our project folder. Let’s do that, and toss some arbitrary Sass code into it.

Screenshot of the VS Code app with an open style.scss file. The file contains a Sass color variable and one selector that's nested three levels deep.
The style.scss file sits alongside the JSON files and node_modules folder at the top level of the project folder.

Here’s the Sass code I used, if you’d like to copy and paste it:

$myColor: #ffd100;

.a {
  .nested {
    .selector {
      color: $myColor;
    }
  }
}

Great! Save that file as style.scss in the root of your project, and let’s try running our new command:

npm run sass:build

Once this task has completed, you should see two new files appear almost instantly in your project folder: style.css and style.css.map.

Screenshot of the VS Code app with a style.scss file open and an open terminal below that with npm commands, including npm run sass:build.
After running npm run sass:build, you should see style.css and style.css.map file appear in the top level of the project folder.

If you like, you can pop open the style.css file—which contains the compiled CSS code—to verify that it is indeed what we expect:

Screenshot of the VS Code app with a compiled style.css file open showing how the npm command to run Sass has processed the Sass code into normal CSS. An open terminal is below it showing the npm commands that were used.
Look at that, pure CSS!

The sass package even goes so far as to compile a source map for us, which lets us see what styles came from what .scss files when we inspect them in a browser’s DevTools. How nice!

If you hit an error: double check the syntax inside of package.json to make sure it is valid JSON (here’s an online JSON validator you can use), and that your .scss file contains valid Sass (here’s an online Sass converter). Another thing to check is that the name of the file matches the name in the command.

Creating a development-only command

This is pretty neat, but we’ll probably get tired of running that command over and over as we’re developing. So, let’s set up a second command that tells Sass to watch the file for us, and re-compile it automatically any time we save changes!

Add this inside the scripts object in package.json:

"sass:watch": "sass style.scss style.css --watch"

Important note: Make sure there is a comma (,) between the two scripts. The order doesn’t matter, but the comma between them does. Again, JSON is strict, so lean on the JSON validator if needed.

Now, if we run sass:watch (not to be confused with sasquatch), you’ll see a message in your terminal saying, “Sass is watching for changes. Press Ctrl-C to stop.”

If you open your style.scss file now, make a change, and save it, you should see a message automatically pop up in the terminal confirming that the Sass has re-compiled into CSS:

A screenshot of text from the terminal saying that Sass is watching for changes. Press control plus c to stop. Below that it says that the style.scss file has compiled into a style.css file.

Now that’s useful! Not only that, but once we commit these files to our repo, we’ll have the exact directions to get Sass installed and up and running, with a simple command—and so will everybody else who works on this project!

We’ll leave things here on this test project. It was useful to see how to get started, but more often than not, you’ll be reaching for a pre-configured project, rather than creating npm commands them from scratch, which is exactly what we’ll do next, in the final chapter of this npm guide.

Final notes on installing npm packages

You should know that there are actually two ways to install npm packages, and which one you want depends on whether the package is meant to be a part of the production build, or whether it’s purely for development purposes.

  • npm install (or npm i) is the standard (and default) way to add a package to a project.
  • npm install --save-dev (or npm i -D) only adds the package to your “dev dependencies,” which means they’ll only be installed when developing the project, and not when building the finalized production version of the project.

Packages installed as development dependencies might include testing libraries, linters, preview servers, and other tools that help you during the development process only. They aren’t typically used to compile or run the website itself.

There’s one final flag worth knowing about: npm install --global (or npm i -g). This is how to install a package globally, as we discussed a little earlier when installing Sass. You could use this if, for example, you want to be able to run sass anywhere on your machine. Other common use cases for global installation might include CLI tools that you’d want to use everywhere, or even another package manager, like Yarn.

What’s next

We’re nearing the conclusion of our journey! There’s one last thing you ought to know, and how to use npm to quickly spin up everything you need on an existing project. So, let’s say you inherit a project that uses npm. Where do you start? How do you make sure you’re collaborating with others consistently? That’s the focus of the last section of this npm guide.


What the Heck Are npm Commands? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/what-the-heck-are-npm-commands/feed/ 0 361320
How the Heck Do You Install an Existing npm Project? https://css-tricks.com/how-to-install-an-npm-project/ https://css-tricks.com/how-to-install-an-npm-project/#comments Thu, 20 Jan 2022 15:03:35 +0000 https://css-tricks.com/?p=361337 (This is a sponsored post.)

We’ve gotten a good overview of how npm works and how to use it to install packages and run commands at this point. Now let’s go a little further and see what it looks …


How the Heck Do You Install an Existing npm Project? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
(This is a sponsored post.)

We’ve gotten a good overview of how npm works and how to use it to install packages and run commands at this point. Now let’s go a little further and see what it looks like to download and install an existing npm project, rather than starting one from scratch. More likely than not, that’s probably what you’ll be doing most of the time. It’s much, much easier than installing and configuring all the individual pieces one by one.

That’s what we’re covering in this final chapter of the guide to npm, and I’ll be drawing from personal experience on a real-life project of mine.

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project? (You are here!)

Here’s a real-life npm project

The project I’ve chosen for this is my own SvelteKit static blog starter. I think it’s a nice example because it comes with lots of pre-installed packages that are great for demonstration purposes.

This is a real project of mine that’s designed to give you—as you might have guessed by the name—a head-start for building a statically-generated blog site. (“Statically generated” means that our code will be compiled down to .html files, ready to deploy anywhere on the web. This is one of a few approaches encompassed in the “Jamstack” way of building sites.)

And no worries if you don’t know anything about SvelteKit—this is just to demonstrate, and we won’t write anything you don’t already know. That said, it’s worth noting that SvelteKit uses Vite under the hood, which is actually a npm package that gives us access to modern build tools and a super speedy development server.

Cloning the project

First, we need to “clone” the project, which is a fancy word for copying the project to our system so we can work on it locally. There are two ways to clone an existing project.

If you prefer the in-browser, visual way, head to the starter repo over at GitHub, and click the “Code” dropdown that’s located directly in GitHub’s UI, and select the “Download ZIP” option.

A screenshot of a GitHub repo zoomed in to the top-right corner of the page with the Code button clicked and showing options to clone the repository. The option to download a ZIP file has a big white arrow pointing at it towards the left to call it out for this existing npm project.

Alternatively, if you prefer using the command line instead, run this command (just make sure you’re in a place where you don’t mind a new project folder added to your computer, e.g. cd /path/to/folder):

npx degit https://github.com/josh-collinsworth/sveltekit-blog-starter.git sveltekit-blog-starter

You may remember that npx allows us to run npm packages without permanently installing them. degit clones the project just like git clone would, but without its Git history (literally, “de-git”).

Whichever method you use, you get a fresh new sveltekit-blog-starter folder. Let’s open it in a code editor, pop open the terminal, and run the npm install (or npm i) command.

An open dark Terminal that has run the npm i command to install an existing npm project called sveltekit-blocg-starter. 202 npm packages are installed in three seconds. There are zero vulnerabilities.
npm automatically runs an audit when installing packages.

At this point, you’ll see a note about vulnerabilities, like we covered in the last section of this guide. It may say something like “found 0 vulnerabilities” (as it does in screenshot above), but it’s quite possible that number will be greater than zero. If you do see vulnerabilities, don’t worry. You’re free to ignore it for now since this isn’t a project we intend to launch in production for others to see or use. (See the section on npm audit in a previous chapter for more info.)

Starting the server and making changes

If you were to peek inside of the package.json file in the cloned project, you’d see the command to start the dev server:

npm run dev

Run that command in the terminal and you should see something like the following almost immediately:

An open dark terminal window that ran the npm run dev command. The terminal output shows that a localhost address has been set up where the development for the project can be previewed.

In VS Code, you can press CMD while clicking the http://localhost:3000 URL, or you can manually enter it in your browser. Either way, the site should be displayed in the browser!

A screenshot of a website that is open at a localhost URL, demonstrating that the development server for the npm project is running and can be viewed in the browser. The site has a light aqua header with a My Awesome Blog heading followed by three navigation links, all centered in the container. After that is the main body of the page with a faint pale green background and darker text, including a heading that says SvelteKit static blog starter followed by a short description of the project and an unordered list of features.

Let’s take just a moment here to appreciate how relatively fast and simple that was! Yes, we might have had to install a bunch of scaffolding first, but that’s an up-front, one-time cost. We have an entire project running on our machine with just a couple of commands—and we can do this same thing any time we want to install another existing project!

I won’t go deep into the details of this particular project because it’s unimportant to learning npm, but it’s a nice example because it has lots of cool things pre-configured, and we can easily make changes and see them update right away in the browser. Let’s look at a few of those commands next.

SvelteKit requires Node 14 or higher. If you installed npm as part of this guide, that won’t be a problem for you. But if you already had it installed before we started, and if you run into errors trying to get this project running, it’s worth a quick node -v to be sure. nvm is your friend if you need to upgrade.

Automatically compile Sass on save

You can find the project’s Sass files in the src/lib/assets/scss/ folder. Try opening the global.scss file directly. Make a change, save it, and you should see the update automatically (and almost instantly) in your browser.

An animated GIF showing the development site preview open on the left and the VS Code editor on the write with a global.scss file open. The body font size is changed in the Sass code, then saved, which triggers an immediate new preview in the browser without having to manually reload the page.

Making content changes

The starter site actually uses the repo’s README.md file as its homepage. If you open README.md and begin making changes (it’s OK if you don’t know Markdown, any edit will do), you should also see those changes show up as soon as you save just like Sass did in the last step:

If you want, you can open another page, say the src/routes/contact.svelte file, and update the HTML to see it live refresh in your browser as well as soon as it saves.

You can even duplicate one of the Markdown files inside of src/lib/posts/ and make edits to see that it automatically appear in the list of posts on the /blog page, if you want to go that far. (Just be sure to give it a unique title.)

Understanding imports

There’s one important thing about npm projects that we mentioned briefly in the fourth chapter, but haven’t covered yet: imports. This guide wouldn’t really be complete if we didn’t touch on that. The basic idea is that we can—true to the name—import a package in our code, and use it on the spot.

How so? Open up the svelte.config.js folder in the project root, and you’ll see a block of import lines at the top, something like this:

import adapter from '@sveltejs/adapter-static'
import { mdsvex } from 'mdsvex'
import preprocess from 'svelte-preprocess'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeSlug from 'rehype-slug'

Every one of those imports is an installed package used in this file. What each package actually does isn’t important right now; I just want to call attention to the import syntax. This is how we use packages in our actual code files; we tell JavaScript what to import and from where. Then we can call it in our code.

This syntax is called “ES6 imports,” which is only important (get it?!) to know because it’s the standard that both browser-based JavaScript and Node JavaScript have agreed on using going forward.

Previously, Node JavaScript used (and often still uses) a slightly different syntax called CommonJS. If you see an import that looks like this, that’s the old CommonJS style:

const myPackage = require('package-name')

The other crucial thing to understand about the ES6 style of import is: the syntax is npm-specific, not a language standard.

To be clear: you can use import in normal JavaScript. It’s a very ordinary feature of the language to export a variable, function, object, etc. from one file, and import it to use in another. But to do that, you need to provide a relative path, or (in more modern browsers) a URL to whatever you’re importing. Just using a string with a package’s slug, like we see here, isn’t valid.

So why is it used if it’s not technically valid code? Because handling this style of import is one of the nice things npm does for us. When we tell npm to import somePackage from 'name' as a string without a path, npm automatically knows to go search through the installed packages on the project to find the import what we asked for. This saves us from both typing tedious relative paths, and from actually needing to know where our packages live deep in the labyrinth of node_modules.

This may go without saying, but: since the syntax isn’t valid, you won’t be able to use it successfully unless your npm project includes a bundler or compiler of some kind, to process the imports and modules into valid browser code.

Building the final site

Most npm projects like this have two main purposes:

  1. Help you develop your site or app
  2. Build a finalized, production version

SvelteKit is no exception. When we’re done with our (awesome) development server setup and happy with our changes, we can run this command:

npm run build

If your dev server is still running, you can either stop it with Ctrl+C, or open up a new terminal tab. You won’t be able to type any commands in the same terminal window where the dev process is running since it’s an active, continuous task.

When we run the build command, SvelteKit chews through all the files in the project and spits out a fully bundled, ready-to-deploy collection of static HTML, CSS and JavaScript files, and does so rather quickly. You could upload this collection of files anywhere you can host a website. Modern tooling; good old-fashioned output.

When the build command finishes, you should see a new build folder in the root (i.e. top level) of your project folder. If you look through it, you’ll notice there are no longer .md, .svelte, or any other files that can’t be read by a browser. Everything has been compiled into pure HTML, CSS and JavaScript, not to mention—as you’ll see if you open a JavaScript or CSS file—they are thoroughly minified to be as small as possible to load in the browser as fast as possible.

If you want, you can run npm run preview once the build is finished to see how the compiled site loads in the browser. The difference here is that the content will be loaded from the final build folder, rather than built with pre-compiled files on the fly as it would when using the dev command. You won’t see any difference unless you open up the Network tab in DevTools (or try to update something), but you’ll be looking at the final product.

This is an optional step, but I think it’s pretty cool to get an idea of how few compiled files we actually end up with, considering all the various files we put into the project, and how tiny the final bundle actually is, thanks to the amazing build tools built into this project. (For the record, it’s all SvelteKit and Vite.)

Modern deployment practices

This is a topic for another time, but modern deployment often doesn’t require you to run a build command and upload the files yourself (though that’s still an option). Instead, a host (like Netlify or Vercel) connects directly to the GitHub repo of your project and, whenever you push changes to the main branch of the repo, the host runs your build command for you and deploys the compiled files automatically!

That’s one of the many extremely nice features of this new era of front-end development. No messing with FTP or manually dragging files anywhere; we are confident that everything is built and deployed automatically when we push our code, without us needing to do anything!

Wrapping up this npm guide

If you’ve made it this far, congratulations! And thank you. Congratulations, because this was a long, long read. And thank you, because… well, it was a long, long read.

But you made it, and hopefully, you learned some important things as well. I mentioned at the start that my goal was not brevity, but effectiveness. That means we covered a lot. We started with a brief overview of npm and where it fits in the modern front-end development landscape before getting familiar with the command line. From there, we broke down the terms “Node” and “package manager” to get a precise understanding of what npm is and does. Once we got acquainted with the role that packages managers play in development, we dove straight into npm, including how to install it, add packages to a project, set up commands, and finally, how to jump into an existing project that uses npm.

My hope is that everything we covered in this npm guide at least opens the door enough for you to explore npm further and level up when you’re ready. It often takes me repeating something many times and trying multiple approaches for something to truly sink in. So, if you’re sitting there feeling almost as confused as you were before, take some more time on this. Reflect on what you know and what you’ve learned, and come back—or try a new approach when you’re ready!

Guide chapters

  1. Who the Heck is This Guide For?
  2. What the Heck Does “npm” Mean?
  3. What the Heck is the Command Line?
  4. What the Heck is Node?
  5. What the Heck is a Package Manager?
  6. How the Heck Do You Install npm?
  7. How the Heck Do You Install npm Packages?
  8. What the Heck Are npm Commands?
  9. How the Heck Do You Install an Existing npm Project? (You are here!)

How the Heck Do You Install an Existing npm Project? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/how-to-install-an-npm-project/feed/ 16 361337
What I Learned Building a Word Game App With Nuxt on Google Play https://css-tricks.com/what-i-learned-building-a-word-game-app-with-nuxt-on-google-play/ https://css-tricks.com/what-i-learned-building-a-word-game-app-with-nuxt-on-google-play/#comments Tue, 25 May 2021 14:25:06 +0000 https://css-tricks.com/?p=340759 I fell in love with coding the moment I created my first CSS :hover effect. Years later, that initial bite into interactivity on the web led me to a new goal: making a game.

Table of contents


What I Learned Building a Word Game App With Nuxt on Google Play originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I fell in love with coding the moment I created my first CSS :hover effect. Years later, that initial bite into interactivity on the web led me to a new goal: making a game.


Those early moments playing with :hover were nothing special, or even useful. I remember making a responsive grid of blue squares (made with float, if that gives you an idea of the timeline), each of which turned orange when the cursor moved over them. I spent what felt like hours mousing over the boxes, resizing the window to watch them change size and alignment, then doing it all over again. It felt like pure magic.

What I built on the web naturally became more complex than that grid of <div> elements over the years, but the thrill of bringing something truly interactive to life always stuck with me. And as I learned more and more about JavaScript, I especially loved making games.

Sometimes it was just a CodePen demo; sometimes it was a small side project deployed on Vercel or Netlify. I loved the challenge of recreating games like color flood, hangman, or Connect Four in a browser.

After a while, though, the goal got bigger: what if I made an actual game? Not just a web app; a real live, honest-to-goodness, download-from-an-app-store game. Last August, I started working on my most ambitious project to date, and four months later, I released it to the world (read: got tired of fiddling with it): a word game app that I call Quina.

What’s the game (and what’s that name)?

The easiest way to explain Quina is: it’s Mastermind, but with five-letter words. In fact, Mastermind is actually a version of a classic pen-and-paper game; Quina is simply another variation on that same original game.

The object of Quina is to guess a secret five-letter word. After each guess, you get a clue that tells you how close your guess is to the code word. You use that clue to refine your next guess, and so on, but you only get ten total guesses; run out and you lose.

Example Quina gameplay

The name “Quina” came about because it means “five at a time” in Latin (or so Google told me, anyway). The traditional game is usually played with four-letter words, or sometimes four digits (or in the case of Mastermind, four colors); Quina uses five-letter words with no repeated letters, so it felt fitting that the game should have a name that plays by its own rules. (I have no idea how the original Latin word was pronounced, but I say it “QUINN-ah,” which is probably wrong, but hey, it’s my game, right?)

I spent my evenings and weekends over the course of about four months building the app. I’d like to spend this article talking about the tech behind the game, the decisions involved, and lessons learned in case this is a road you’re interested in traveling down yourself.

Choosing Nuxt

I’m a huge fan of Vue, and wanted to use this project as a way to expand my knowledge of its ecosystem. I considered using another framework (I’ve also built projects in Svelte and React), but I felt Nuxt hit the sweet spot of familiarity, ease of use, and maturity. (By the way, if you didn’t know or hadn’t guessed: Nuxt could be fairly described as the Vue equivalent of Next.js.)

I hadn’t gone too deep with Nuxt previously; just a couple of very small apps. But I knew Nuxt can compile to a static app, which is just what I wanted — no (Node) servers to worry about. I also knew Nuxt could handle routing as easily as dropping Vue components into a /pages folder, which was very appealing.

Plus, though Vuex (the official state management in Vue) isn’t terribly complex on its own, I appreciated the way that Nuxt adds just a little bit of sugar to make it even simpler. (Nuxt makes things easy in a variety of ways, by the way, such as not requiring you to explicitly import your components before you can use them; you can just put them in the markup and Nuxt will figure it out and auto-import as needed.)

Finally, I knew ahead of time I was building a Progressive Web App (PWA), so the fact that there’s already a Nuxt PWA module to help build out all the features involved (such as a service worker for offline capability) already packaged up and ready to go was a big draw. In fact, there’s an impressive array of Nuxt modules available for any unseen hurdles. That made Nuxt the easiest, most obvious choice, and one I never regretted.

I ended up using more of the modules as I went, including the stellar Nuxt Content module, which allows you to write page content in Markdown, or even a mixture of Markdown and Vue components. I used that feature for the “FAQs” page and the “How to Play” page as well (since writing in Markdown is so much nicer than hard-coding HTML pages).

Achieving native app feel with the web

Quina would eventually find a home on the Google Play Store, but regardless of how or where it was played, I wanted it to feel like a full-fledged app from the get-go.

To start, that meant an optional dark mode, and a setting to reduce motion for optimal usability, like many native apps have (and in the case of reduced motion, like anything with animations should have).

Under the hood, both of the settings are ultimately booleans in the app’s Vuex data store. When true, the setting renders a specific class in the app’s default layout. Nuxt layouts are Vue templates that “wrap” all of your content, and render on all (or many) pages of your app (commonly used for things like shared headers and footers, but also useful for global settings):

<!-- layouts/default.vue -->
<template>
  <div
    :class="[
      {
        'dark-mode': darkMode,
        'reduce-motion': reduceMotion,
      },
      'dots',
    ]"
  >
    <Nuxt />
  </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters(['darkMode', 'reduceMotion']),
  },
  // Other layout component code here
}
</script>

Speaking of settings: though the web app is split into several different pages — menu, settings, about, play, etc. — the shared global Vuex data store helps to keep things in sync and feeling seamless between areas of the app (since the user will adjust their settings on one page, and see them apply to the game on another).

Every setting in the app is also synced to both localStorage and the Vuex store, which allows saving and loading values between sessions, on top of keeping track of settings as the user navigates between pages.

And speaking of navigation: moving between pages is another area where I felt there was a lot of opportunity to make Quina feel like a native app, by adding full-page transitions.

Nuxt page transitions in action

Vue transitions are fairly straightforward in general—you just write specifically-named CSS classes for your “to” and “from” transition states—but Nuxt goes a step further and allows you to set full page transitions with only a single line in a page’s Vue file:

<!-- A page component, e.g., pages/Options.vue -->
<script>
export default {
  transition: 'page-slide'
  // ... The rest of the component properties
}
</script>

That transition property is powerful; it lets Nuxt know we want the page-slide transition applied to this page whenever we navigate to or away from it. From there, all we need to do is define the classes that handle the animation, as you would with any Vue transition. Here’s my page-slide SCSS:

/* assets/css/_animations.scss */

.page-slide {
  &-enter-active {
    transition: all 0.35s cubic-bezier(0, 0.25, 0, 0.75);
  }

  &-leave-active {
    transition: all 0.35s cubic-bezier(0.75, 0, 1, 0.75);
  }

  &-enter,
  &-leave-to {
    opacity: 0;
    transform: translateY(1rem);

    .reduce-motion & {
      transform: none !important;
    }
  }

  &-leave-to {
    transform: translateY(-1rem);
  }
}

Notice the .reduce-motion class; that’s what we talked about in the layout file just above. It prevents visual movement when the user has indicated they prefer reduced motion (either via media query or manual setting), by disabling any transform properties (which seemed to warrant usage of the divisive !important flag). The opacity is still allowed to fade in and out, however, since this isn’t really movement.

Comparing default motion (left) with reduced motion (right)

Side note on transitions and handling 404s: The transitions and routing are, of course, handled by JavaScript under the hood (Vue Router, to be exact), but I ran into a frustrating issue where scripts would stop running on idle pages (for example, if the user left the app or tab open in the background for a while). When coming back to those idle pages and clicking a link, Vue Router would have stopped running, and so the link would be treated as relative and 404.

Example: the /faq page goes idle; the user comes back to it and clicks the link to visit the /options page. The app would attempt to go to /faq/options, which of course doesn’t exist.

My solution to this was a custom error.vue page (this is a Nuxt page that automatically handles all errors), where I’d run validation on the incoming path and redirect to the end of the path.

// layouts/error.vue
mounted() {
  const lastPage = '/' + this.$route.fullPath.split('/').pop()
  // Don't create a redirect loop
  if (lastPage !== this.$route.fullPath) {
    this.$router.push({
      path: lastPage,
    })
  }
}

This worked for my use case because a) I don’t have any nested routes; and b) at the end of it, if the path isn’t valid, it still hits a 404.

Vibration and sound

Transitions are nice, but I also knew Quina wouldn’t feel like a native app — especially on a smartphone — without both vibration and sound.

Vibration is relatively easy to achieve in browsers these days, thanks to the Navigator API. Most modern browsers simply allow you to call window.navigator.vibrate() to give the user a little buzz or series of buzzes — or, using a very short duration, a tiny bit of tactile feedback, like when you tap a key on a smartphone keyboard.

Obviously, you want to use vibration sparingly, for a few reasons. First, because too much can easily become a bad user experience; and second, because not all devices/browsers support it, so you need to be very careful about how and where you attempt to call the vibrate() function, lest you cause an error that shuts down the currently running script.

Personally, my solution was to set a Vuex getter to verify that the user is allowing vibration (it can be disabled from the settings page); that the current context is the client, not the server; and finally, that the function exists in the current browser. (ES2020 optional chaining would have worked here as well for that last part.)

// store/getters.js
vibration(state) {
  if (
    process.client &&
    state.options.vibration &&
    typeof window.navigator.vibrate !== 'undefined'
  ) {
    return true
  }
  return false
},

Side note: Checking for process.client is important in Nuxt — and many other frameworks with code that may run on Node — since window won’t always exist. This is true even if you’re using Nuxt in static mode, since the components are validated in Node during build time. process.client (and its opposite, process.server ) are Nuxt niceties that just validate the code’s current environment at runtime, so they’re perfect for isolating browser-only code.

Sound is another key part of the app’s user experience. Rather than make my own effects (which would’ve undoubtedly added dozens more hours to the project), I mixed samples from a few artists who know better what they’re doing in that realm, and who offered some free game sounds online. (See the app’s FAQs for full info.)

Users can set the volume they prefer, or shut the sound off entirely. This, and the vibration, are also set in localStorage on the user’s browser as well as synced to the Vuex store. This approach allows us to set a “permanent” setting saved in the browser, but without the need to retrieve it from the browser every time it’s referenced. (Sounds, for example, check the current volume level each time one is played, and the latency of waiting on a localStorage call every time that happens could be enough to kill the experience.)

An aside on sound

It turns out that for whatever reason, Safari is extremely laggy when it comes to sound. All the clicks, boops and dings would take a noticeable amount of time after the event that triggered them to actually play in Safari, especially on iOS. That was a deal-breaker, and a rabbit hole I spent a good amount of hours despairingly tunneling down.

Fortunately, I found a library called Howler.js that solves cross-platform sound issues quite easily (and that also has a fun little logo). Simply installing Howler as a dependency and running all of the app’s sounds through it — basically one or two lines of code — was enough to solve the issue.

The Howler.js logo, featuring a cute little howler monkey wearing headphones

If you’re building a JavaScript app with synchronous sound, I’d highly recommend using Howler, as I have no idea what Safari’s issue was or how Howler solves it. Nothing I tried worked, so I’m happy just having the issue resolved easily with very little overhead or code modification.

Gameplay, history, and awards

Quina can be a difficult game, especially at first, so there are a couple of ways to adjust the difficulty of the game to suit your personal preference:

  1. You can choose what kind of words you want to get as code words: Basic (common English words), Tricky (words that are either more obscure or harder to spell), or Random (a weighted mix of the two).
  2. You can choose whether to receive a hint at the start of each game, and if so, how much that hint reveals.
Quina offers several different ways to play, to accommodate players of all skill levels

These settings allow players of various skill, age, and/or English proficiency to play the game on their own level. (A Basic word set with strong hints would be the easiest; Tricky or Random with no hints would be the hardest.)

“Soft hints” reveal one letter in the code word (but not its position)

While simply playing a series of one-off games with adjustable difficulty might be enjoyable enough, that would feel more like a standard web app or demo than a real, full-fledged game. So, in keeping with the pursuit of that native app feel, Quina tracks your game history, shows your play statistics in a number of different ways, and offers several “awards” for various achievements.

Quina tracks the results of all games played, your longest win streaks, and many other stats

Under the hood, each game is saved as an object that looks something like this:

{
  guessesUsed: 3,
  difficulty: 'tricky',
  win: true,
  hint: 'none',
}

The app catalogues your games played (again, via Vuex state synced to localStorage) in the form of a gameHistory array of game objects, which the app then uses to display your stats — such as your win/loss ratio, how many games you’ve played, and your average guesses — as well as to show your progress towards the game’s “awards.”

This is all done easily enough with various Vuex getters, each of which utilizes JavaScript array methods, like .filter() and .reduce(), on the gameHistory array. For example, this is the getter that shows how many games the user has won while playing on the “tricky” setting:

// store/getters.js
trickyGamesWon(state) {
  return state.gameHistory.filter(
    (game) => game.win && game.difficulty === 'tricky'
  ).length
},

There are many other getters of varying complexity. (The one to determine the user’s longest win streak was particularly gnarly.)

Adding awards was a matter of creating an array of award objects, each tied to a specific Vuex getter, and each with a requirement.threshold property indicating when that award was unlocked (i.e., when the value returned by the getter was high enough). Here’s a sample:

// assets/js/awards.js
export default [
  {
    title: 'Onset',
    requirement: {
      getter: 'totalGamesPlayed',
      threshold: 1,
      text: 'Play your first game of Quina',
    }
  },
  {
    title: 'Sharp',
    requirement: {
      getter: 'trickyGamesWon',
      threshold: 10,
      text: 'Win ten total games on Tricky',
    },
  },
]

From there, it’s a pretty straightforward matter of looping over the achievements in a Vue template file to get the final output, using its requirement.text property (though there’s a good deal of math and animation added to fill the gauges to show the user’s progress towards achieving the award):

Awards are unlocked and displayed if a player’s progress is above the threshold; otherwise, the game displays the progress bar with an indication of how much is left until the award is unlocked.

There are 25 awards in all (that’s 5 × 5, in keeping with the theme) for various achievements like winning a certain number of games, trying out all the game modes, or even winning a game within your first three guesses. (That one is called “Lucky” — as an added little Easter egg, the name of each award is also a potential code word, i.e., five letters with no repeats.)

Unlocking awards doesn’t do anything except give you bragging rights, but some of them are pretty difficult to achieve. (It took me a few weeks after releasing to get them all!)

Pros and cons of this approach

There’s a lot to love about the “build once, deploy everywhere” strategy, but it also comes with some drawbacks:

Pros

  • You only need to deploy your store app once. After that, all updates can just be website deploys. (This is much quicker than waiting for an app store release.)
  • Build once. This is sorta true, but turned out to be not quite as straightforward as I thought due to Google’s payments policy (more on that later).
  • Everything is a browser. Your app is always running in the environment you’re used to, whether the user realizes it or not.

Cons

  • Event handlers can get really tricky. Since your code is running on all platforms simultaneously, you have to anticipate any and all types of user input at once. Some elements in the app can be tapped, clicked, long-pressed, and also respond differently to various keyboard keys; it can be tricky to handle all of those at once without any of the handlers stepping on each other’s toes.
  • You may have to split experiences. This will depend on what your app is doing, but there were some things I needed to show only for users on the Android app and others that were only for web. (I go into a little more detail on how I solved this in another section below.)
  • Everything is a browser. You’re not worried about what version of Android your users are on, but you are worried about what their default browser is (because the app will use their default browser behind the scenes). Typically on Android this will mean Chrome, but you do have to account for every possibility.

Logistics: turning a web app into a native app

There’s a lot of technology out there that makes the “build for the web, release everywhere” promise — React Native, Cordova, Ionic, Meteor, and NativeScript, just to name a few.

Generally, these boil down to two categories:

  1. You write your code the way a framework wants you to (not exactly the way you normally would), and the framework transforms it into a legitimate native app;
  2. You write your code the usual way, and the tech just wraps a native “shell” around your web tech and essentially disguises it as a native app.

The first approach may seem like the more desirable of the two (since at the end of it all you theoretically end up with a “real” native app), but I also found it comes with the biggest hurdles. Every platform or product requires you to learn its way of doing things, and that way is bound to be a whole ecosystem and framework unto itself. The promise of “just write what you know” is a pretty strong overstatement in my experience. I’d guess in a year or two a lot of those problems will be solved, but right now, you still feel a sizable gap between writing web code and shipping a native app.

On the other hand, the second approach is viable because of a thing called “TWA,” which is what makes it possible to make a website into an app in the first place.

What is a TWA app?

TWA stands for Trusted Web Activity — and since that answer is not likely to be helpful at all, let’s break that down a bit more, shall we?

A TWA app basically turns a website (or web app, if you want to split hairs) into a native app, with the help of a little UI trickery.

You could think of a TWA app as a browser in disguise. It’s an Android app without any internals, except for a web browser. The TWA app is pointed to a specific web URL, and whenever the app is booted, rather than doing normal native app stuff, it just loads that website instead  —  full-screen, with no browser controls, effectively making the website look and behave as though it were a full-fledged native app.

TWA requirements

It’s easy to see the appeal of wrapping up a website in a native app. However, not just any old site or URL qualifies; in order to launch your web site/app as a TWA native app, you’ll need to check the following boxes:

  • Your site/app must be a PWA. Google offers a validation check as part of Lighthouse, or you can check with Bubblewrap (more on that in a bit).
  • You must generate the app bundle/APK yourself; it’s not quite as easy as just submitting the URL of your progressive web app and having all the work done for you. (Don’t worry; we’ll cover a way to do this even if you know nothing about native app development.)
  • You must have a matching secure key, both in the Android app and uploaded to your web app at a specific URL.

That last point is where the “trusted” part comes in; a TWA app will check its own key, then verify that the key on your web app matches it, to ensure it’s loading the right site (presumably, to prevent malicious hijacking of app URLs). If the key doesn’t match or isn’t found, the app will still work, but the TWA functionality will be gone; it will just load the web site in a plain browser, chrome and all. So the key is extremely important to the experience of the app. (You could say it’s a key part. Sorry not sorry.)

Advantages and drawbacks of building a TWA app

The main advantage of a TWA app is that it doesn’t require you to change your code at all — no framework or platform to learn; you’re just building a website/web app like normal, and once you’ve got that done, you’ve basically got the app code done, too.

The main drawback, however, is that (despite helping to usher in the modern age of the web and JavaScript), Apple is not in favor of TWA apps; you can’t list them in the Apple App store. Only Google Play.

This may sound like a deal-breaker, but bear a few things in mind:

  • Remember, to list your app in the first place, it needs to be a PWA — which means it’s installable by default. Users on any platform can still add it to their device’s home screen from the browser. It doesn’t need to be in the Apple App Store to be installed on Apple devices (though it certainly misses out on the discoverability). So you could still build a marketing landing page into your app and prompt users to install it from there.
  • There’s also nothing to prevent you from developing a native iOS app using a completely different strategy. Even if you wanted both iOS and Android apps, as long as a web app is also part of the plan, having a TWA effectively cuts out half of that work.
  • Finally, while iOS has about a 50% market share in predominantly English-speaking countries and Japan, Android has well over 90% of the rest of the world. So, depending on your audience, missing out on the App Store may not be as impactful as you might think.

How to generate the Android App APK

At this point you might be saying, this TWA business sounds all well and good, but how do I actually take my site/app and shove it into an Android app?

The answer comes in the form of a lovely little CLI tool called Bubblewrap.

You can think of Bubblewrap as a tool that takes some input and options from you, and generates an Android app (specifically, an APK, one of the file formats allowed by the Google Play Store) out of the input.

Installing Bubblewrap is a little tricky, and while using it is not quite plug-and-play, it’s definitely far more within reach for an average front-end dev than any other comparable options that I found. The README file on Bubblewrap’s NPM page goes into the details, but as a brief overview:

Install Bubblewrap by running npm i -g @bubblewrap/cli (I’m assuming here you’re familiar with NPM and installing packages from it via the command line). That will allow you to use Bubblewrap anywhere.

Once it’s installed, you’ll run:

bubblewrap init --manifest https://your-webapp-domain/manifest.json

Note: the manifest.json file is required of all PWAs, and Bubblewrap needs the URL to that file, not just your app. Also be warned: depending on how your manifest file is generated, its name may be unique to each build. (Nuxt’s PWA module appends a unique UUID to the file name, for example.)

Also note that by default, Bubblewrap will validate that your web app is a valid PWA as part of this process. For some reason, when I was going through this process, the check kept coming back negative, despite Lighthouse confirming that it was in fact a fully functional progressive web app. Fortunately, Bubblewrap allows you to skip this check with the --skipPwaValidation flag.

If this is your first time using Bubblewrap, it will then ask if you want it to install the Java Development Kit (JDK) and Android Software Development Kit (SDK) for you. These two are the behind-the-scenes utilities required to generate an Android app. If you’re not sure, hit “Y” for yes.

Note: Bubblewrap expects these two development kits to exist in very specific locations, and won’t work properly if they’re not there. You can run bubblewrap doctor to verify, or see the full Bubblewrap CLI README.

After everything’s installed — assuming it finds your manifest.json file at the provided URL — Bubblewrap will ask some questions about your app.

Many of the questions are either preference (like your app’s main color) or just confirming basic details (like the domain and entry point for the app), and most will be pre-filled from your site’s manifest file.

Other questions that may already be pre-filled by your manifest include where to find your app’s various icons (to use as the home screen icon, status bar icon, etc.), what color the splash screen should be while the app is opening, and the app’s screen orientation, in case you want to force portrait or landscape. Bubblewrap will also ask if you want to request permission for your user’s geolocation, and whether you’re opting into Play Billing.

However, there are a few important questions that may be a little confusing, so let’s cover those here:

  • Application ID: This appears to be a Java convention, but each app needs a unique ID string that’s generally 2–3 dot-separated sections (e.g., collinsworth.quina.app). It doesn’t actually matter what this is; it’s not functional, it’s just convention. The only important thing is that you remember it, and that it’s unique. But do note that this will become part of your app’s unique Google Play Store URL. (For this reason, you cannot upload a new bundle with a previously used App ID, so make sure you’re happy with your ID.)
  • Starting version: This doesn’t matter at the moment, but the Play Store will require you to increment the version as you upload new bundles, and you cannot upload the same version twice. So I’d recommend starting at 0 or 1.
  • Display mode: There are actually a few ways that TWA apps can display your site. Here, you most likely want to choose either standalone (full-screen, but with the native status bar at the top), or fullscreen (no status bar). I personally chose the default standalone option, as I didn’t see any reason to hide the user’s status bar in-app, but you might choose differently depending on what your app does.

The signing key

The final piece of the puzzle is the signing key. This is the most important part. This key is what connects your progressive web app to this Android app. If the key the app is expecting doesn’t match what’s found in your PWA, again: your app will still work, but it will not look like a native app when the user opens it; it’ll just be a normal browser window.

There are two approaches here that are a little too complex to go into in detail, but I’ll try to give some pointers:

  1. Generate your own keystore. You can have Bubblewrap do this, or use a CLI tool called keytool (appropriately enough), but either way: be very careful. You need to explicitly track the exact name and passwords for your keystores, and since you’re creating both on the command line, you need to be extremely careful of special characters that could mess up the whole process. (Special characters may be interpreted differently on the command line, even when input as part of a password prompt.)
  2. Allow Google to handle your keys. This honestly isn’t dramatically simpler in my experience, but it saves some of the trouble of wrangling your own signing keys by allowing you to go into the Google Play Developer console, and download a pre-generated key for your app.

Whichever option you choose, there’s in-depth documentation on app signing here (written for Android apps, but most of it is still relevant).

The part where you get the key onto your personal site is covered in this guide to verifying Android app links. To crudely summarize: Google will look for a /.well-known/assetlinks.json file at that exact path on your site. The file needs to contain your unique key hash as well as a few other details:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target" : { "namespace": "android_app", "package_name": "your.app.id",
               "sha256_cert_fingerprints": ["your:unique:hash:here"] }
}]

What you should know about listing an app

Before you get started, there are also some hurdles to be aware of on the app store side of things:

  • First and foremost, you need to sign up before you can publish to the Google Play Store. This eligibility costs a one-time $25 USD fee.
  • Once approved, know that listing an app is neither quick nor easy. It’s more tedious than difficult or technical, but Google reviews every single app and update on the store, and requires you to fill out a lot of forms and info about both yourself and your app before you can even start the review process — which itself can take many days, even if your app isn’t even public yet. (Friendly heads-up: there’s been a “we’re experiencing longer than usual review times” warning banner in the Play console dashboard for at least six months now.)
    • Among the more tedious parts: you must upload several images of your app in action before your review can even begin. These will eventually become the images shown in the store listing — and bear in mind that changing them will also kick off a new review, so come to the table prepared if you want to minimize turnaround time.
    • You also need to provide links to your app’s terms of service and privacy policy (which is the only reason my app even has them, since they’re all but pointless).
    • There are lots of things you can’t undo. For example, you can never change a free app to paid, even if it hasn’t publicly launched yet and/or has zero downloads. You also have to be strict on versioning and naming with what you upload, because Google doesn’t let you overwrite or delete your apps or uploaded bundles, and doesn’t always let you revert other settings in the dashboard, either. If you have a “just jump in and work out the kinks later” approach (like me), you may find yourself starting over from scratch at least once or twice.
  • With a few exceptions, Google has extremely restrictive policies about collecting payments in an app. When I was building, it was charging a 30% fee on all transactions (they’ve since conditionally lowered that to 15% — better, but still five times more than most other payment providers would charge). Google also forces developers (with a few exceptions) to use its own native payment platform; no opting for Square, Stripe, PayPal, etc. in-app.
    • Fun fact: this policy had been announced but wasn’t in effect yet while I was trying to release Quina, and it still got flagged by the reviewer for being in violation. So they definitely take this policy very seriously.

Monetization, unlockables, and getting around Google

While my goal with Quina was mostly personal — challenge myself, prove I could, and learn more about the Vue ecosystem in a complex real-world app — I had also hoped as a secondary goal that my work might be able to make a little money on the side for me and my family.

Not a lot. I never had illusions of building the next Candy Crush (nor the ethical void required to engineer an addiction-fueled micro-transaction machine). But since I had poured hundreds of hours of my time and energy into the game, I had hoped that maybe I could make something in return, even if it was just a little beer money.

Initially, I didn’t love the idea of trying to sell the app or lock its content, so I decided to add a simple “would you care to support Quina if you like it?” prompt after every so many games, and make some of the content unlockable specifically for supporters. (Word sets are limited in size by default, and some game settings are initially locked as well.) The prompt to support Quina can be permanently dismissed (I’m not a monster), and any donation unlocks everything; no tiered access or benefits.

This was all fairly straightforward to implement thanks to Stripe, even without a server; it’s all completely client-side. I just import a bit of JavaScript on the /support page, using Nuxt’s handy head function (which adds items to the <head> element specifically on the given page):

// pages/support.vue
head() {
  return {
    script: [
      {
        hid: 'stripe',
        src: 'https://js.stripe.com/v3',
        defer: true,
        callback: () => {
          // Adds all Stripe methods like redirectToCheckout to page component
          this.stripe = Stripe('your_stripe_id')
        },
      },
    ],
  }
},

With that bit in place (along with a sprinkle of templating and logic), users can choose their donation amount — set up as products on the Stripe side — and be redirected to Stripe to complete payment, then returned when finished. For each tier, the return redirect URL is slightly different via query parameters. Vue Router parses the URL to adjust the user’s stored donation history, and unlock features accordingly.

You might wonder why I’m revealing all of this, since it exposes the system as fairly easy to reverse-engineer. The answer is: I don’t care. In fact, I added a free tier myself, so you don’t even have to go to the trouble. I decided that if somebody really wanted the unlockables but couldn’t or wouldn’t pay for whatever reason, that’s fine. Maybe they live in a situation where $3 is a lot of money. Maybe they gave on one device already. Maybe they’ll do something else nice instead. But honestly, even if their intentions aren’t good: so what?

I appreciate support, but this isn’t my living, and I’m not trying to build a dopamine tollbooth. Besides, I’m not personally comfortable with the ethical implications of using a stack of totally open-source and/or free software (not to mention the accompanying mountain of documentation, blog posts, and Stack Overflow answers written about all of it) to build a closed garden for personal profit.

So, if you like Quina and can support it: sincerely, thank you. That means a ton to me. I love to see my work being enjoyed. But if not: that’s cool. If you want the “free” option, it’s there for you.

Anyway, this whole plan hit a snag when I learned about Google Play’s new monetization policy, effective this year. You can read it yourself, but to summarize: if you make money through a Google Play app and you’re not a nonprofit, you gotta go through Google Pay and pay a hefty fee — you are not allowed to use any other payment provider.

This meant I couldn’t even list the app; it would be blocked just for having a “support” page with payments that don’t go through Google. (I suppose I probably could have gotten around this by registering a nonprofit, but that seemed like the wrong way to go about it, on a number of levels.)

My eventual solution was to charge for the app itself on Google Play, by listing it for $2.99 (rather than my previously planned price of “free”), and simply altering the app experience for Android users accordingly.

Customizing the app experience for Google Play

Fortunately enough, Android apps send a custom header with the app’s unique ID when requesting a website. Using this header, it was easy enough to differentiate the app’s experience on the web and in the actual Android app.

For each request, the app checks for the Android ID; if present, the app sets a Vuex state boolean called isAndroid to true. This state cascades throughout the app, working to trigger various conditionals to do things like hide and show various FAQ questions, and (most importantly) to hide the support page in the nav menu. It also unlocks all content by default (since the user’s already “donated” on Android, by purchasing). I even went so far as to make simple <WebOnly> and <AndroidOnly> Vue wrapper components to wrap content only meant for one of the two. (Obviously, users on Android who can’t visit the support page shouldn’t see FAQs on the topic, as an example.)

<!-- /src/components/AndroidOnly.vue -->
<template>
  <div v-if="isAndroid">
    <slot />
  </div>
</template>

<script>
export default {
  computed: {
    isAndroid() {
      return this.$store.state.isAndroid
    },
  },
}
</script>

Accounting for accounts

For a time while building Quina, I had Firebase set up for logins and storing user data. I really liked the idea of allowing users to play on all their devices and track their stats everywhere, rather than have a separate history on each device/browser.

In the end, however, I scrapped that idea, for a few reasons. One was complexity; it’s not easy maintaining a secure accounts system and database, even with a nice system like Firebase, and that kind of overhead isn’t something I took lightly. But mainly: the decision boiled down to security and simplicity.

At the end of the day, I didn’t want to be responsible for users’ data. Their privacy and security is guaranteed by using localStorage, at the small cost of portability. I hope players don’t mind the possibility of losing their stats from time to time if it means they have no login or data to worry about. (And hey, it also gives them a chance to earn those awards all over again.)

Plus, it just feels nice. I get to honestly say there’s no way my app can possibly compromise your security or data because it knows literally nothing about you. And also, I don’t need to worry about compliance or cookie warnings or anything like that, either.

Wrapping up

Building Quina was my most ambitious project to date, and I had as much fun designing and engineering it as I have seeing players enjoy it.

I hope this journey has been helpful for you! While getting a web app listed in the Google Play Store has a lot of steps and potential pitfalls, it’s definitely within reach for a front-end developer. I hope you take this story as inspiration, and if you do, I’m excited to see what you build with your newfound knowledge.


What I Learned Building a Word Game App With Nuxt on Google Play originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/what-i-learned-building-a-word-game-app-with-nuxt-on-google-play/feed/ 14 340759