184

I'm looking at some code from a coworker wrote and she's using the @ symbol in require statements. This is the first line of one of these files:

var restServer = require('@company/config')

When I try to run this code, I get an error:

Error: Cannot find module '@company/config'

Which I frankly expect, there's nothing that looks like this in my directory for require to recognize! It seems like there's some magic going on here, which I hate.

All I can guess is that either this is some obscure npm or Node trick that I haven't been exposed to, or maybe that there's some other dark art of configuration that I'm not getting. Any info appreciated, even if it's just an explanation of how @ works with require.

Other ideas: Chef is involved somewhere in this whole thing, so that might be relevant.

Update: 99% certain this is an issue with the way npm config works at this point, but still unsure of how to go about fixing it.

Update2 based on some stuff I uncovered:

Dereks-MacBook-Pro:project-dir derekjanni$ npm config set //registry.npmjs.org/:authtoken $SECRET_TOKEN

Dereks-MacBook-Pro:project-dir derekjanni$ npm install
npm ERR! Darwin 15.0.0
npm ERR! argv "/usr/local/Cellar/node/5.5.0/bin/node" "/usr/local/bin/npm" "install"
npm ERR! node v5.5.0
npm ERR! npm  v3.5.3
npm ERR! code E404
npm ERR! 404 Not found : @company/config
npm ERR! 404  '@company/config' is not in the npm registry.
lamont
  • 3,854
  • 1
  • 20
  • 26
Derek Janni
  • 2,397
  • 2
  • 13
  • 13
  • 3
    Associate an operation with a scope for a scoped registry. Useful when logging in to a private registry for the first time: npm login --scope=@organization --registry=registry.organization.com, which will cause @organization to be mapped to the registry for future installation of packages specified according to the pattern @organization/package. from https://docs.npmjs.com/misc/config – Derek Janni Mar 29 '16 at 19:55
  • 1
    Related post - [What is the meaning of the “at” (@) prefix on npm packages?](https://stackoverflow.com/q/36667258/465053) – RBT Jun 03 '18 at 10:34
  • 2
    `npm help scope` – trailing slash Jul 11 '18 at 17:53
  • 1
    Related: why are some modules _not_ scoped? Looking through one of my projects I see that D3, 'has', 'postcss' each have many subcomponents but they don't use the `@` scoping. Do they gain some beneficial property by not being scoped? – Michael Iles Nov 19 '19 at 17:08

5 Answers5

120

Scoped packages in npm are preceded by an '@' symbol.

A scope allows you to create a package with the same name as a package created by another user or Org without conflict. https://docs.npmjs.com/about-scopes

Scopes are a way of grouping related packages together, and also affect a few things about the way npm treats the package. Each npm user/organization has their own scope, and only you can add packages in your scope. This means you don’t have to worry about someone taking your package name ahead of you. Thus it is also a good way to signal official packages for organizations. https://docs.npmjs.com/misc/scope

The docs include additional information on requiring scoped packages: https://docs.npmjs.com/misc/scope#requiring-scoped-packages

Requiring scoped packages

Because scoped packages are installed into a scope folder, you have to include the name of the scope when requiring them in your code, e.g.

require('@myorg/mypackage')

There is nothing special about the way Node treats scope folders, this is just specifying to require the module mypackage in the folder called @myorg.

vaer-k
  • 10,923
  • 11
  • 42
  • 59
53

The @ scope is indicates common package ownership for a set of packages

From the official documentation is at: https://docs.npmjs.com/about-scopes

When you sign up for an npm user account or create an Org, you are granted a scope that matches your user or Org name. You can use this scope as a namespace for related packages.

A scope allows you to create a package with the same name as a package created by another user or Org without conflict.

The main advantage of scopes I've seen so far is that each scope is controlled by npm account of an organization / user, much like GitHub usernames / organization names.

This way, it makes it easy to determine if the package you are looking at belongs to an organization you trust, or if it is a third party tool.

For example, if you see a package:

@angular/cli

then you know that it comes from the user / group that controls the Angular team and can be trusted.

On the other hand, the same could not be said about:

angular-cli

TODO: the web UI / URL scheme is really wonky, how do you easily link: https://www.npmjs.com/package/@angular/cli to the corresponding organization / user page, presumably https://www.npmjs.com/~angular ? By searching the page source, the only hit for that URL is under "collaborators", but that contains other collaborators as well: https://www.npmjs.com/~angular-cli and https://www.npmjs.com/~google-wombot

See also: What is the meaning of the "at" (@) prefix on npm packages?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
29

So I solved this one myself.

Turns out @company/config is one of our private NPM repositories, hosted on npm and defined by this alias to an internal GitHub repository: it had nothing to do with how require works.

Using @ may or may not be a protocol that I was unaware of for private NPM repos, keep that in mind if you run into this.

Derek Janni
  • 2,397
  • 2
  • 13
  • 13
28

Apart from scoped packages, the '@' can arise due to module-alias package in npm. Through module aliasing you can use frequently used modules without requiring its entire path. Also its effective when directory structure is long. e.g.) require('../../../../some/very/deep/module')

Instead you can use: var module = require('@deep/module')

In package.json you can provide the modules for which you are providing alias:

"_moduleAliases": {
  "@root"      : ".", // Application's root
  "@deep"      : "src/some/very/deep/directory/or/file",
  "@my_module" : "lib/some-file.js",
  "something"  : "src/foo", // Or without @. Actually, it could be any string
}

And in the main file of the app use this:

require('module-alias/register');

Refer here for detailed info: module-alias

Pransh Tiwari
  • 3,983
  • 1
  • 32
  • 43
7

When you call require() it reads a route. Since there seems to be no problem if you name a folder as @company, you should be able to require something with an @.

Your coworker may have wanted to keep @company/config.js for herself because configurations usually are personal and could not be the same for another user.

require will call files inside your project folder, with a detail:

  • If you call files inside your project folders you must add ./ in front of your route.
  • If you call any global package such as http or any npm modules (which are installed at node_modules), you can omit the ./.

I created a route @company/config inside my test project folder. It only allowed me to require it using ./@company/config. Only when i moved the folder inside node_modules, it allowed me to require('@company/config');.

I wouldn't recommend to put any module inside node_modules, it's just a 'container' for npm packages. Try to create a new config file and change the require route or simply delete the require and create a config object in your main file.

user5402942
  • 109
  • 2
  • 1
    Thank you! This is a good answer with some useful, but I actually solved my own problem a while ago. I'll post it for the sake of answering others questions. – Derek Janni Apr 14 '16 at 23:32