microbundle
                                
                                 microbundle copied to clipboard
                                
                                    microbundle copied to clipboard
                            
                            
                            
                        Mixed default and named exports changes default export
Hey everyone! I am having the following issue, if I export like this:
import GoogleMap from './google_map';
export default GoogleMap;
It will build:
module.exports = GoogleMap;
However, when including named exports:
import GoogleMap from './google_map';
export { namedExport1, namedExport2 } from './named_exports;
export default GoogleMap;
it changes to:
exports.namedExport1 = namedExport1;
exports.namedExport2 = namedExport2;
...
exports.default = GoogleMap;
Which results in the following error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I am pretty sure you will ask why we do need default exports, in my case I've a library that is used by a lot of people, I switched to microbundle a bit ago and realized later on this was buggy and it won't work with SSR unless we do module.exports, thing is even if I want to change the way we import / export to work with microbundle, I need to provide backwards compatibility or something...
I think this might be related to #264 and #306 but I am not completely sure if that's the case.
Hiya. This is done intentionally. Here's what you can do to produce CommonJS and UMD bundles that don't have the issue:
{
  "scripts": {
    "build": "microbundle -f cjs,umd src/index.cjs.js && microbundle -f es,modern src/index.js"
  }
}
// index.js
import GoogleMap from './google_map';
export { namedExport1, namedExport2 } from './named_exports;
export default GoogleMap;
// index.cjs.js
import GoogleMap from './google_map';
import { namedExport1, namedExport2 } from './named_exports;
Object.assign(GoogleMap, { namedExport1, namedExport2 });
export default GoogleMap;
Now require('your-lib') === GoogleMap, but require('your-lib').namedExport1 === namedExport1.
I might add an option to do this automatically.
Works like a charm, thanks for the quick response!
Would be awesome if you add an option to do this automatically! 🎉
Feel free to close the issue, unless you want to keep it for that option you want to add.
@developit any implications why we don't do this behaviour by default if it's umd/cjs? Any reasons that make this a big nono?
TBH I don't think there would be any negative effects, it just hasn't been implemented.
I might add an option to do this automatically.
@developit would love this
same lol
I've been getting a lot of bug reports on how this works in markdown-to-jsx: https://github.com/probablyup/markdown-to-jsx/issues/333
https://github.com/probablyup/markdown-to-jsx/blob/676e53ff33036fd0527a9ea79cd478a74ea20513/index.cjs.tsx#L1-L3
Webpack doesn't seem to be able to resolve this
Couldn't you do this for both? Rather than having two different files?
import GoogleMap from './google_map';
import { namedExport1, namedExport2 } from './named_exports;
Object.assign(GoogleMap, { namedExport1, namedExport2 });
export default GoogleMap;
Unfortunately this work around breaks typescript's understanding of the exports
Unfortunately this work around breaks typescript's understanding of the exports
Can use JSDoc for it.
/*
* @type {SomeClass}
*/
const exported = OtherClass
export default exported
// index.cjs.js import GoogleMap from './google_map'; import { namedExport1, namedExport2 } from './named_exports; Object.assign(GoogleMap, { namedExport1, namedExport2 }); export default GoogleMap;
Can't this shadow/replace namedExportX properties of GoogleMap if they exist?
Would the following work?
import GoogleMap from './google_map';
import { namedExport1, namedExport2 } from './named_exports;
export default GoogleMap;
const default = GoogleMap;
export { default, namedExport1, namedExport2 };
or
import GoogleMap from './google_map';
import { namedExport1, namedExport2 } from './named_exports;
export default GoogleMap;
export { GoogleMap as default, namedExport1, namedExport2 };
or
import GoogleMap from './google_map';
export { namedExport1, namedExport2 } from './named_exports;
export default GoogleMap;
export const default = GoogleMap;
Should work as long as default is not a name you care about?!
EDIT: OK. This does not work since default is not a valid identifier.
export default GoogleMap;
export const default = GoogleMap;
is not a allowed as default is a reserved keyword https://mathiasbynens.be/notes/reserved-keywords
It breaks type acquisition in our case :( https://github.com/olesku/eventhub-jsclient/issues/9
@qwelias you should be able to use an intermediary type definition to fix this:
// types.d.ts
import EventHub from './eventhub.ts';
export default EventHub;
export = EventHub;
FWIW TypeScript has a setting that fixes this ("commonjsInterop" or something to that effect), however that's the crux of the issue: TypeScript doesn't have a logical behaviour for modules that are situationally CommonJS or ESM. The only generalized solution is to explicitly define the root export.
Glad I found this! https://github.com/developit/microbundle/issues/712#issuecomment-683794530
I set up a demo repo if anyone is curious to see this in action https://github.com/DavidWells/microbundle-cjs-default-export-fix/