Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to require/import files other than main export in Node #2078

Open
tylersticka opened this issue Nov 7, 2022 · 2 comments
Open

Unable to require/import files other than main export in Node #2078

tylersticka opened this issue Nov 7, 2022 · 2 comments
Labels
🐛 bug Something isn't working 👷 environment Setup, build tools, configuration, etc.

Comments

@tylersticka
Copy link
Member

Overview

We currently define an exports field in our package.json, with additional files (such as compiled tokens) available via other fields.

But according to the Node docs, this prevents other files from being imported:

When the "exports" field is defined, all subpaths of the package are encapsulated and no longer available to importers. For example, require('pkg/subpath.js') throws an ERR_PACKAGE_PATH_NOT_EXPORTED error.

I've experienced this in a project where I wanted to import our design tokens.

Steps to reproduce

You can follow these steps to create a barebone test case project:

  1. Create a directory: mkdir cloudfour-export-issue
  2. Enter that directory: cd cloudfour-export-issue
  3. Initialize a new npm project: npm init -y
  4. Install our patterns: npm i -D @cloudfour/patterns
  5. Create a script that attempts to require tokens:printf "const tokens = require(\"@cloudfour/patterns/src/compiled/tokens/json/tokens.json\");" > index.js
  6. Run script: node index

Here is an example of the error you will likely see:

node:internal/modules/cjs/loader:499
      throw e;
      ^

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './src/compiled/tokens/json/tokens.json' is not defined by "exports" in /PATH/TO/cloudfour-export-issue/node_modules/@cloudfour/patterns/package.json
    at new NodeError (node:internal/errors:387:5)
    at throwExportsNotFound (node:internal/modules/esm/resolve:464:9)
    at packageExportsResolve (node:internal/modules/esm/resolve:748:3)
    at resolveExports (node:internal/modules/cjs/loader:493:36)
    at Function.Module._findPath (node:internal/modules/cjs/loader:533:31)
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:942:27)
    at Function.Module._load (node:internal/modules/cjs/loader:804:27)
    at Module.require (node:internal/modules/cjs/loader:1028:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/Users/tylersticka/Repos/exports-test/index.js:1:16) {
  code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
@tylersticka tylersticka added 🐛 bug Something isn't working 👷 environment Setup, build tools, configuration, etc. labels Nov 7, 2022
@spaceninja spaceninja self-assigned this Dec 16, 2022
@spaceninja
Copy link
Member

I dug into this a bit, but I'm putting it back because it requires a bit more discussion (and, frankly, a check-in with @calebeby about the right path forward).

My (admittedly shallow) understanding is that exports is the new standard, aiming to replace main and module, and has the capability of conditional exports. However, it also introduces the new side effect that @tylersticka mentioned.

My gut says the right answer is to remove exports in favor of our main and module lines, unless exports is giving us some advantage or feature that I'm missing.

A quick survey of how some other pattern libraries handle this:

@spaceninja spaceninja removed their assignment Dec 16, 2022
@calebeby
Copy link
Member

You can use glob-like patterns in export maps. It looks like the documentation says that in their glob syntax * matches subpaths as well so in their example an export map like this:

  "exports": {
    "./features/*.js": "./src/features/*.js"
  },

would allow importing a file like this:

import featureY from 'es-module-package/features/y/y.js';

main is standardized in node, but not for importing of esm files from esm files (that was always nonstandard and only implemented by bundlers).
module, jsnext:main, es2015, and es2017 are all nonstandard, just implemented by some bundlers and tools.

I think we should stick to export maps and add the globs as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working 👷 environment Setup, build tools, configuration, etc.
Projects
None yet
Development

No branches or pull requests

3 participants