opral / lix-sdk

1 stars 0 forks source link

what APIs to tree-shake and what not? #58

Closed samuelstroschein closed 1 week ago

samuelstroschein commented 2 months ago

Context

We are exposing a mix of tree-shakable and non tree-shakable APIs atm.

// not tree-shakable
lix.commit( {... })

// tree-shakable
merge({ lix,  ... })

Proposal

Settle on one consistent approach.

samuelstroschein commented 2 months ago

Arguments for tree-shakable:

await commit(lix, { args })
await merge(lix, { args} )
await resolveConflict(lix, { args })  

Arguments for an all in one object

await lix.commit({ args })
await lix.merge({ args} )
await lix.resolveConflict({ args })

I tend to favor tree-shakable. The lix object would become state. Nothing more, nothing less. Smaller bundle sizes, potentially enabling use cases that are restricted in bundle sizes, and easier testing.

samuelstroschein commented 2 months ago

I forgot about Paraglide JS style tree-shaking + API discovery! This seems to combine the best of both worlds!

import * as sdk from "lix-js/sdk"

// full api discovery for every sdk api
sdk.x

// even `openLix()` is now discoverable 
const lix = await sdk.openLix()

// "state" related functions are discoverable + tree-shakable 🎉
await sdk.commit({ lix, ... args })
await sdk.merge({ lix, ... args })
await sdk.resolveConflict({ lix, ...args })

In case you wonder why I do import * as sdk and not import * as lix, I intend to delay discussions on how to call a lix. For branding purposes, I think we can just go with lix (instead of repo, project, etc.). The import * as X api is a variable declaration. Hence, we don't have to make a decision right now.

samuelstroschein commented 1 month ago

Issues like these https://github.com/markdoc/markdoc/issues/505 support a tree-shaking approach.

TL;DR

samuelstroschein commented 1 week ago

Another reason for tree-shaking are transactions. The lix.api() pattern automatically calls lix.db internally. That doesn't work for scenarios where transactions are required LIXDK-213.

A tree-shakable API enables passing the db to the function which can be a transaction.

image.png

The lix.api() would become very odd

lix.getLeafChange({ db: trx })
samuelstroschein commented 1 week ago

Finding after testing nested tree-shaking:

export * as filter from "./utilities.js"
export { merge } 
import * as sdk from "@lix-js/sdk"

// works
sdk.merge()
// imports all filter apis 
sdk.filter.changeOnlyInSource()

Decision

Go for tree-shaking. We can add lix.* apis easily later on with the tree-shakabel functions but unbundling from lix.* to tree-shaking is harder.