Closed wizardnet972 closed 6 months ago
Another issue related to this, when I create @nx/js
lib with esbuild, nx compile by default to esm
and because the node is compile with cjs
it can't import this lib.
if I change the node app to work as esm
then back to the main issue - the lib can't be found because esm
doesn't handle the libs inside the project. also it not wrap them with __toEsm
.
Hitting this same issue. Existed in 15.x
too. Seems like there's a special case for cjs
that handles lib imports. I assume there's a reason it's not enabled for esm
?:
Another issue related to this, when I create
@nx/js
lib with esbuild, nx compile by default toesm
and because the node is compile withcjs
it can't import this lib. if I change the node app to work asesm
then back to the main issue - the lib can't be found becauseesm
doesn't handle the libs inside the project. also it not wrap them with__toEsm
.
Currently you cannot import a @nx/js library inside a @nx/node app. You can verify this on an empty workspace by creating a node app and a js library both with esbuild as bundler and try to share code between them. @AgentEnder @jaysoo @FrozenPandaz @vsavkin
@samratarmas and others with related problems:
I have am using shared @nx/js
libs in my nx workspace right now in both vite/react front-end (esm) and node/express back-end (cjs) apps. The trick: build both cjs + esm so everything is happy.
I would prefer all esm but as you have discovered node
generator and nx serve
(among others...) breaks with esm and nx has not addressed these issues to date.
My solution is as follows:
context: all of my projects libs are buildable my "build" target in project.json
uses the @nx/esbuild:esbuild
executor
package.json
of your lib strip module
etc so that instead of you overriding his value it will be generated during build
package.json
of my shared libs only specify name
, version
, and sideEffects
project.json
under targets.build.options
"generatePackageJson": true
"format": ["esm", "cjs"]
Note how project.json
can override your tsconfig. You can even go all-out and specify custom options direct to esbuild by adding a targets.build.options.esbuildOptions
object that take absolute precedence.
A potentially useful capability with esbuildOptions
that might help depending on your project/deploy requirements is the ability to set outExtension
in case you need .mjs
(otherwise Nx will choose js
for esm and cjs
for cjs).
Troubleshooting:
project.json
in its entirety and ensure that you have no other configurations
that will override the above (and if you do, modify them accordingly).dist/
output to make sure entrypoint files is being created for each of cjs and esm and that the generated package.json has identified the correct ones for module
and main
I hope this helps you, it took some time to land on this solution. I couldn't find anything helpful in the docs.
IMHO shared libraries across front-end and back-end are a key reason to use Nx and I think it should Just WorkTM out of the box
Obviously this is not how it should be, but setting bundle
to true in the esbuild config in project.json
seems to work for now.
As mentioned in previous comments, the support for ESM in @nx/node is not there, however if you tell esbuild to bundle everything to one file then your compiled code is all in one entry main.js file so there are no ESM imports to worry about.
@hugonteifeh and @samratarmas I agree eliminating imports entirely with bundle: true
is a logical and valid solution to eliminating import problems... I have an important caveat to share regarding tree shaking.
One of the key reasons why I chose to build both cjs + esm for the shared @nx/js
libraries in my project and why I suggested it above was to preserve the ability tof downstream bundlers to effectively optimize builds.
In terms of cutting down my React bundle sizes, the combination of declaring sideEffects
in package.json
(ideally false
if you can help it) and providing ESM for downstream bundlers proved effective in my Nx project (including with the stock configuration of Vite+React).
Otherwise beware of unused/dead code from shared libraries ending up in your front-end builds. You could end up with an entire library/package's code (and potentially all of its dependencies! imagine all of @faker-js/faker
or something) mashed into your bundle even if you only imported a tiny few-lines-of-code helper function from a shared utility library.
Size wasn't a huge concern for me on the back-end (though it may be for some) however on the front and it caused some big red flags with absurd bundle sizes in React apps until I addressed it.
(if anyone from nrwl/nx is reading this: please support using ESM everywhere)
From a brand new project (node app + JS lib), if I build my depended libs
then run serve it works. The other solution is to set the field bundle
to true in my app
project.json.
npx nx run my-js-lib:build --skip-nx-cache=true
npx nx run my-node-svc:serve
Is there a way to build all the depended libs when running serve
?
This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! 🙏
Is this solved now? Or is the workaround all that is available
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.
Current Behavior
I create a nodejs app with
esbuild
andesm
.In the project, I have imports from libs.
When nx builds the node project it not add the mapping code to the output files (
_resolveFilename
) or don't add them topackage.json
.The results are the libs is missing from the node runtime.
Expected Behavior
like
cjs
format, should be handle the imports from the libs.GitHub Repo
No response
Steps to Reproduce
esm
Nx Report