Wombat Driven Understanding - An Interactive Guide to Using Npm

Raquel Vélez speaking at viennaJS in January, 2017
93Views
 
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

So you want to write some software. And you decide to use npm, because everyone's saying it's the coolest thing ever. Great! But... where do you start? And once you've started, how do you take advantage of the advanced features? Let's write an app together! Whether you're brand new to using npm or have been using it for years, I guarantee you'll learn a new trick or two - or at least get a good laugh!


Transcript


- [Raquel] My name is Raquel Velez. [Foreign Language] I'm just going to do this whole thing in English. Okay. So, let's do a little survey. Fist to high five, where fist is you've never heard of npm, you've no idea what it is, not a clue. All the way up to, I can give a presentation on npm tomorrow and I'd be like I'd be easy. So everybody just tell me where you are. Excellent. Okay, cool. My goal is for every single one of you to learn something new by the end of tonight, okay? All right, so today what we're going to do is we're going to build an app. But before we do that let me explain a little about, about npm. So npm is, a package manager for JavaScript. A lot of people think npm stands for node package manager. Actually, it's just three letters N, P, and M, they don't mean anything. But even saying npm is a package manager for JavaScript is a little bit misleading because there's actually some CSS in our registry. There's Go, there's Rust, someone even stuffed some C++ in there, so really it's just a package manager. So just kind of FYI. And our number one priority at npm is to reduce friction. Our goal is to make it so that you can have the easiest time possible building really awesome apps, and publishing packages, and just doing the cool stuff that you just want to do. So let's go ahead and build an app. With any good application we should have a goal in mind, so, what I would like to do is build a random wombat fact generator. And it's going to be a command-line client because well, we could build like a web client and all that cool stuff, especially since I tend to work mostly with the web team or have a... I don't have time for that. So, command-line client it will be, this is a wombat, it is a marsupial native to Australia. It's really cute, it's really adorable. And it happens to be the animal of npm. You're probably like, what? Why? Well, it turns out, if you take npm and you flip it upside down, it says wdu, which obviously means the Wombat Developer Union. So it actually turns out that everybody at npm, we refer to ourselves as wombats. So, if people like, "Hey, wombats" it's because it's we're talking about npm people. But anyway, all right, let's go ahead and do this thing. So the first thing I want you to do is, I want you to install a node, if you haven't done that already, you just go to nodejs.org, there's a big green button depending on your platform, and you're just like, "Okay great, install this thing." And it's going to install the thing, and it's going to be fine. If you have special other ways of installing node, that's cool too, whatever. Just make sure you got the latest and greatest stable version. Okay. The next thing I want you to do is I want you to upgrade npm. So, node's release process is like monthly, if you're lucky, maybe every few months, and that's fine, that's the process that they need. But npm has a two-week release process. So every two weeks, we release a new version of npm. And while npm comes bundled with node, I can't guarantee that the version that you got when you installed node is the latest. So make sure you run npminpm@lalest-g for the latest and greatest. Okay. Ready? Let's do this live. So, you want to build an app. The first thing I need to show you is...is this big enough? No. Is that big enough? Yeah. Okay cool. So the first thing I want to show you, that's way too big for me. Okay. First thing to do, npm help, is a really great way to just kind of see everything that npm can do without having to go online or anything. It's like our man pages, right? So if you have questions or you want to just, what is the name of that, that thing that I should use or what command and whatever, you can totally do that with just npm help. Okay, great. So I want to make a new directory called random-wombat-facts and run a CD into that directory. And if you're looking at this and going what on Earth is that syntax, that is not bash, it's because it's not bash, it's fish shell. I love fish shell. We're not going to have a shell war. All shells are great, mine is just great. Okay. So I just started this new application, and I know I want to use npm, so I'm going to use a command called "npm init". Now, what npm init does is, it creates a package.json. Your package.json is basically this manifest file that says, what's the name of this package? What's the version of this package? What's a description and what are some keywords? And also, what are the dependencies that this package depends on? And we actually use that when you publish your package to kind of help with your search results and all sorts of things like that. So instead of having to actually write out that thing, the whole package.json by hand, I'm lazy, I wonder if you're lazy, but I'm a developer, so kind of by default I'm lazy. I'm going to let the machine do as much automated work as possible. So, npm init is your friend. So, anything that's in parens is the automated, if you like this just press "enter". So random-wombat-facts is the name for an app, fine, that sounds fine. Version 1 point... yeah,cool. Description, random wombat facts generator, great. Entry point, we'll call it index.js, that's fine. Test commands, who need tests. Git repository, none of that either, but if you were to have run "git init" first, and there was like an automatic already existing git-repo in there, it would auto complete that for you as well. So keywords, random wombat facts, stuff, is cool, just got here today, seems pretty neat so far. A license, you always want to have a license with your application or any packages that you build so that other people in the event that you decide to publish them, other people know how much access they have to your code. So ISC is a really nice, friendly, open source license. But if you don't really want to give a license at all, you can actually say "UNLICENSED". And that's something you can just say, no license, this is my code, don't touch it, hands-off, okay. Maybe don't publish it publicly, if you don't want anybody to touch it. But just saying, you could do that. And then it goes ahead and gives you a printout like this is...so this is what I'm planning on printing out, and it's just like, yeah, okay that's cool, I guess. All right, so we have this index, we have this package.json and that's fantastic, and now we're going to go ahead and create this initial file. This is going to be the entry point. No, no. Okay. Vim, index.js, and no, we're not going to have any wars about Vim versus Emacs. Okay. So I want to have...I just want to have a basic list of facts, right? So I'm just going to have, const facts equals some array of facts. And this is just to kind of test some stuff. And then, I'm going to console.log, some random fact right, so just going to pick the first one, and let's put a semicolon, okay. So now, what I can do is I can run that index.js and say, "Okay, did it do its thing?" Well yeah, it did exactly what I asked it to. Fact one, but I'm only putting out the very first one of that array, but what do I really want to do? I've really want to have a random item from that array. So, okay, surely, surely somebody has already created a package that allows me to just say, "Pick a random item from a given array," right? Okay. So let's go to npmjs.com and let's just, let's use the search which used to be awful, but I promise it's better. And let's say, I just want to find something random in an array something, something. Well, hey, would you look at that, there's a random item, get a random item from an array. That sounds exactly like what I want. So we go in there and suddenly it's like, okay so how do I install this usage? Var randomItem = require random-item, randomItem, you give it an array, and then out should pop something really random. Okay. Well, let's go ahead and do this, let's go ahead and save this, let's go ahead and install it. So what I'm going to do is npm install random-item, and I'm going to do a --save here. What dash dash save does is it automatically puts the name and the current version number into your package.json. Again, I'm lazy, I don't want to have to remember every single package that I installed, and I don't want to have to remember every single version of every single package that I installed. So let the computer do it for you. And we can see how this ended up working out by, here we have this dependencies, random-item, you know, and it has the version number, so perfect. Fantastic, that's exactly what I want. Now, this isn't specific to npm, it's a little bit more of a node thing, but I don't trust everything I read on the internet. So I like to trust but verify. And the way that I do that is I run the node-repl. So if you just doing node, that's the repl, it's the read-eval-print loop. And what this is, is it's basically a console that you can...it's just like opening up a browser and going into the console and, like, playing around with jquery stuff, but you could do that here on the command-line with node stuff. Okay, cool. So, let's say I just want to try out a little bit of a... just want to create a little array, and I want to require this random item. And according to the docs, if I do rando(arr) I should get a variety of values. And hey, there we go it just gives me different values as expected. So I press CTRL+C twice and get out of there. So now that I know that this works the way that I expect it to I'm happy to ahead and put it into my app. So let me go back into my app and I'm going to add this randomItem=require("random-item") and instead of facts zero, I'm going to do that, right. And so now, what I expect is when I run node index.js, I should get different facts, okay. So this is working exactly as expected. Fantastic. I'm really lazy, really, really, really lazy. I hate writing, node index.js all the time. And this is like what you're going to see now is going to seem really silly, but imagine instead of starting your app every time it's not just node index.js. Maybe it's, run the tests, run the gob file, make sure everything passes, and then run node index.js. It really sucks to have to do it over, and over, and over again. I'm sure you can write a bash script and you probably will write a bash script, but here's a fun fact. If I go into my package.json, I can do it, I can use what's called run scripts, and I can add a start script that basically just does exactly what I ask it to. So start and test, and a few other things like pre-install and post-install are reserved keywords in the node run script ecosystem. So what this means is, by putting that in there I can do node or npm start, and it'll go ahead and run that for me. And it doesn't have to be explicitly whatever you have on the command line there, it can be a bash script. You can just say, "Here, run this bash script whenever I run node start, or node test," or whatever. So that's kind of nice. So, that's pretty cool and if I look at...so that's easy, but here if we look at my index.js, you can see that I've got some semicolons, and some other not semicolons. And how many of you have code-bases where there is, like a bunch of people you can see where the fights about semicolons and tabs versus spaces and etc. have occurred, right? Like it's just a warzone of everybody having different opinions. At least, that's how it looks on the npm code-bases. Well, it used to. We started using a package called "standard" which some of you may have heard of, but basically what it does is, it's a standardized style guide for how to write JavaScript. Basically, nobody wins, it compromises for everybody. And since nobody wins, everyone can either fight all the time or they can just stop fighting. And so that's what we've done, we just stopped fighting. So I want to go ahead and use this, and usually when you install standard you kind of install it globally. Turns out you don't have to ever install things globally, not ever, especially when it's associated specifically with an app. So I want to use standard and I want to use it, and I have a run script for it as well. So I'm going to go ahead and add, and go back into my package, oh no. First, I'm going to install standard, and so you'll see that there are shortcuts, -I, I'm sorry, I is just regular install, -D is a shortcut for --save-dev. And by the way, -S is just --save. So in this case, because standard isn't going to be anything that I'm ever using in production, my production code does not actually care about whether the code is formatted properly, it's a development dependency, right? I only care about this package when I'm doing something in development. So I'm going to go ahead and add this to my devDependencies and that's going to go ahead and do its thing. And we can take a look at package.json now and you can see that there are, there's a difference between dependencies and devDependencies. Now, so that's pretty cool, but now I want to create a run script so that I don't have to keep doing it separately. And here's...this is also the fun way that you avoid doing anything globally. If it's in a run script, it'll just know to look straight into your node package or into your node modules folder, so that you don't have to deal with all this stuff. So I'm going to go in my package.json and I want to create a run script called standardize and it's just going to run standard. And that again, it seems a little bit silly but I'm the silliest version of everything right now, but I'm sure you can think of other reasons why this would be useful. Now, standardize isn't a reserved keyword in npm land, so in order to run this script, we've had to do npm run standardize. So it goes ahead and runs it and it's like, "Oh my god, everything's terrible." And why is it? Because, oh, you have an extra semicolon, get rid of it. Again, lazy I want my computers to do everything for me. And it says really simply run standard --fix to automatically fix some problems. Okay, that's pretty cool. But did you know that if I do npm run standardize, I can actually add command-line arguments to my run scripts, by just doing an extra --. So in this case, I'd do run npm run standardize -- and then --fix. And what that will do is it actually runs the standard --fix. And if we look at my index.js, no more semicolons, they're all gone. Sadness for the semicolons, that was the battle I lost. Okay. I don't care. All right. I knew you're thinking like, "Death to semicolons!" And other people are like, "No, the semicolons, save them!" and nobody cares. Okay. Okay, so that's all fantastic. Now, I want to create another module, right? So when you're creating these applications, you're thinking, "All right, well, I want to, you know, many small modules." That's the npm manifesto. That sounds great. How do I know when to create a new module? Well, first of all let's talk about the difference between a package and a module. A package is just anything that you do npm install with. So you can npm publish whatever you like, and then you can npm install and it'll unpack its own little tar ball, whatever great. A module is specifically a package that uses node's require feature, right? So it has to use the require syntax in order to actually put it into your application. So in this particular case, I like to think about modules as things that can be reused, not necessarily just by me but maybe by other people as well. So I'm thinking, I'm going to create a new package that's specifically wombat-facts, just a bunch of wombat-facts. Okay. So let's go ahead and create a new directory called wombat-facts, and I'm going to go into that, and then so...again, creating a package is exactly the same as creating a new application. So I'm going to do npm init, but I know what it's going to say in the little, in the parenthesis, and I just know I'm going to press enter a whole bunch of times, so I'm just going to say --yes. What that does is, it just automatically does it for you. I'm so lazy and it helps me. It's so great. Okay. So, okay, fantastic. I'm going to build this package.json or this index.js now, and in this case, because it's a module and you do a module.exports. And here, I'm going to do my fact1, fact2, fact3, and it's just going to be a simple little array, right? And so that's all I want this package to be, I just want it to be an array of wombat-facts. So what some people would mistakenly do right now is, they would go ahead and publish it. Because they want to check to see if it works in their application, right? This is a module and we have an application. And I want to make sure that my module works in my application before I say, "My application is done and this module is done." But you don't actually have to publish it before you test it. There's a fun little command called "npm link". What npm link does is it creates a symlink between the package that you're working on, and any other application in your system that might want to depend on that package. So I created this link. Now I can go back into my random-wombat-facts app, and I can do npm link wombat-facts, because that's the name of the package that we created back up here, right? So, npm link wombat-facts, fantastic. Now, it's all been linked together, which means that if I go into my index.js here I can replace these facts with require("wombat-facts") and it should work exactly as we expect, right? So now, if I do npm start fact1, fact2, fact3, yeah, okay, great. But in case, you're kind of like, I don't really trust that this works, good news, we have real wombat-facts. So I'm going to go ahead and pull these in, and it should be, vim index.js, and just trust me on this. Okay. So now, I'm going to go back to my application and note, I'm not relinking or anything like that, the symlinks are just there, we don't have to go back all the time. Now, if I just do npm start, I find out wombats have that teeth like rodents. Wombat incisors, like those of rodents, are continuously growing. To keep them in check, wombats gnaw on bark and tough vegetation. Did you know that? I bet you didn't, that was a random wombat fact, we can do another one. There used to be giant wombats. An ancestor of today's wombats was a giant the size of a rhinoceros that lived during the Ice Age. It is believed that ancient Aborigines hunted the giant wombat. Did you know that? No, you didn't. It's working! Excellent. Okay great. So this works exactly the way I expected it to. I'm going to go ahead and I'm ready to publish this. But you know, I always worry about name collisions, right? There's only so many names out there, actually there's a lot of names out there, there's so many names out there. But let's say you wanted to build, like, a super, super fast app, or super app fast module that does something really fast and you want to call it express. That's not going to happen. For those of you who were not in the npm ecosystem, express is kind of a big deal. It's a framework. It goes fast sometimes? I don't know. Anyway, in fact, the good is that you don't have to worry about that anymore. You can actually have scoped packages. And most of the time people want to have, like, private packages, and so normally, people associate scoped packages with either private packages from the npm solo product or with the npm organizations product. So you can have like your @orgnames/packages. But as long as you're an npm registered user, as long as you want to make it, you know, free and public and stuff, you can actually have free scoped packages. So what you would do...so first of all I'm going to update my package.json, because this is not the first time that I've ever done this talk. Okay, just change the version number, I'll explain why in a minute. But okay, so now what I want to do is I want to publish this, but I want to...oh wait. First, I want to...wait a minute. I have to change my package name to @rockbot, because I'm logged in as rockbot. And so "@rockbot/wombat-facts" this is now a scoped module. And change version number, great. So now, I want to do npm publish, and I can do --access=public. So adding that --access=public, means that it's going to be a public package. So since it's not a private package I don't have to pay for it. So I don't actually have to have a solo account or an org account for this. So it's going to go ahead and it's going to go and push that up. Excellent. Okay. So now I can take a look at it, right? I can see...if I go to @rockbot/wombat-facts. I can see...here it is. Ta-da! Oh no, this has no readme. We should fix that, shouldn't we? Yes, yes we should. So let me go ahead and add a readme, and it's going to be, you know, random wombat facts. Okay. So now what I want to do is...so I've added this readme so I should really bump my version number, right? So the way that I'm going to do this is, I'm going to say npm version patch and %s, will give me the version number and it just says, adds a README, because oops. And so what this does is, npm version, will actually auto-update your version for you. And in the event that you're using, you know, git or an...if you want to push all this up, you can actually do git push and git push-- tags. So, v2.0.1 will actually create...or npm version, will create a new commit for you, and it will go ahead and create a new tag for you automatically. So you can go ahead and push that all up. Make sure you remember to push the tags, because I always forget. And then, If I were to do npm publish, and you shouldn't have to do --access=public every single time. Actually, I'll even show you. So I can do that. But now it will publish, and it will add the README. And so, you can see, rockbot/wombat-facts@2.0.1, and now if I refresh the website, because I'm in Vienna and I can have wombat-facts. I don't know where my description...oh because I don't have it...whatever, doesn't matter. Okay. Yay! Okay, that's fantastic. So now, keep in mind, by creating this new wombat-facts...oh, and I should also remember to unlink this because that no longer works. So if I go back to the random-wombat-facts, and I try to do npm start, because I npm unlinked... I don't know what happened there, it shouldn't have worked. - [Audience] You linked it with the name before. - You're right. So you know what I'm going to do? Npm unlink wombat-facts. Or not. Anyway, because I accidentally unlinked it or didn't, I forgot to unlink it, if I had unlinked it before publishing it and changing everything, this would all be broken. And we would have to go into our index.js and we'd need to update this to @rockbot/wombat-facts and you would also want to npm i @rockbot/wombat-facts -S, right. So you'd want to make sure that you have the latest and greatest in everything. But now, let's say I'm really sick of all this stuff and I just want to unpublish, you can do npm unpublish. Note that, due to some recent history of things, you can only unpublish within the first 24 hours of creating your thing or if absolutely no one has ever used it. Sorry, but there are robots, they will all use it. So if you want to unpublish something, if you like, if you realize, "Oh my goodness, I totally published something and I didn't mean too." Do it within 24 hours, if not, you're going to have to talk to our support team, but I promise they're the super nicest people ever, it'll be fine. And they try to get back to everybody as quickly as possible. But there's so many of you, and so few of us, okay. So let's say I want to unpublish everything, absolutely everything, so I can unpublish just certain versions. I can say @2.0.1, for example. I can just unpublish the one, and it will unpublish just that one version. Or I can just... I can unpublish literally everything and just say --force and it says, "I sure hope you know what you're doing," and I think I do. So, you know, make sure you know what you're doing when you unpublish everything. So that's all of that stuff. Let's go back to...let's talk a little bit about semver. So semver is semantic versioning, right? The whole point of semver is, first of all...oh shoot. There's a show in the United States that's, like, improv called <i>Whose Line is it Anyway?</i> and, like, people try to, like, get points and stuff, and like the host is very adamant that the points don't matter. So, semver version numbers don't really matter. You can...they're cheap. They're free, in fact. You can have as many version numbers as you like, as much as you like, whatever. But do note, that semver, is the handshake that you make with the rest of the npm community. So we all try to use semver, like properly, so that everybody knows whenever they install a version of your package, they know what to expect. So let's talk about semver. It's three digits, separated by periods, and sometimes there's like an extra hypheny thing, but don't worry about that. Okay. So the very last number, which in this case is the one all the way to your right. Yes, to your right. So that's the patch number. That's the number that you bump whenever you have like a bug fix or you needed to add a readme or you wanted to fix a typo in the readme or whatever. Nothing really significant has changed, it's just...oops, I forgot to add this thing. So you can do this with npm version patch. The next number, the middle number, that's your minor number. So any time you add new features, maybe you add another API endpoint, but it doesn't change anything else in your code, that's when you want to bump that. So you can do npm version minor. Then, the one all the way to the left, the first number, that is your major number. So any time you break something, maybe you want to deprecate an API endpoint or maybe you want to... I don't know. If you want to rename a function and didn't want to have to like add the extra backwards compatible version of that function, that's a major breaking change, npm version major is your friend there. So people often come in and they're like, "Oh my goodness. I accidentally published version 1.2.3 and I need to bump, I need to change the readme on this thing. But I have another version of the exact same code in another, like, registry or something and it's 1.2.3, and I really can't afford to do a 1.2.4 because then they'll mismatch. Can we please just unpublish the 1.2.3, so I can republish on top of 1.2.3?" And the answer is no. No you cannot, because the handshake would then be broken. Again, they're cheap. Version numbers are cheap. If you had to go ahead and update the readme on the one version, you had to go to 1.2.4, then just change the other one to 1.2.4. It's okay, I promise, it's fine. It's fine. No one's going to die. Unless you divide by zero. Don't do that. Okay. Okay. So that's everything I wanted to cover today, but there're obviously tons more, right? bundledDependency, configuration options, dist-tags, npm deprecate, npm pack, npm shrinkwrap, npm update, npm outdated. Oh my god, so many things. And yet there's yet even more. Where do you find out about all of this stuff? docs.npmjs.com, literally everything that we've ever written in terms of documentation for the community and client, the website, the registry, everything lives here. So if you have questions, this is the first place that you need to look. But if you need further help, like I said, our support team is super awesome. So, you can go to the support URL and you can fill out the form if you want or you can send us an email, or you can chat at us on Twitter or you can even...if you really wanted to, you can create issues on specific repos for the CLI, the website, or the registry itself. Really easy, we try to get back to you as quickly as possible. But please keep in mind, there are 20 people working at npm, and there are millions of you all. So please be patient. Please be patient. We love you, we do. I have a million and seven of these stickers. If you're wondering who this very fine wombat is, that is your wonderful Kaiser Franz Joseph, skiing. I will be...