Reputation: 10340
I am writing a Bluetooth library for Node.js using TypeScript and Rollup. I want to enable users to import my libraries components in these ways
import Sblendid from "@sblendid/sblendid";
import Sblendid, { Peripheral } from "@sblendid/sblendid";
const Sblendid = require("@sblendid/sblendid");
const { Peripheral } = require("@sblendid/sblendid");
My project structure looks like this:
root
∟ rollup.config.ts
∟ src
∟ index.ts
∟ sblendid.ts
∟ peripheral.ts
And the according code is this:
index.ts
export {
default,
} from "./sblendid";
export {
default as Peripheral,
} from "./peripheral";
sblendid.ts
export default class Sblendid {}
peripheral.ts
export default class Peripheral {}
I am bundling everything with Rollup and my entire config is this:
import typescript from "typescript";
import commonjs from "rollup-plugin-commonjs";
import resolve from "rollup-plugin-node-resolve";
import typescriptPlugin from "rollup-plugin-typescript2";
import autoExternal from "rollup-plugin-auto-external";
import { terser } from "rollup-plugin-terser";
import pkg from "./package.json";
export default {
input: "src/index.ts",
output: [
{
file: pkg.main,
format: "cjs",
sourcemap: true
},
{
file: pkg.module,
format: "es",
sourcemap: true
}
],
plugins: [
autoExternal(),
resolve({ preferBuiltins: true }),
commonjs(),
typescriptPlugin({ typescript, objectHashIgnoreUnknownHack: true }),
terser()
]
};
You can find the entire code here
https://github.com/LukasBombach/sblendid/tree/master/packages/sblendid
Now, this setup does not work. Rollup tells me
$ rollup -c rollup.config.ts src/index.ts → dist/index.cjs.js, dist/index.es.js... (!) Mixing named and default exports Consumers of your bundle will have to use bundle['default'] to access the default export, which may not be what you want. Use `output.exports: 'named'` to disable this warning
which is true. This
const Sblendid = require("@sblendid/sblendid");
simply does not work. What I have to do is this:
const Sblendid = require("@sblendid/sblendid").default;
I can fix this behavior by not mixing named ad default exports, ok, but then I lose the ability to do this:
import Sblendid, { Peripheral } from "@sblendid/sblendid";
So I am wondering. Is there any way, maybe using multiple bundles, I can achieve having users be able to do both:
// This
import Sblendid from "@sblendid/sblendid";
import Sblendid, { Peripheral } from "@sblendid/sblendid";
// And this
const Sblendid = require("@sblendid/sblendid");
const { Peripheral } = require("@sblendid/sblendid");
Upvotes: 14
Views: 11742
Reputation: 23
We can achieve this by patching rollup.
https://github.com/avisek/rollup-patch-seamless-default-export
// Default export
const lib = require('your-library')
lib('Hello') // <-- instead of using `.default` property
// Named exports
const { namedExport1, namedExport2 } = lib
// One liner syntex. This is also supported.
const { default: defaultExport, namedExport1, namedExport2 } = require('your-library')
Upvotes: 0
Reputation: 864
Commonjs does not have the concept of default export. When you are able do:
const Splendid = require("@sblendid/sblendid");
const { Peripheral } = require("@sblendid/sblendid");
It does mean that
assert.equal(Splendid.Peripheral, Peripheral);
That Peripheral
is a property of Splendid
.
This is basically achieved by
Splendid.Peripheral = /* something */;
module.exports = Splendid;
When cjs code is transpiled from esm code (what rollup does) the only choice is to introduce a default
property on the exports
object.
If you're not comfortable with adding properties just for the sake of exporting, add a snipped like this to your docs.
const { default: Splendid, Peripheral } = require('...');
Upvotes: 0
Reputation: 610
If you target only nodejs environment you can export like this (index.ts)
import Sblendid from "./sblendid";
import Peripheral from "./peripheral";
Sblendid.Peripheral = Peripheral;
export default Sblendid;
Upvotes: 1