Tree Shaking with Good DX

I'm trying to see if there's a solution where I can have a great developer experience (DX) (Ability to call elements as children of the parent like <Table.Row>) but also tree shake my primitive UI components. Given the following code...
const _Table = ({children}) => React.createElement("Table", {children});
const Head = ({children}) => React.createElement("Head", {children});
const Header = ({children}) => React.createElement("Th", {children});
const Body = ({children}) => React.createElement("TBody", {children});
// etc.

const Table = {Table: _Table, Head, Header, Body}
export default Table;
const _Table = ({children}) => React.createElement("Table", {children});
const Head = ({children}) => React.createElement("Head", {children});
const Header = ({children}) => React.createElement("Th", {children});
const Body = ({children}) => React.createElement("TBody", {children});
// etc.

const Table = {Table: _Table, Head, Header, Body}
export default Table;
When importing, I'd like to use it like so... (best DX)
return (
<Table.Table>
<Table.Head>
</Table.Head>
</Table.Table>
)
return (
<Table.Table>
<Table.Head>
</Table.Head>
</Table.Table>
)
My understanding is that importing it as the default won't tree-shake unused elements since I'm importing the whole Table object
import Table from "./Table";
import Table from "./Table";
But I also don't want to do something like this where I have to import all the elements at the top. This optimizes tree-shaking but decreases developer experience
import {TableTable, TableHead} from "./Table"

return (
<TableTable>
<TableHead>
</TableHead>
<TableTable>
)
import {TableTable, TableHead} from "./Table"

return (
<TableTable>
<TableHead>
</TableHead>
<TableTable>
)
The only alternative I can think of is...
// Table.tsx
// define the elements

const Table = {
Table: _Table,
Head,
Header,
Body,
TableRoot: _Table,
TableHead: Head,
TableHeader: Header,
TableBody: Body,
}
export const Table;
// Table.tsx
// define the elements

const Table = {
Table: _Table,
Head,
Header,
Body,
TableRoot: _Table,
TableHead: Head,
TableHeader: Header,
TableBody: Body,
}
export const Table;
Then when using it... you can choose to import it all or if you only need a small portion you can only import that element. But I think this somewhat defeats the whole tree shaking thing as it makes it much bigger in size when importing it all.
import Table from "./Table" // <- this makes it even bigger in size now I think
// or
import {TableRoot, TableHead} from "./Table"
import Table from "./Table" // <- this makes it even bigger in size now I think
// or
import {TableRoot, TableHead} from "./Table"
Open to different people's ideas and thoughts on what the best approach is.
1 Reply
Paul
Paul16mo ago
Also, if in my application I use Table.Header once, does that mean it'll be included in the bundle so there's no point trying to remove tree-shake it because all other references will just be a reference to it? So the only benefit of tree-shaking is when you DON'T use it at all anywhere in your application?