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 default export when required from CJS #2148

Merged
merged 1 commit into from
Oct 9, 2024
Merged

Conversation

simonihmig
Copy link
Collaborator

@simonihmig simonihmig commented Oct 9, 2024

When this package was converted to TS, module.exports = was converted to export default, without taking into account that this would make TS emit this as a named export of "default" (exports.default = sideWatch), so CJS consumers would have to call it as require('@embroider/broccoli-side-watch').default() (aka "double default" problem). As we are only targeting CJS consumers, this changes makes the compiled js have a single main export as module.exports = sideWatch.

Tests weren't able to catch this, as TS was providing the interoperability, while node.js does not.

When this package was converted to TS, `module.exports = ` was converted to `export default`, without taking into account that this would TS emit this as a named export of "default" (`exports.default = sideWatch`), so CJS consumers would have to call it as `require('@embroider/broccoli-side-watch').default()` (aka "double default" problem). As we are only targeting CJS consumers, this changes makes the compiled js have a single main export as `module.exports = sideWatch`.
@simonihmig simonihmig added the bug Something isn't working label Oct 9, 2024
@@ -27,7 +27,7 @@ interface SideWatchOptions {
dependencies that you're actively developing. For example, right now
@embroider/webpack doesn't rebuild itself when non-ember libraries change.
*/
export default function sideWatch(actualTree: InputNode, opts: SideWatchOptions = {}) {
function sideWatch(actualTree: InputNode, opts: SideWatchOptions = {}) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe it's better to author as proper modules and expose a compiled dist instead of source than to ship cjs compatible code by default

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not sure what exactly you mean here? How could I write code or set up TS so that export default compiles to something that would work in CJS as const sideWatch = require('@embroider/broccoli-side-watch')?

FWIW, we have a similar case here.

The alternative would be to not using a default export, but require users to const { sideWatch } = require('@embroider/broccoli-side-watch'), which wouldn't suffer from that interoperability problem.

Copy link
Collaborator

Choose a reason for hiding this comment

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

personally I don't see why import { sideWatch } ... is frowned upon
I would prefer that to writting the similar case you mentioned before

while this will not really be needed in vite land and so on
it sets precedence which could be followed when adding other packages that may be used from module only places

and I'm not sure if we're not going to have issues with macros in the future because of the choice you mentioned there in systems that use modules exclusively

are we in a new enough node environment where we could say use top level import? would that work?

as for how to make the current syntax work, I'm talking ab out shipping two separate bundles one for cjs and one for modules with entry points specific to each declared in package json
all of that is a much more convoluted setup and would require more of a pre build step than we're doing now

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This package is going to be used in ember-cli-build.js, which is supposed to be CJS, so I think it does need to work nicely in a CJS env.

I'm open to moving to const { sideWatch } = require('@embroider/broccoli-side-watch'), but since this package existed before (as unstable) and was actively used, I preferred to not cause a breaking change.

For the dual build setup, I'm all for that, but indeed this is well out of scope for this quick fix.

@ef4 ef4 merged commit ca5f8f7 into stable Oct 9, 2024
223 checks passed
@ef4 ef4 deleted the fix-side-watch-export branch October 9, 2024 13:38
@github-actions github-actions bot mentioned this pull request Oct 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants