Two modules in one package.json file

Viewed 1468

I am trying to create a plugin that is UI Framework independent. I cannot do any dynamic imports so I have decided to build it two times with rollup. But now I have the problem that I cannot import the different files separately.

How my structure looks:

- dist
    - quasar.js
    - vuetify.js

In my package.json I have dist as main. But when I try the following in my application I get an error:

import VueScanField from 'vue-scan-field/quasar'

The error:

This dependency was not found:

* vue-scan-field/quasar in ./src/boot/vue-scan-field.ts

There is probably something wrong with the main variable in my package.json. Thats why it is not recognizing /quasar. Anybody any idea?

I have tried subpaths exports but with the same result. My config looked like this:

  "exports": {
    "./quasar": "./dist/quasar.js",
    "./vuetify": "./dist/vuetify.js"
  },

But I still get the same error

1 Answers

Try filling exports field in package.json. Documentation addresses the exact use case you describe:

Subpath exports

When using the "exports" field, custom subpaths can be defined along with the main entry point by treating the main entry point as the "." subpath:

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

Now only the defined subpath in "exports" can be imported by a consumer:

import submodule from 'es-module-package/submodule';
// Loads ./node_modules/es-module-package/src/submodule.js

While other subpaths will error:

import submodule from 'es-module-package/private-module.js';
// Throws ERR_PACKAGE_PATH_NOT_EXPORTED

Further info:

Demo scenario

Folder structure:

├── package // the package we want to distribute
│   ├── package.json
│   ├── submodule1.js
│   └── submodule2.js
├── main.js // consumer script
└── package.json

submodule contents:

// ./package/submodule1.js
export default 'submodule1.js'

// ./package/submodule2.js
export default 'submodule2.js'
export const name = 'second submodule'

inside ./package/package.json, I defined submodule exports for these files:

{
    "name": "my-package",
    "type": "module", // enable ESM imports
    "exports": {
        "./a": "./submodule1.js",
        "./b": "./submodule2.js"
    }
}

then I installed the ./package directory in consumer project using npm install ./package which added an entry in ./package.json

{
    "name": "consumer",
    "type": "module",
    "dependencies": {
        "my-package": "file:package"
    }
}

Now, I can import submodules (both default and named exports) from ./main.js:

import a from 'my-package/a'
import b, {name as bName} from 'my-package/b'

console.log(a);
console.log(b);
console.log(bName);

which prints:

submodule1.js
submodule2.js
second submodule

I can go as far as to prevent importing the base package and only allowing submodules by explicitly setting root package export to null (or by simply omitting it altogether):

{
    "name": "my-package",
    "main": "main.js",
    "type": "module",
    "exports": {
        ".": null, // prevent importing root package
        "./a": "./submodule1.js",
        "./b": "./submodule2.js"
    }
}

which causes this code to throw error

import mypackage from 'my-package'
node:internal/process/esm_loader:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in /path/to/demo/node_modules/my-package/package.json imported from /path/to/demo/index.js
    at new NodeError (node:internal/errors:329:5)
    at throwExportsNotFound (node:internal/modules/esm/resolve:337:9)
    ...
    at link (node:internal/modules/esm/module_job:56:36) {
  code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Related