Skip to content

Commit

Permalink
feat(account-kit): separate bundled export for non-react environments (
Browse files Browse the repository at this point in the history
  • Loading branch information
holic authored Apr 16, 2024
1 parent cafb1a0 commit cc3d95e
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 64 deletions.
13 changes: 7 additions & 6 deletions packages/account-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"license": "MIT",
"type": "module",
"exports": {
".": "./dist/index.js",
"./internal": "./dist/internal.js",
"./bundle": "./dist/bundle.js"
".": "./dist/tsup/index.js",
"./internal": "./dist/tsup/internal.js",
"./bundle": "./dist/vite/bundle.js"
},
"typesVersions": {
"*": {
Expand All @@ -28,14 +28,14 @@
}
},
"bin": {
"local-bundler": "./dist/bin/local-bundler.js"
"local-bundler": "./dist/tsup/bin/local-bundler.js"
},
"scripts": {
"build": "pnpm run build:js",
"build:js": "tsup",
"build:js": "tsup & vite build",
"clean": "pnpm run clean:js",
"clean:js": "rimraf dist",
"dev": "tsup --watch",
"dev": "tsup --watch & vite build --watch",
"local-bundler": "pnpx tsx cli/local-bundler.ts",
"test": "tsc --noEmit && vitest",
"test:ci": "tsc --noEmit && vitest --run"
Expand Down Expand Up @@ -78,6 +78,7 @@
"postcss": "^8.4.23",
"tailwindcss": "^3.4.3",
"tsup": "^6.7.0",
"vite": "^4.3.6",
"vitest": "0.34.6"
},
"peerDependencies": {
Expand Down
25 changes: 25 additions & 0 deletions packages/account-kit/src/bundle/SyncStore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useAccountModal } from "../useAccountModal";
import { useAppAccountClient } from "../useAppAccountClient";
import { useEffect } from "react";
import { Store } from "./store";

export type Props = {
store: Store;
};

export function SyncStore({ store }: Props) {
const { accountModalOpen, openAccountModal, closeAccountModal, toggleAccountModal } = useAccountModal();
const appAccountClient = useAppAccountClient();

useEffect(() => {
store.setState({
accountModalOpen,
openAccountModal,
closeAccountModal,
toggleAccountModal,
appAccountClient,
});
}, [store, accountModalOpen, appAccountClient, closeAccountModal, openAccountModal, toggleAccountModal]);

return <></>;
}
28 changes: 19 additions & 9 deletions packages/account-kit/src/bundle/mount.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import "@rainbow-me/rainbowkit/styles.css";
import type { Config as WagmiConfig } from "wagmi";
import type { Config as AccountKitConfig } from "../AccountKitProvider";
import { Store, store } from "./store";

export type MountOptions = {
rootElementId?: string;
wagmiConfig: WagmiConfig;
accountKitConfig: AccountKitConfig;
};

export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountKitConfig }: MountOptions): () => void {
export type MountResult = {
unmount: () => void;
store: Store;
};

export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountKitConfig }: MountOptions): MountResult {
if (typeof window === "undefined") {
console.warn("MUD Account Kit should only be used in browser bundles.");
return () => {};
throw new Error("MUD Account Kit should only be used in browser bundles.");
}

if (document.getElementById(rootElementId)) {
console.warn("MUD Account Kit is already mounted.");
return () => {};
throw new Error("MUD Account Kit is already mounted.");
}

async function setup() {
Expand All @@ -26,6 +31,7 @@ export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountK
const { QueryClientProvider, QueryClient } = await import("@tanstack/react-query");
const { RainbowKitProvider, lightTheme, midnightTheme } = await import("@rainbow-me/rainbowkit");
const { AccountKitProvider } = await import("../AccountKitProvider");
const { SyncStore } = await import("./SyncStore");

const queryClient = new QueryClient();

Expand All @@ -34,6 +40,7 @@ export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountK
// Create a new stacking context
// https://web.dev/learn/css/z-index/#stacking-context
rootElement.style.willChange = "contents";
document.body.appendChild(rootElement);

const root = ReactDOM.createRoot(rootElement);
root.render(
Expand All @@ -50,15 +57,15 @@ export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountK
darkMode: midnightTheme({ borderRadius: "none" }),
}}
>
<AccountKitProvider config={accountKitConfig} />
<AccountKitProvider config={accountKitConfig}>
<SyncStore store={store} />
</AccountKitProvider>
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
);

document.body.appendChild(rootElement);

return () => {
root.unmount();
rootElement.remove();
Expand All @@ -69,5 +76,8 @@ export function mount({ rootElementId = "mud-account-kit", wagmiConfig, accountK
console.error("Failed to mount MUD Account Kit.", error);
});

return () => setupPromise.then((unmount) => unmount?.());
return {
unmount: () => setupPromise.then((unmount) => unmount?.()),
store,
};
}
21 changes: 21 additions & 0 deletions packages/account-kit/src/bundle/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { StoreApi, createStore } from "zustand/vanilla";
import { AppAccountClient } from "../common";

export type State = {
accountModalOpen: undefined | boolean;
openAccountModal: undefined | (() => void);
closeAccountModal: undefined | (() => void);
toggleAccountModal: undefined | ((open: boolean) => void);
// TODO: downcast this to a plain wallet client to support non-smart account use cases later
appAccountClient: AppAccountClient | undefined;
};

export type Store = StoreApi<State>;

export const store = createStore<State>(() => ({
accountModalOpen: undefined,
openAccountModal: undefined,
closeAccountModal: undefined,
toggleAccountModal: undefined,
appAccountClient: undefined,
}));
3 changes: 2 additions & 1 deletion packages/account-kit/src/exports/bundle.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { mount } from "../bundle/mount";
export { mount, type MountOptions, type MountResult } from "../bundle/mount";
export { type Store } from "../bundle/store";
1 change: 0 additions & 1 deletion packages/account-kit/src/exports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@

export { AccountButton } from "../AccountButton";
export { useAccountModal } from "../useAccountModal";
export { useAccountRequirements } from "../useAccountRequirements";
export { AccountKitProvider } from "../AccountKitProvider";
export { useAppAccountClient } from "../useAppAccountClient";
10 changes: 7 additions & 3 deletions packages/account-kit/src/ui/Shadow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ export const Shadow = forwardRef<HTMLSpanElement, Props>(function Shadow({ child
const container = containerRef.current;
if (!container) return;

const root = container.attachShadow({ mode: "open", delegatesFocus: true });
root.adoptedStyleSheets = [sheet];
setShadowRoot(root);
if (container.shadowRoot) {
setShadowRoot(container.shadowRoot);
} else {
const root = container.attachShadow({ mode: "open", delegatesFocus: true });
root.adoptedStyleSheets = [sheet];
setShadowRoot(root);
}
}, []);

return (
Expand Down
2 changes: 0 additions & 2 deletions packages/account-kit/src/useAppAccountClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ export function useAppAccountClient(): AppAccountClient | undefined {
throw new Error(`No ERC4337 bundler URL found for chain ${chain.name} (id: ${chain.id})`);
}

console.log("Bundler:", chain.erc4337BundlerUrl.http);

const pimlicoBundlerClient = createPimlicoBundlerClient({
chain: publicClient.chain,
transport: http(chain.erc4337BundlerUrl.http),
Expand Down
1 change: 0 additions & 1 deletion packages/account-kit/src/useOnboardingSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ const store = createStore<{ readonly step: OnboardingStep | null }>(() => ({ ste
export function useOnboardingSteps() {
const initialStep = useStore(store, (state) => state.step);
const { requirements } = useAccountRequirements();
console.log("requirements", requirements);

const setStep = useCallback((step: OnboardingStep): void => {
store.setState({ step });
Expand Down
58 changes: 18 additions & 40 deletions packages/account-kit/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
import { defineConfig } from "tsup";
import packageJson from "./package.json";

export default defineConfig([
{
entry: {
index: "src/exports/index.ts",
internal: "src/exports/internal.ts",
"bin/local-bundler": "cli/local-bundler.ts",
},
target: "esnext",
format: ["esm"],
dts: false, // TODO: figure out how to reenable
sourcemap: true,
clean: true,
minify: true,
// Because we're injecting CSS via shadow DOM, we'll disable style injection and load CSS as a base64 string.
// TODO: figure out how to do this conditionally for only specific imports?
injectStyle: false,
loader: {
".css": "text",
},
export default defineConfig({
outDir: "dist/tsup",
entry: {
index: "src/exports/index.ts",
internal: "src/exports/internal.ts",
"bin/local-bundler": "cli/local-bundler.ts",
},
{
entry: {
bundle: "src/exports/bundle.ts",
},
target: "esnext",
format: ["esm"],
dts: false, // TODO: figure out how to reenable
sourcemap: true,
clean: true,
minify: true,
// Because we're injecting CSS via shadow DOM, we'll disable style injection and load CSS as a base64 string.
// TODO: figure out how to do this conditionally for only specific imports?
injectStyle: false,
loader: {
".css": "text",
},
// don't code split otherwise dep imports in bundle seem to break
splitting: false,
noExternal: Object.keys(packageJson.dependencies),
target: "esnext",
format: ["esm"],
dts: false, // TODO: figure out how to reenable
sourcemap: true,
clean: true,
minify: true,
// Because we're injecting CSS via shadow DOM, we'll disable style injection and load CSS as a base64 string.
// TODO: figure out how to do this conditionally for only specific imports?
injectStyle: false,
loader: {
".css": "text",
},
]);
});
15 changes: 15 additions & 0 deletions packages/account-kit/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from "vite";

export default defineConfig({
build: {
outDir: "dist/vite",
sourcemap: true,
lib: {
entry: "src/exports/bundle.ts",
name: "MUD Account Kit",
fileName: "bundle",
// TODO: more formats?
formats: ["es"],
},
},
});
5 changes: 4 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cc3d95e

Please sign in to comment.