You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/tree-shakeability.md
+75-2Lines changed: 75 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -150,8 +150,81 @@ Split into `@eth-optimism/actions-sdk-core`, `@eth-optimism/actions-sdk-aave`, e
150
150
1.**No config shape change** — `ActionsConfig` remains the same. The developer's mental model doesn't change.
151
151
2.**Leverages existing patterns** — The registry/factory pattern already decouples provider creation from the `Actions` class. Making `HostedProviderFactory.create()` async and using `await import()` inside each factory is a natural extension.
152
152
3.**Well-contained breaking change** — `createActions` becoming async (`Promise<Actions>`) is a single call site change for consumers. Most initialization code is already async (wallet setup, chain connections).
153
-
4.**Solves both problems completely** — Optional peer deps fix install-time warnings/bloat. Dynamic imports fix bundle-time bloat by ensuring bundlers only include provider code that's actually imported at runtime.
154
-
5.**Incremental adoption** — Can be rolled out in stages (peer deps first, then dynamic imports) if needed.
153
+
4.**Incremental adoption** — Can be rolled out in stages (peer deps first, then dynamic imports) if needed.
154
+
155
+
### Tradeoffs & DX Impact
156
+
157
+
This approach introduces a meaningful change to the consumer install experience. It's important to understand what changes and why.
158
+
159
+
#### Fundamental constraint: config cannot control installs
160
+
161
+
npm/pnpm dependency resolution happens at `npm install` time — before any code runs. The SDK's `ActionsConfig` is a runtime concept. There is no mechanism in the npm ecosystem for a package to say "if the consumer configures Morpho, install `@morpho-org/*` automatically." The only options are:
162
+
163
+
-**Hard `dependencies`**: always installed for every consumer (current behavior for Aave/Morpho/ethers)
164
+
-**`peerDependencies`**: consumer must install manually; npm 7+ auto-installs non-optional peers, pnpm does not
165
+
-**`peerDependencies` + `optional: true`**: never auto-installed, no warnings if missing
166
+
167
+
#### Before vs After: what a Turnkey + Morpho developer does
Aave, ethers v5, and Morpho packages auto-install as hard `dependencies` — even though this developer doesn't use Aave. Turnkey packages are peer deps and must be installed manually (same as before).
All protocol and wallet dependencies are now optional peers. The consumer must explicitly install every provider's dependencies. Aave and ethers are no longer installed. However, Morpho packages (previously auto-installed) must now be installed manually too.
191
+
192
+
```ts
193
+
const actions =awaitcreateActions({ /* ... */ }) // now async
194
+
```
195
+
196
+
If a developer forgets to install a required dependency, they get a clear error at runtime:
#### Bundle-time: where dynamic imports help and where they don't
205
+
206
+
Dynamic `import()` behaves differently depending on the runtime environment:
207
+
208
+
**Node.js (no bundler):** Dynamic imports work as expected. Only the configured providers are loaded at runtime. If Aave packages aren't installed and the config doesn't request Aave, no error occurs — the `import()` is never called.
209
+
210
+
**Frontend bundler (esbuild, webpack, Vite/Rollup):** The bundler resolves dynamic import targets at **build time**, not runtime. This means:
211
+
212
+
- If `@morpho-org/*` is installed, the bundler follows `await import('./MorphoLendProvider.js')` → `MorphoLendProvider.js` → `@morpho-org/blue-sdk` and includes it in the output (either inlined or as a separate chunk depending on code-splitting support).
213
+
- If `@aave/*` is NOT installed, the bundler cannot resolve the Aave provider's transitive deps and will either error or leave the import as a runtime expression.
214
+
215
+
**The real frontend bundle win is indirect**: because unused deps aren't in `node_modules`, the bundler can't include them. The dynamic import pattern makes this safe by deferring the resolution so that missing packages cause a runtime error (with a helpful message) rather than a build-time crash across all entry points.
216
+
217
+
#### Summary of tradeoffs
218
+
219
+
|| Before | After |
220
+
|---|---|---|
221
+
|**Install command**| Only wallet peer deps manually installed; protocol deps auto-install | All provider deps manually installed |
222
+
|**Unused deps installed**| Yes (Aave + ethers for Morpho-only users) | No |
223
+
|**Peer dep warnings**| Yes (all 10 wallet packages) | No (all optional) |
0 commit comments