Svelte: CommonJS output is non-idiomatic

Created on 25 Apr 2019  Â·  17Comments  Â·  Source: sveltejs/svelte

Right now (Svelte 3.0.1), when you call compile with format: 'cjs', the final line of the output code is

exports.default = Test;

which seems like a bug – usually you only see default in CommonJS-land when you're dealing with ESM modules that were bundled to CJS. You wouldn't expect to see default in a vanilla CJS module.

It seems like the export should just be

exports = Test;
proposal

Most helpful comment

@cam-stitt for the time being, in your jest transformer you can inject the es module interop code to prevent needing to call .default. See example: https://github.com/WeAreGenki/minna-ui/blob/dev/utils/jest-config/src/svelte-transform.ts#L23

I admit though it's a bit awkward for svelte components to use exports.default _without_ the es module interop too.

All 17 comments

I think this causes more problems than it solves in the long run, no? It changes the component's semantics (any named exports becomes static properties of the component itself, unlike in ESM) and I imagine it would break import Thing from './cjs/Thing.svelte'. (Though maybe we need to add exports.__esModule = true for that)

It changes the component's semantics

Can a component definition ever actually export anything besides the constructor function? I thought all other exports were interpreted as props, instead of being something that it made sense to actually import/require somewhere else.

import Thing from './cjs/Thing.svelte'

This behavior is undefined as far as I'm concerned – different bundlers have different behavior here.

Realistically, since Svelte is ESM-first, I think the only folks who will be compiling to CommonJS will be ones targeting node, or browserify.

const SomeComponent = require('./SomeComponent.html').default looks really awkward, I'd probably add a nasty hack to sveltify rather than force that on browserify users

Can a component definition ever actually export anything besides the constructor function?

yep: https://svelte.dev/tutorial/module-exports

derp, forgot about context="module"

I'm still leaning towards the idiomatic CJS thing being

AudioPlayer.stopAll = stopAll
module.exports = AudioPlayer

This might be worth exploring as well. Babel did this back at version 5, but it got removed for spec compatibility.

CommonJS output also breaks import foo from 'bar'; in a Svelte component. foo ends up being undefined.

An issue that may potentially be caused by the current CJS format. When using Svelte 3 with Jest, I'm having to access default on the imported component:

import Component from './Component.html';

new Component.default({});

It is a strange quirk to have to remember to add the .default to all test cases.

@cam-stitt for the time being, in your jest transformer you can inject the es module interop code to prevent needing to call .default. See example: https://github.com/WeAreGenki/minna-ui/blob/dev/utils/jest-config/src/svelte-transform.ts#L23

I admit though it's a bit awkward for svelte components to use exports.default _without_ the es module interop too.

The current sveltify workaround is to replace exports.default = with module.exports =

https://github.com/TehShrike/sveltify/blob/master/index.js#L47

IT'S BAD BUT I'LL FIX IT LATER

Thanks for the fix @MaxMilton it is a handy workaround. It seems though, that some of the dependent imports in my components also fail when using CJS. Has anyone else had that issue? One of the difficulties is working out if it's caused by Jest or Svelte :thinking:. I think it's the svelte changes, as the code worked fine for svelte 2.

@cam-stitt my guess is it may be related to your jest config. Do you have any example repo?

I managed to resolve the issue by adding the interop to my jest transform
for svg assets. I didn't need this for svelte 2, but seems to resolve the
issue now.

On Thu, 9 May 2019, 07:35 Max Milton, notifications@github.com wrote:

@cam-stitt https://github.com/cam-stitt my guess is it may be related
to your jest config. Do you have any example repo?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/sveltejs/svelte/issues/2562#issuecomment-490659478,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AABNSE7MWR7M3IYJWXDC4JTPUNBQFANCNFSM4HINOC2Q
.

I feel like it's probably been long enough that, whether or not this was the right decision before, changing it now would definitely be a breaking change. Thoughts?

I think this could still be fixed in a backwards-compatible way?

module.exports = Object.assign(Test, moduleExports, {
    default: Test
})

Oh, it's happening again. Don't you think it's much easier to avoid default exports completely? They were added only to interop with commonjs and does not really serve this purpose but make it even more complex. Considering module as a namespace works well for many language.

Just an observation. I see a few new issues related to this every month.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Rich-Harris picture Rich-Harris  Â·  3Comments

sskyy picture sskyy  Â·  3Comments

bestguy picture bestguy  Â·  3Comments

1u0n picture 1u0n  Â·  3Comments

matt3224 picture matt3224  Â·  3Comments