Mike Sherov
Mike Sherov

Reputation: 13427

How to require a file other than the npm main file in node?

package.json:

...
"name": "mypackage",
"main": "src/index.js"
...

Directory structure:

|- src/
|--- index.js
|--- other.js

I can require src/index.js with require('mypackage');, but how can I require src/other.js?

If the answer is require('mypackage/src/other');, is there a way to make it so I can require it with require('mypackage/other'); (i.e. teaching node what the source file directory is of your module?

Upvotes: 49

Views: 21780

Answers (6)

just import it as a simple file.

const otherfile = require('./node_modules/other_package/other_file.js');

Upvotes: 0

Giorgio
Giorgio

Reputation: 13529

From node 12.7.0 there is the [exports][1] property of the package.json that can help you.

{
  "main": "./main.js",
  "exports": {
    ".": "./main.js",
    "./other": "./src/submodule.js"
  }
}```

If you have a lot of submodules and you want to export all files you can use a [subpath pattern][1]:

```//package.json
{
  "exports": {
    "./*": "./src/*.js"
  },
}```


  [1]: https://nodejs.org/api/packages.html#subpath-patterns

Upvotes: 0

Mohammed Samir
Mohammed Samir

Reputation: 416

Edit

Don't use prepublish anymore. Instead, use prepublishOnly.

My own approach to the solution:

As no one has an idea of how to perform the desired behaviour, we can't stand still, the best answer now is:

Solution 1:

From Patrick solution, and his package generate-export-aliases: we can add some npm scripts to automate the whole publish process. Either you write your code directly in commonjs inside ./src/ subdirectory or you used some new shining ES feature transpiled in ./dist, you will have your module files to be exposed, so add npm scripts:

"scripts": {
  "expose": "generate-export-aliases",
  "prepublishOnly": "npm run expose",
  "postpublish": "git reset --hard HEAD"
}

Or a more save scripts

"scripts": {
  "expose": "generate-export-aliases",
  "prepublishOnly": "git ceckout -b prepublish-expose && npm run expose",
  "postpublish": "git add . && git stash && git stash drop && git checkout master && git branch -d prepublish-expose"
}

Solution 2: Without generate-export-aliases

You can use gulp task runner (transpile if needed and put the files directly in the root dir, no need to copy or move again).

Indeed, this is the exposing step, you can keep prepublishOnly and postpublish scripts unchanged and just change the expose script. Save time and build in the root dir directly.

Upvotes: 1

Patrick
Patrick

Reputation: 861

You'll have to explicitly expose the file in the root folder, but many projects (including older versions of lodash) do this as part of a pre-publish step. In fact there's a package that does exactly what @Creynders suggests, adding module.exports = require('./path/to/file') files in your root folder. A while back I wrote up a guide on getting started, but the gist is pretty simple.

Install

npm install --save-dev generate-export-aliases

Configure

{
  "name": "my-package",
  "scripts": {
    "prepublish": "generate-export-aliases"
  },
  "config": {
    "exportAliases": {
      "other": "./src/other"
    }
  }
}

Use

const other = require('my-package/other')

DISCLAIMER: I'm the author of the package

Upvotes: 3

Norbert
Norbert

Reputation: 663

I'm currently looking into the exact same thing.

Package.json has a property called 'files':

http://blog.kewah.com/2014/npm-as-a-front-end-package-manager/

https://docs.npmjs.com/files/package.json

The "files" field is an array of files to include in your project. If you name a folder in the array, then it will also include the files inside that folder.

But I have yet to find how to do a import/require of such a file. I don't really see another point in listing these files other then to be able to import/require them?


I was able to import a file from a package if it was listed in this files array.

{
    "name": "local-ui-utilities",
    "version": "0.0.1",
    "description": "LOCAL UI Utilities",
    "main": "index.jsx",
    "author": "Norbert de Langen",
    "license": "none",
    "dependencies": {
    },
    "files": [
       "/colors/sets/variables.css"
    ]
}

I'm able to import the css file from the package using postcss-import:

@import "local-ui-utilities/colors/sets/a.css";

This probably isn't your use-case, but postcss-import just uses npm under the hood. So This should work for your use-case as well, I would think.

This question and accepted answer seem related: Node/NPM: Can one npm package expose more than one file?

Upvotes: 6

Creynders
Creynders

Reputation: 4583

AFAIK You'll have to explicitly expose it in the root:

Directory structure:

|- src/
|--- index.js
|--- other.js
|- other.js

Then in /other.js

module.exports = require('src/other.js');

Now you can do require('mypackage/other')

Upvotes: 15

Related Questions