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

Use package.json#exports map #4155

Closed
mischnic opened this issue Feb 17, 2020 · 55 comments · Fixed by #8807
Closed

Use package.json#exports map #4155

mischnic opened this issue Feb 17, 2020 · 55 comments · Fixed by #8807

Comments

@mischnic
Copy link
Member

mischnic commented Feb 17, 2020

🙋 feature request

Use exports maps in the resolver

https://nodejs.org/api/esm.html#esm_package_exports
https://nodejs.org/api/esm.html#esm_conditional_exports
https://webpack.js.org/guides/package-exports/

💻 Examples

https://github.com/preactjs/preact/blob/master/package.json#L11
https://unpkg.com/browse/[email protected]/package.json

Relevant code

The resolver: https://github.com/parcel-bundler/parcel/blob/v2/packages/resolvers/default/src/DefaultResolver.js
which calls: https://github.com/parcel-bundler/parcel/blob/v2/packages/utils/node-resolver-core/src/NodeResolver.js

@phaux
Copy link

phaux commented Feb 29, 2020

Also, conditional exports could be used while bundling to specify the dist paths. They could replace package.json#{main,module,browser} if the package.json#exports key exists.

Example:

{
  "exports": {
    ".": {
      "require": "./dist/node/index.js",
      "import": "./dist/module/index.js",
      "browser": "./dist/browser/index.js"
    }
  }
}

Would be the same as:

{
  "main": "./dist/node/index.js",
  "module": "./dist/module/index.js",
  "browser": "./dist/browser/index.js",
}

@jkrems
Copy link

jkrems commented Apr 15, 2020

If nodejs/node#32869 lands, this likely should include support for NODE_ENV based resolution ("production" and "development").

@developit
Copy link

Some links to implementations/details in other tools/bundlers (more to come):

@mischnic
Copy link
Member Author

https://github.com/lukeed/resolve.exports might be useful

@rsthn
Copy link

rsthn commented Apr 2, 2021

This would be actually awesome! I was recently refactoring code and used the "exports" field, and I didn't know parcel didn't support this.

@TomzBench
Copy link

yes i think as a work around i have to peek into the package and import from the global scope :(

@aminya
Copy link
Contributor

aminya commented Jun 11, 2021

Any plan for supporting this? There have been so many changes on the V2 branch that it is hard to track the progress.

@devongovett
Copy link
Member

At the moment we're focused on blockers for a stable v2 release in the next month or so. This will likely be sometime after that.

@kkirby
Copy link
Contributor

kkirby commented Sep 23, 2021

As a quick work around, I made this fallback resolver: @kkirbatski/parcel-resolver-require-resolve

import { Resolver } from '@parcel/plugin';

export default new Resolver({
	async resolve({ filePath }) {
		try {
			return {
				filePath: require.resolve(filePath),
			};
		} catch (e) {
			return null;
		}
	},
});

@aminya
Copy link
Contributor

aminya commented Oct 16, 2021

Now that we have Parcel 2, is this on the priority? Solid-js depends on this feature.

@mischnic
Copy link
Member Author

Packages like [email protected] don't contain a "main" (or module, ...) field at all, but only

	"type": "module",
	"exports": "./dist/index.js",

So currently you can't import it with Parcel: Failed to resolve 'mem' from './index.js

@adelsz
Copy link

adelsz commented Nov 5, 2021

Unfortunately mozilla/glean is also not usable with Parcel because of this.

@paulmillr
Copy link

Hey folks, this is very important: basically Parcel cannot use modules which support both common.js and ESM. We're forced to revert and drop support for ESM because of that.

@devongovett
Copy link
Member

FWIW, I looked into implementing this not long ago, using the library linked above. I couldn't figure out where it should go in the resolution algorithm though. Node has two different algorithms for CommonJS and ESM, but bundlers usually do more interop so we will have to diverge. In addition, there are many different conditions that are possible, and it's not obvious whether it should occur before or after other resolution features like aliases. More research is required to see how other bundlers behave so that we don't fragment the ecosystem even more.

basically Parcel cannot use modules which support both common.js and ESM

This has been possible for a long time, even without the exports field. The main and module field already work today. If that's the only thing you need it should work with Parcel and other tools just fine. If you need other kinds of conditions, then it's more complicated.

@KaKi87
Copy link

KaKi87 commented Dec 12, 2021

Vuetify 3, for example, won't work. (import 'vuetify/styles')
Thanks

@fregante
Copy link
Contributor

fregante commented Dec 12, 2021

I found a (manual) workaround to continue using Parcel even with these dependencies:

Add an alias entry in package.json

{
	"alias": {
 		"mem": "./node_modules/mem/dist/index.js"
	},
	"dependencies": {
		"mem": "^9.0.1"
	}
}

Live example: https://github.com/refined-github/refined-github/blob/fa2eb1c952da8d03672d19866782652474dae884/package.json#L129

Every time a new dependency starts using exports, you'll have add it here.

Alternatively, kkirby’s plugin also looks interesting, but I haven't tried it.

@kkirby
Copy link
Contributor

kkirby commented Dec 25, 2021

@devongovett

FWIW, I looked into implementing this not long ago, using the library linked above. I couldn't figure out where it should go in the resolution algorithm though.

The package I needed this for was swiper. The package.json contained an exports directive for resolving the files of the package. To get parcel to resolve it, I installed my plugin and created a .parcelrc file in my project root. Inside it contained this:

{
	"extends": "@parcel/config-default",
	"resolvers": [
		"...",
		"@kkirbatski/parcel-resolver-require-resolve"
	]
}

I'm not really familiar with these new mechanisms for resolving packages, but hopefully this helps a little.

@joebeachjoebeach
Copy link

This is causing issues with using Preact in the Parcel development server:

Server running at http://localhost:1234
🚨 Build failed.

@parcel/core: Failed to resolve 'preact/jsx-dev-runtime' from './src/app.jsx'

  /Users/joe/code/playground/parcel-preact-error/src/app.jsx:1:1
  > 1 | export default function App() {
  >   | ^
    2 |   return <div>This is content</div>;
    3 | }

Preact specifies what preact/jsx-dev-runtime resolves to via its package.json#exports.

Repo with reproduction.

The alias workaround mentioned in earlier comments works, but it's disappointing that Parcel's JSX docs say Preact works out of the box.

@devongovett
Copy link
Member

#8807 implements package exports support, and will be included in the next release soon.

@devongovett
Copy link
Member

This is now released in nightly. Would be great if you all could try it out in your projects and report back if it is working before the full release!

@danieltroger
Copy link
Contributor

This is now released in nightly. Would be great if you all could try it out in your projects and report back if it is working before the full release!

Great news!

I'll add some comments here if I experience issues with it.

I'm not quite sure yet how big of a pain point this will be for us and if it's worth the effort to report this as a proper issue with a reproduction, but one issue that I encountered already is the following:

daniel@Daniels-MacBook-Pro vanilla-js % yarn dev
Server running at http://localhost:3000
🚨 Build failed.

@parcel/core: Failed to resolve '@depict-ai/ui/locales' from '/Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/locales/index.js'

  /Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/locales/index.js:1:15
  > 1 | export * from "@depict-ai/ui/locales";
  >   |               ^^^^^^^^^^^^^^^^^^^^^^^^
    2 | 

@parcel/resolver-default: Could not find extended tsconfig

  /Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/tsconfig.json:2:14
    1 | {
  > 2 |   "extends": "../../tsconfig_base",
  >   |              ^^^^^^^^^^^^^^^^^^^^^
    3 |   "compilerOptions": {
    4 |     "composite": true,

@parcel/resolver-default: Cannot load file '../../tsconfig_base' in '../../browser-tags-v2/packages/js-ui'.
💡 Did you mean './tsconfig'?

This worked before (on 2.8.3).

The setup is the following:

  1. /Users/daniel/Documents/depict.ai/browser-tags-v2 is a yarn workspace with different packages in the packages folder
  2. The parcel instance that runs in this example from vanilla-js is not part of the browser-tags-v2 workspace. It uses yarn link though to link all packages in the yarn workspace so that the versions on the filesystem are used instead of the published ones on npm.
  3. We're using yarn 3.3.1 everywhere
  4. In /Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/package.json (the package where parcel complains about not being able to find @depict-ai/ui/locales the UI package is included like this: "@depict-ai/ui": "workspace:^" in the dependencies section
  5. When importing @depict-ai/ui from vanilla-js directly (import * as locales from "@depict-ai/ui/locales";) it works

So parcel now has issues resolving workspace packages in workspaces it isn't ran in if that makes sense.

@danieltroger
Copy link
Contributor

Next issue:

@devongovett I'd love to hear from you if this is a supported use case or if I'm just doing illegal stuff here (also contains actual regression:

We're publishing a package that exports both TypeScript code and a SCSS module (for styling).

It would be really nice to be able to just import the TypeScript stuff as import { SearchPage } from "@depict-ai/js-ui"; and the styling as @use "@depict-ai/js-ui";.

To do that, I've put this in the package.json file of @depict-ai/js-ui:

"sass": "index.scss",
"exports": {
    ".": {
      "import": "./dist/module.js",
      "require": "./dist/main.js",
      "types": "./dist/index.d.ts",
      "default": "./dist/module.js",
      "sass": "./index.scss"
    },
    "./locales": {
      "types": "./locales/index.d.ts",
      "import": "./locales/index.js",
      "require": "./locales/require.js",
      "default": "./locales/index.js"
    }
  },

(I got the inspiration for the sass entry from bootstrap)

Unfortunately though, it doesn't work - parcel tries to import the JavaScript into SCSS instead (it does work on packages though that only export scss):

daniel@Daniels-MacBook-Pro vanilla-js % yarn dev
Server running at http://localhost:3000
🚨 Build failed.

@parcel/transformer-sass: expected "{".
  ╷
1 │ import {add_to_version_info as $gXbnb$add_to_version_info, catchify as $gXbnb$catchify, href_change_ipns as $gXbnb$href_change_ipns, Tenant as $gXbnb$Tenant, GenericSliderArrowButton as $gXbnb$GenericSliderArrowButton, RecommendationSlider as $gXbnb$RecommendationSlider, make_placeholder_rr as 
$gXbnb$make_placeholder_rr} from "@depict-ai/utilishared";
  │                                                                                                                                                                                                                                                                                                               
                   ^
  ╵
  ../../browser-tags-v2/packages/js-ui/dist/module.js 1:322  @use
  src/depict-ui.scss 2:1                                     @use
  src/styling.scss 1:1                                       root stylesheet

  Error: expected "{".
    ╷
  1 │ import {add_to_version_info as $gXbnb$add_to_version_info, catchify as $gXbnb$catchify, href_change_ipns as $gXbnb$href_change_ipns, Tenant as $gXbnb$Tenant, GenericSliderArrowButton as $gXbnb$GenericSliderArrowButton, RecommendationSlider as $gXbnb$RecommendationSlider, make_placeholder_rr as 
  $gXbnb$make_placeholder_rr} from "@depict-ai/utilishared";
    │                                                                                                                                                                                                                                                                                                             
                       ^
    ╵
    ../../browser-tags-v2/packages/js-ui/dist/module.js 1:322  @use
    src/depict-ui.scss 2:1                                     @use
    src/styling.scss 1:1                                       root stylesheet
      at Object.wrapException (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:1250:17)
      at Object.throwWithTrace0 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:23399:15)
      at ScssParser0.wrapSpanFormatException$1$1 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:91071:13)
      at ScssParser0.wrapSpanFormatException$1 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:91077:19)
      at ScssParser0.parse$0 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:95148:19)
      at Object.Stylesheet_Stylesheet$parse0 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:22778:56)
      at /Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:71275:63
      at _wrapJsFunctionForAsync_closure.$protected (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:3841:15)
      at _wrapJsFunctionForAsync_closure.call$2 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28694:12)
      at _awaitOnObject_closure.call$1 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28682:32)



Regression in 2.0.0-nightly.1251

A regression of the new exports system is that it's not possible anymore to import the styling by explicitly specifying a file name (to workaround the error message shown above):

Let me know if you need a better reproduction for this.

I will try to create a styling.scss file in the meantime and see if that works instead.

daniel@Daniels-MacBook-Pro vanilla-js % yarn dev
Server running at http://localhost:3000
🚨 Build failed.

@parcel/transformer-sass: Can't find stylesheet to import.
  ╷
2 │ @use "@depict-ai/js-ui/index.scss" as plp-styling;
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/depict-ui.scss 2:1  @use
  src/styling.scss 1:1    root stylesheet

  Error: Can't find stylesheet to import.
    ╷
  2 │ @use "@depict-ai/js-ui/index.scss" as plp-styling;
    │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ╵
    src/depict-ui.scss 2:1  @use
    src/styling.scss 1:1    root stylesheet
      at Object.wrapException (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:1250:17)
      at /Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:71174:25
      at _wrapJsFunctionForAsync_closure.$protected (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:3841:15)
      at _wrapJsFunctionForAsync_closure.call$2 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28694:12)
      at _awaitOnObject_closure.call$1 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28682:32)
      at Object._rootRunUnary (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:4216:18)
      at StaticClosure.<anonymous> (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:100086:16)
      at _CustomZone.runUnary$2$2 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:30091:39)
      at _Future__propagateToListeners_handleValueCallback.call$0 (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:29163:51)
      at Object._Future__propagateToListeners (/Users/daniel/Documents/depict.ai/storefronts/vanilla-js/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:4012:93)

@devongovett
Copy link
Member

@danieltroger thanks so much for testing! Really great to get feedback from real-world projects – it's really hard to cover all possible project setups in our integration tests so this is very helpful.

You have some interesting cases here. The first one looks related to tsconfig. It's trying to find the "../../tsconfig_base" file referenced in the "extends" field from /Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/tsconfig.json, so /Users/daniel/Documents/depict.ai/browser-tags-v2/tsconfig_base. I think this is perhaps a bug where we need to append .json to that if it is omitted.

The second issue about SASS is because with package.json exports, only files declared in the exports map are allowed to be imported, so where it would previously have resolved to index.scss it won't anymore. The "sass" export condition isn't yet supported, so it resolves to the "default" export. We could probably support the "sass" condition though, not sure if other tools do.

Third issue is the same as the second. Importing directly from index.scss won't work with package.json exports unless it is explicitly declared as an export. This is also how node and other tools work, but does make me a little nervous about introducing this change in a minor version...

@danieltroger
Copy link
Contributor

The first one looks related to tsconfig. It's trying to find the "../../tsconfig_base" file referenced in the "extends" field from /Users/daniel/Documents/depict.ai/browser-tags-v2/packages/js-ui/tsconfig.json, so /Users/daniel/Documents/depict.ai/browser-tags-v2/tsconfig_base. I think this is perhaps a bug where we need to append .json to that if it is omitted.

Yes, the tsconfig error looks like that's probably it.
Do you think it's unable to find the locales export though because it can't correctly read the tsconfig? Why does it need to understand the tsconfig?

We could probably support the "sass" condition though, not sure if other tools do.

Not sure, but some tool should because bootstrap does it, I assume?
I think it would be awesome if you could support it.

The second issue about SASS is because with package.json exports, only files declared in the exports map are allowed to be imported

Why does this not work then?
parcel-repro.zip

(Unzip, yarn install, yarn build)

It yields:

daniel@Daniels-MacBook-Pro parcel-repro % yarn build
🚨 Build failed.

@parcel/transformer-sass: Can't find stylesheet to import.
  ╷
1 │ @use "@depict-ai/react-ui/styles/index.scss" as search-styling;
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/styling.scss 1:1  root stylesheet

  Error: Can't find stylesheet to import.
    ╷
  1 │ @use "@depict-ai/react-ui/styles/index.scss" as search-styling;
    │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ╵
    src/styling.scss 1:1  root stylesheet
      at Object.wrapException (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:1250:17)
      at /private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:71174:25
      at _wrapJsFunctionForAsync_closure.$protected (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:3841:15)
      at _wrapJsFunctionForAsync_closure.call$2 (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28694:12)
      at _awaitOnObject_closure.call$1 (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:28682:32)
      at Object._rootRunUnary (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:4216:18)
      at StaticClosure.<anonymous> (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:100086:16)
      at _CustomZone.runUnary$2$2 (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:30091:39)
      at _Future__propagateToListeners_handleValueCallback.call$0 (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:29163:51)
      at Object._Future__propagateToListeners (/private/tmp/parcel-repro/.yarn/cache/sass-npm-1.58.3-8afd137ed0-35a2b98c03.zip/node_modules/sass/sass.dart.js:4012:93)

Why I think this should work:

@depict-ai/[email protected] has

"exports": {
   "./styles/": "./dist/styles/",
}

in its package.json.
Also I'd love @use "@depict-ai/react-ui/styles/" as search-styling; to work.

How would you recommend me solve my sass exporting use case?

This is also how node and other tools work, but does make me a little nervous about introducing this change in a minor version...

Indeed. I think it could break lots of things and there doesn't seem to be a workaround for that breakage other than changing the imported package?

@devongovett
Copy link
Member

Why does it need to understand the tsconfig?

This is to support another resolver feature, which respects the baseUrl and paths declared in tsconfig.json. Kind of unrelated to package exports, just something else that happens while trying to resolve.

Not sure, but some tool should because bootstrap does it, I assume?

Bootstrap uses the top-level "sass" field in package.json it seems: https://github.com/twbs/bootstrap/blob/5241b988c0156dbcc2c6bdaeb29967141bea567d/package.json#L39 I don't see any exports in their package.json. But I do see that sass-loader in webpack does support the "sass" condition, so probably worth supporting.

Why I think this should work:

"exports": {
   "./styles/": "./dist/styles/",
}

Ah this is using a deprecated syntax in package exports for exporting directories. Node deprecated this syntax in Node 14, and fully removed it in Node 17: https://nodejs.org/api/deprecations.html#DEP0148. I thought since Parcel's support for this is brand new we could get away without supporting it. The new syntax is:

"exports": {
   "./styles/*": "./dist/styles/*",
}

See https://nodejs.org/api/packages.html#subpath-patterns.

How would you recommend me solve my sass exporting use case?

I think supporting the "sass" export condition is probably the right way. Alternatively you could add "./index.scss" to your package exports.

Indeed. I think it could break lots of things and there doesn't seem to be a workaround for that breakage other than changing the imported package?

Well, it's a bit of a strange case because most packages on npm would already have had to deal with this if they supported node or other tools like webpack for a while. For internal packages only ever loaded by parcel, package exports were never supported before so it is unlikely that they would have them.

@danieltroger
Copy link
Contributor

danieltroger commented Feb 20, 2023

This is to support another resolver feature, which respects the baseUrl and paths declared in tsconfig.json. Kind of unrelated to package exports, just something else that happens while trying to resolve.

I see. I tried adding .json everywhere after tsconfig_base and can confirm that I now no longer have any workspace related issues, so it seems to just be that lil bug!

Another thing I had to do was changing the following but now everything works again. Just FYI. Change to fix:
diff --git a/storefronts/vanilla-js/babel.config.json b/storefronts/vanilla-js/babel.config.json
index 733ceb3e41..b002b1838a 100644
--- a/storefronts/vanilla-js/babel.config.json
+++ b/storefronts/vanilla-js/babel.config.json
@@ -5,7 +5,7 @@
       {
         "throwIfNamespace": false,
         "runtime": "automatic",
-        "importSource": "~/"
+        "importSource": "~"
       }
     ]
   ]

Error message without it:

🚨 Build failed.

@parcel/core: Failed to resolve '~//jsx-runtime' from './src/scripts/productCard.tsx'

  /Users/daniel/Documents/depict.ai/storefronts/vanilla-js/src/scripts/productCard.tsx:2:45
    1 | import { ContainedPlaceholderImage, Placeholder } from "@depict-ai/utilishared";
  > 2 | import { StrongerDisplay } from "./display";
  >   |                                             ^
    3 | 
    4 | const img_aspect_ratio = 2 / 3;

@parcel/resolver-default: Cannot load file './/jsx-runtime' in './'.
💡 Did you mean './jsx-runtime'?

But I do see that sass-loader in webpack does support the "sass" condition, so probably worth supporting.

Yay, that'd be amazing 🎉

Ah this is using a deprecated syntax in package exports for exporting directories.

Ah, thanks. Thanks a lot for the links to the docs too. What do you think about warning about this? I think that could save people time and pain.

I think supporting the "sass" export condition is probably the right way. Alternatively you could add "./index.scss" to your package exports.

Right, so just "./index.scss": "./index.scss" I presume.

On a second thought

Importing directly from index.scss won't work with package.json exports unless it is explicitly declared as an export.

Why doesn't @use "@depict-ai/js-ui/styles" as plp-styling;

work given

"exports": {
    ".": {
      "import": "./dist/module.js",
      "require": "./dist/main.js",
      "types": "./dist/index.d.ts",
      "default": "./dist/module.js",
      "sass": "./styles.scss"
    },
    "./locales": {
      "types": "./locales/index.d.ts",
      "import": "./locales/index.js",
      "require": "./locales/require.js",
      "default": "./locales/index.js"
    }
  },

I'd consider it explicitly declared when it says "sass": "./styles.scss". Maybe it makes sense to allow importing things where the key is not yet supported by parcel?

@danieltroger
Copy link
Contributor

Right, so just "./index.scss": "./index.scss" I presume.

This works, but only when importing @depict-ai/js-ui/index.scss and not when importing @depict-ai/js-ui/index like it normally would in sass

@devongovett
Copy link
Member

#8844 implements support for the sass, less, stylus, and style conditions supported by webpack. It also opens the door for plugins to support other custom conditions. Note that in your example, "sass" would need to come before the "default" condition for this to work, since default always matches and matching follows the key order in package.json.

That PR also fixes the tsconfig extends bug.

@ukstv
Copy link

ukstv commented Apr 20, 2023

I regret to post to a closed issue, but I think the story is not over yet. Apparently, parcel can not correctly resolve uint8arrays or multiformats/bases/base36 for example. I guess, the culprit is the default config actually ignores exports map and looks for main or whatever. I manually modified package.json for uint8arrays to set main field, and it works fine. Surprisingly, "exports": {".": "./dist/src/index.js"} did not work.

@ukstv
Copy link

ukstv commented Apr 20, 2023

Oh, never mind. It works in nightly. I hope it is released soon enough.

@devongovett
Copy link
Member

Yes, sorry it's taken longer than expected to get released. We have run into some backward compatibility issues. Unfortunately, I think we are going to have to make exports support opt-in until Parcel 3 as adding it is a breaking change for some packages. Once that is done we can release it soon.

@danieltroger
Copy link
Contributor

For future reference, here's how to opt-in to this before parcel 3 is released https://parceljs.org/blog/v2-9-0/#new-resolver

@char0n
Copy link

char0n commented Aug 22, 2023

Hi everybody,

When bundling CommonJS code and one of the dependencies is using using imports field, we'll end up hanging on the following error:

@parcel/core: Failed to resolve '#swagger-ui' from 
'./node_modules/swagger-ui-react/index.cjs'

  /swagger-ui-parcel/node_modules/swagger-ui-react/index.cjs:7:49
    6 | var _propTypes = _interopRequireDefault(require("prop-types"));
  > 7 | var _swaggerUi = _interopRequireDefault(require("#swagger-ui"));

New resolver is explicitly enabled in root package.json:

  "@parcel/resolver-default": {
    "packageExports": true
  }

I've tried to use alias in root package.json, but with no effect:

  "alias": {
    "./node_modules/swagger-ui-react/index.mjs": "./node_modules/swagger-ui-react/index.cjs",
    "#swagger-ui": "./node_modules/swagger-ui-react/swagger-ui.js"
  }

Any idea how to resolve this, or do I need to write my own resolver?

Note: when using ESM, everything works as expected.

@mgol
Copy link

mgol commented Feb 13, 2024

I’m testing Parcel exports implementation against jQuery (which introduces exports in its recently released 4.0.0-beta) and I struggle to make it work without duplicating jQuery when both import & require are used in the code base. More info in the jQuery issue jquery/jquery#5416; I’d appreciate input from Parcel maintainers there.

@fregante
Copy link
Contributor

fregante commented Jun 27, 2024

Since this is the top search result, here's what you need to enable support for the exports map in Parcel v2.

Add this to your package.json:

{
  "dependencies": {
    // your stuff here
  },
  "devDependencies": {
    // your stuff here
  },
  "@parcel/resolver-default": {
     "packageExports": true
  }
}

@ukstv
Copy link

ukstv commented Jun 27, 2024

Oh, and 2 cents from me regarding monorepo. If you use monorepo, @parcel/resolver-default (see above) clause should be set on the root package.json. Otherwise, parcel does not pick it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.