0

When creating a npm package, it is quite common and convenient to structure it like so:

root
  / dist
  / src
  / package.json

where package.json:

{
  "main": "dist/index.js"
  "files": [ "dist" ]
}

The drawback of this approach is, when consumer wants to require files using relative path, it needs to include the dist folder. E.g. const abc = require('my-package/dist/x/y/abc');

Is there a way to tell NodeJS to resolve relative path based on path.dirname(main) or something similar?

UPDATE: to clarify, this is related to relative/deep resolution, not about export hoisting in ES6. It is a controversial subject that should this be done at all, as the consumer is coupled to the internal folder structure of the package.

UPDATE 2: what I want to achieve is a concept of "sub-module" (similar to namespacing). For example, my folder structure looks like this:

root
  / dist
     / testUtil.js
     / index.js

testUtil.js contains useful functions for testing. Since it is not used in normal use, I don't want to export them at top-level. i.e., instead of:

// index.js
export * from './testUtil'

I would do:

// index.js
import * as testUtil from './testUtil'
export { testUtil }

However, that still expose the testUtil module namespace at top-level and it is hard to use:

// consuming.js
import { testUtil } from 'my-package'
const { funcA, funcB } = testUtil

It would be better if I can "tug" it under a relative path:

// consuming.js
import { funcA, funcB } from 'my-package/testUtil'

Currently, without solving the 'dist' issue, I have to do this instead:

// consuming.js
import { funcA, funcB } from 'my-package/dist/testUtil'
unional
  • 14,651
  • 5
  • 32
  • 56
  • You could just publish the `dist` directory. – Steven Goodman Sep 11 '17 at 19:25
  • Do you mean create a copy of `package.json` inside `dist`? This mean I have to sync the `dependencies` and copy part of the scripts such as `install`, `prepare`, `publish`, `version`, etc? – unional Sep 11 '17 at 20:13
  • 1
    Yeah. It'd be more cumbersome but it would leave you with a much "cleaner" package. You could probably just have a `package.dist.json` that you copy and rename as a build step. Although your distributed version probably would have far fewer scripts; it would really just need an install and run script. – Steven Goodman Sep 11 '17 at 20:18

3 Answers3

2

You can set your NODE_PATH environment variable, and that should do the trick:

export NODE_PATH=./dist

There are some other patterns you could try out here.

Ezra Chu
  • 832
  • 4
  • 13
0

Usual way is to export lots of stuff from within your "dist/index.js" file, rather than getting people to import other files. You can re-export stuff like this:

export { default as Something } from './something.js'
export SomethingElse from './something-else.js'

See this answer for more: ES6, how can you export an imported module in a single line?

Duncan Thacker
  • 5,073
  • 1
  • 10
  • 20
  • Yes. That is a good approach on ES6. The OP is about relative path resolution, which is a controversial subject. – unional Sep 11 '17 at 20:23
0

To solve the dist folder issue, you could publish your dist directory as a standalone package. This would involve maintaining a separate package.json (it would most likely be a much slimmer package.json compared to your source package).

For the sub-module/namespacing issue, I don't see the problem.

Given a package with the directory structure:

root
  / index.js
  / testUtils.js
  / utilities
    / index.js
    / calculator.js
    / worker.js

You can access the normal top-level exports with require("root").

You can access testUtils with require("root/testUtils").

You can access the top-level utilities module with require("root/utilities").

You can access calculator with require("root/utilities/calculator").

It's just up to you to maintain this structure in the way you want to expose to your consumers.

Steven Goodman
  • 576
  • 3
  • 15