loading...

Explain package-lock.json like I am five

twitter logo github logo ・1 min read

What is the point of having same dependency tree ? And how does dependency tree actually work ? Should I commit package-lock.json every time I add new package ? How is it related to symbols (e.g. ^ ) that are put before package versions in package.json ?

twitter logo DISCUSS (16)
markdown guide
 

There are four different ways you could say you need to have ice cream:

  • I want ice cream (ice-cream: *)
  • I want chocolate ice cream (ice-cream: ^1.0.0)
  • I want chocolate ice cream with sprinkles (ice-cream: ~1.0.0)
  • I want chocolate ice cream with chocolate sprinkles (ice-cream: 1.0.0)

Regardless, when you get your ice cream, it's chocolate with chocolate sprinkles. You're now locked into that. If you want your friend to have ice cream, too, you can give him the lock so you're both enjoying the same ice cream. If it doesn't matter exactly having the same ice cream in this moment, though, you can just give him those instructions I called out above rather than also giving him the lock.

Now that your friend is getting ice cream without a lock, he might get:

  • Vanilla ice cream (ice-cream: *)
  • Chocolate ice cream with peanuts (ice-cream: ^1.0.0)
  • Chocolate ice cream with rainbow sprinkles (ice-cream: ~1.0.0)
  • Chocolate ice cream with chocolate sprinkles (ice-cream: 1.0.0)

If we're cool with him maybe working with different ice cream than you, then awesome! If not, if maybe he's a dude who is trying to figure out whether or not to invest millions into your ice cream and he got something totally different, then you should probably give him the lock file to make sure you guys are on the same page.

 

Say I have specified ice-cream: ^ 1.0.0 in package.json and given him the lock file. Now ice-cream 1.1.0 is available, shouldn't he be getting 1.1.0 because my package.json has ^ symbol specified?

 

Keeping the ice cream metaphor because I think I'm clever:

When you're starting your ice cream business, it may not actually matter what kind of ice cream. You're focused on getting marketing and a retail location and stuff like that, so strawberry ice cream wouldn't kill things right now.

But once you open your business, your customers need reliability. Now that they've seen chocolate ice cream with chocolate sprinkles on the menu, they want to keep coming back for that.

That's why there would be a difference in dev dependencies, application dependencies, but also wanting to have a specific version actually deployed every time. The app just needs ice cream, you developing might need chocolate ice cream to test consistently, but now the server should always build with chocolate ice cream with chocolate sprinkles so no quirks from peanut allergies make it into production.

 

No, it reads the package-lock.json.

package.json is for you as the developer
package-lock.json is for me (or the server) as the installer

The package.json will be considered only if the lock is missing, hence the reason why they invented the lock, because the package.json is not enough to guarantee repeatability

 

What is the point of having same dependency tree ?

The lock file main purpose is repeatability of the installs.
If you have it you can be sure the packages listed there are the same that are going to be installed on your production application.

If you only have the package.json you will probably end up with slightly different versions for the same packages.

Should I commit package-lock.json every time I add new package ?

Yes

How is it related to symbols (e.g. ^ ) that are put before package versions in package.json ?

When you specify your dependencies you have multiple ways to specify a dependency. You can list the exact version (but it means you have to change both package.json and the lock file every time there's a new version) or you can use semver which allows you to be a little more elastic. ^1.2.3 for example means install all the 1.x.x future versions because the agreement says: "1 is the major version, 2 is the minor version, 3 is the patch version". So the developer likely won't release incompatible software until the version goes from 1.x.x to 2.x.x, and such version won't be intercepted by your initial rule ^1.2.3. If instead you only want bugfixes (the last digit) you can use ~1.2.3 which means install all the 1.2.x versions.

 

Thank you for your response.
I'm still kinda confused.

  1. Can I have only package.json without any symbol specified(i.e. exact version) so that same package version is installed everywhere ?
  2. Say I have specified awesome-package: ^ 1.2.3 in package.json and accordingly it's dependency tree is added in package-lock.json, will it install awesome-package-1.3.0 when available ? A) If yes, will it update package-lock.json as well ? If so then we are not using exact same version everywhere even though we are using package-lock.json, right ? B) If no, then what's the point of specifying those symbols if updates are not getting installed ?
 

Can I have only package.json without any symbol specified(i.e. exact version) so that same package version is installed everywhere ?

To have the same package AND the same version installed everywhere you need to specify the version, for example

{"dependencies": {"hello": "1.2.3"}}

In theory this guarantees that your hello package is installed with the same version everywhere. Unfortunately it doesn't guarantee that any other library that hello uses as a dependency will be installed with the same version. For this, you need the lock file

A) If yes, will it update package-lock.json as well

Yes but only when you add a package. If the version you allow points to 1.3.0 the lock file will be updated when you run npm install.

If so then we are not using exact same version everywhere even though we are using package-lock.json,

Yes, you are. When you install (and not add) a package, the package.json is totally bypassed. What npm does is read the package-lock.json and install the exact versions specified there

 

I don't think I'm able to answer everything, but here's at least some points:

  • The ^ in ^3.0.0 indicates that the package needs to be at least version 3.0.0. So having version 2.9.9 installed on the machine would require an update to version 3.0.0 or newer

  • The purpose of package-lock.json is to outline the list of version requirements for each package. This is useful for 2 reasons:

    • If a new feature is released in fancyTool.js v. 1.1.0 that you implement, you wouldn't want users to install v. 1.0.0. and wonder why it isn't working.
    • If the syntax changes dramatically from v. 1.0.0 to v. 2.0.0, you want to be able to require that v. 1.0.0 be installed instead of v. 2.0.0 (which would in turn break your program).
 

Then why to have both package-lock.json and those symbols in package.json ? Purpose of both of these things is same right ? How do they work together ?

 

The symbols are part of the package-lock.json structure. Each package independently can be assigned either a specific version or a minimum version that is needed. i.e.)

  "cookie": "0.3.1",
  "cookie-signature": "1.0.6",
  "debug": "2.6.8",
  "depd": "^1.1.1",

In this example, cookie, cookie-signature, and debug will install their specific versions and depd needs at least 1.1.1, but would also accept something like 2.0.0 or 1.2.1

 

A small thing to add here regarding lock files is speed. If your repo don't have a lock file, NPM (or any package manager) check all existing version of your dependencies and install the ones matching what you asked for. The same process if repeated for all sub-dependencies and so on.

Lock file remove this roundabout, it don't need to check to know "who need what" or "what version match this".

I just test on a project:

$ rm -rf node_modules/ package-lock.json
$ npm install
> added 1392 packages from 555 contributors, updated 2 packages and audited 52426 packages in 140.629s
$ rm -rf node_modules/
$ npm install
> added 1394 packages from 556 contributors and audited 52426 packages in 19.795s
 

Package-lock.json is the building instructions that comes with a Lego model.

Each package represents the different shapes or colour for a part that you eventually use to build a Lego model out of it.

Without a package-lock.json, it is like you are spreading it around and mixing with different Lego parts that do not come with the box.

By using symbols, you allow different types of the part to build your Lego model.

Which each part could be switched from an older Lego model you had brought previously or a new box of Lego model you had brought just now.

 

I just got one of these. So, basically, I do nothing? Include it in git commits, and that's it?

 
Classic DEV Post from Jun 6 '19

How do you onboard a new team member?

My team have a lot of roles to fill this year and recruitment is underway. I'm curious, when you joined your team, what made it a smooth experience?

Ankit Utekar profile image
Trying to be 'jack of all trades, master of some', but haven't decided on that 'some' yet 😀! JavaScript ( React-Redux, Jest-Enzyme ), C# ( WebApis)

dev.to now has dark mode.

Go to the "misc" section of your settings and select night theme ❤️