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

Fix broken NPM bundle by publishing in ES-Module format #1944

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

elikoga
Copy link

@elikoga elikoga commented Mar 17, 2025

Closes #1943

This fixes the issue that the generated CommonJS NPM-Published Bundle contains invalid CommonJS (top level await is not supported in CommonJS), which makes tooling fail.

What is important to note is that a top-level await itself is not the problem at all, the only problem is the fact that the published bundle contains invalid CommonJS. The CommonJS format does not allow top-level awaits.

CI passes on my master.

@elikoga elikoga force-pushed the master branch 2 times, most recently from 88f0580 to b5be498 Compare March 17, 2025 15:48
@elikoga elikoga changed the title Fix NPM bundle by publishing in ES-Module format Fix broken NPM bundle by publishing in ES-Module format Mar 17, 2025
Copy link
Member

@CendioOssman CendioOssman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Nice work!

I had a look at what this might require from users. And it sees Node.js 14 will be needed. But that is long EoL, so I would assume all users have a sufficiently new Node.js for this.

package.json Outdated
"prepublish": "node ./utils/convert.js --clean"
"lint": "eslint app core po/po2js.cjs po/xgettext-html.cjs tests utils",
"test": "karma start karma.conf.cjs",
"prepare": "node ./utils/convert.cjs --clean"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a conversion step at all?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might be able to get away with simply copying a folder, however that would increase the complexity of the patch.

There is little harm in having an additional no-op buildstep except for the build times.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have modified convert.js to a build.js that copies the required js files to the target folder without using babel

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted: Actually, since we are using Babel to rewrite vendored imports, the conversion script is needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewriting does not seem to work properly. I'm not seeing any changes.

We could also consider dropping that as well, as the relative path will be the same.

In fact, is there any requirement on a lib/ directory? We mostly had that since the files were change. Is there anything preventing us from just shipping core/ and vendor/ as is?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any fundamental problem, except for the fact that I use the import as follows let RFB = await import('@novnc/novnc/lib/rfb.js'); so I would want to preserve some file-copying so that we keep the imports the same as before.

Cockpit uses the same import path as far as I can see:
https://github.com/cockpit-project/cockpit-machines/blob/d0a26ccf69f1969e02ef4a0c8e835da305dd43f9/src/components/vm/consoles/consoles.jsx#L22C34-L22C58
https://github.com/patternfly/react-console/blob/1cf89cb13e829f3691010687ea034f90b59f3cf7/packages/module/src/components/VncConsole/VncConsole.tsx#L7

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We specify the primary import in package.json. What is that used for? Can't users of our npm package respect that somehow?

Copy link
Author

@elikoga elikoga Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://docs.npmjs.com/cli/v11/configuring-npm/package-json#browser

If your module is meant to be used client-side the browser field should be used instead of the main field. This is helpful to hint users that it might rely on primitives that aren't available in Node.js modules. (e.g. window)

It seems to be cosmetic/for documentation purposes but I am still testing some stuff

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My tooling gives me:

[plugin:vite:import-analysis] Failed to resolve entry for package "@novnc/novnc". The package may have incorrect main/module/exports specified in its package.json.

image

So the value seems to be ignored by my flavour of tooling

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A modern solution would be to use the exports field:

https://docs.npmjs.com/cli/v11/configuring-npm/package-json#exports
https://nodejs.org/api/packages.html#package-entry-points

Which is supported since Node 12 and would allow us to make the npm-published slimmer while keeping old imports valid.

@elikoga
Copy link
Author

elikoga commented Mar 25, 2025

Rebased on to master

@@ -62,7 +62,7 @@ export default [
}
},
{
files: ["po/po2js", "po/xgettext-html"],
files: ["po/po2js.js", "po/xgettext-html.js"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't seem to be any need to add any extension to these commands now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need, can change back

"prepublish": "node ./utils/convert.js --clean"
"lint": "eslint app core po/po2js.js po/xgettext-html.js tests utils",
"test": "karma start karma.conf.cjs",
"prepare": "node ./utils/convert.js --clean"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, the change to "prepare" is best kept in its own commit.

package.json Outdated
"prepublish": "node ./utils/convert.js --clean"
"lint": "eslint app core po/po2js.cjs po/xgettext-html.cjs tests utils",
"test": "karma start karma.conf.cjs",
"prepare": "node ./utils/convert.cjs --clean"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewriting does not seem to work properly. I'm not seeing any changes.

We could also consider dropping that as well, as the relative path will be the same.

In fact, is there any requirement on a lib/ directory? We mostly had that since the files were change. Is there anything preventing us from just shipping core/ and vendor/ as is?

Comment on lines 68 to 71
presets: [
[ '@babel/preset-env',
{ modules: 'commonjs' } ]
{ modules: false } ]
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presets is doing some weird stuff with the code. We likely want to drop this (if we don't end up dropping babel completely).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try dropping babel once again

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

Successfully merging this pull request may close these issues.

noVNC cannot be bundled due to top-level await in browser.js
2 participants