Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions e2e/examples.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,7 @@
"serveCmd": "preview",
"profile": "standard",
"mountPath": "/",
"status": "broken",
"brokenReason": "Dynamic SDK reads a bare `process` global (nextTick/versions/emit) and imports `buffer/index.js`, so it needs Node shims. vite-plugin-node-polyfills declares Vite 8 support but is broken under its rolldown resolver: it aliases its own shims by bare specifier, and its exports map still has legacy trailing-slash keys pointing at files, which rolldown rejects (\"Expecting folder to folder mapping\"). Fails on 0.26.0 and 0.28.0 alike, in build and in dep pre-bundling. Blocked on upstream davidmyersdev/vite-plugin-node-polyfills#158, #161 and #154. The @dynamic-labs v5 upgrade itself is fine — it type-checks and bundles."
"status": "active"
},
{
"name": "nuxt",
Expand Down
5 changes: 3 additions & 2 deletions e2e/tests/profiles/widget-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { expect, test, waitForTokens } from '../fixtures/base.fixture.js'
* Widget smoke profile — covers standard (widget at /) and routed (widget at custom path).
* mountPath is read from project metadata so the same spec handles both profiles.
*
* Standard (13): vite, connectkit, privy, privy-ethers, rainbowkit, reown, svelte,
* zustand-widget-config, vue, nextjs, nextjs15, remix, react-router
* Standard (14): vite, connectkit, privy, privy-ethers, rainbowkit, reown, svelte,
* zustand-widget-config, vue, nextjs, nextjs15, remix, react-router,
* dynamic
* Routed (1): tanstack-router (mountPath: /widget)
*/

Expand Down
4 changes: 2 additions & 2 deletions examples/dynamic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"react": "^19.2.8",
"react-dom": "^19.2.8",
"viem": ">=2.52.0",
"vite-plugin-env-compatible": "^2.0.1",
"wagmi": "^3.7.6"
},
"devDependencies": {
Expand All @@ -45,6 +44,7 @@
"@vitejs/plugin-react": "^6.0.5",
"globals": "^17.11.0",
"typescript": "^7.0.2",
"vite": "^8.2.1"
"vite": "^8.2.1",
"vite-plugin-node-polyfills": "^0.26.0"
}
}
18 changes: 10 additions & 8 deletions examples/dynamic/src/components/WalletHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import { Box, Typography } from '@mui/material'
export function WalletHeader() {
return (
<Box
p={2}
mb={2}
display="flex"
justifyContent="space-between"
alignItems="center"
borderBottom="1px solid #EEE"
sx={{
p: 2,
mb: 2,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
borderBottom: '1px solid #EEE',
}}
>
<Typography px={2} fontWeight={600} fontSize={24}>
<Typography sx={{ px: 2, fontWeight: 600, fontSize: 24 }}>
Dynamic + LI.FI widget Example
</Typography>
<Box display="flex" alignItems="center">
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<DynamicWidget />
</Box>
</Box>
Expand Down
89 changes: 86 additions & 3 deletions examples/dynamic/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,93 @@
import { createRequire } from 'node:module'
import { dirname, join, resolve } from 'node:path'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
import EnvCompatible from 'vite-plugin-env-compatible'
import { defineConfig, type Plugin } from 'vite'
import { nodePolyfills } from 'vite-plugin-node-polyfills'

// The Dynamic SDK reads a bare `process` global (nextTick/versions/emit) and its own
// polyfills.js imports `buffer/index.js`, so it needs real Node shims — build-time
// `process.env.*` substitution is not enough.
//
// nodePolyfills() supplies those shims, but it points at them by bare specifier, and
// its exports map still carries legacy trailing-slash keys that resolve to files.
// Rolldown (Vite 8) rejects that with "Expecting folder to folder mapping", which
// breaks both `vite build` and dev dependency pre-bundling. 0.28.0 ships an identical
// exports map and fails the same way, so bumping the plugin does not help — the
// upstream fixes are open but unreleased (davidmyersdev/vite-plugin-node-polyfills#161
// and #154).
//
// So we resolve the shims to their real files, which keeps rolldown out of the exports
// map. Two places need it, because pre-bundling runs its own resolver:
// - the module graph, via resolveId (also covers subpaths like `buffer/index.js`)
// - the plugin's own returned config, patched before Vite merges it, which is where
// the pre-bundle alias maps and injected banner come from
// Both become deletable once upstream ships.
const require = createRequire(import.meta.url)
const pkgRoot = resolve(
dirname(require.resolve('vite-plugin-node-polyfills')),
'..'
)
const SHIM_PREFIX = 'vite-plugin-node-polyfills/shims/'
const SHIM_RE =
/^(?:node:)?(?:vite-plugin-node-polyfills\/shims\/)?(buffer|global|process)(?:\/.*)?$/
const QUOTED_SHIM_RE =
/(['"])vite-plugin-node-polyfills\/shims\/(buffer|global|process)\1/g
// Alias values point at the shim *directory*: aliases substitute by prefix, so a
// directory keeps both `buffer` and `buffer/index.js` resolvable. Import specifiers
// (the injected banner) get the file itself.
const shimDir = (name: string) => join(pkgRoot, 'shims', name, 'dist')
const shimPath = (name: string) => join(shimDir(name), 'index.js')

/** Rewrite every bare shim specifier in a value tree to an absolute path. */
function absolutizeShims<T>(value: T): T {
if (typeof value === 'string') {
const exact = value.startsWith(SHIM_PREFIX)
? shimDir(value.slice(SHIM_PREFIX.length))
: value.replace(
QUOTED_SHIM_RE,
(_, quote: string, name: string) =>
`${quote}${shimPath(name)}${quote}`
)
return exact as unknown as T
}
if (Array.isArray(value)) return value.map(absolutizeShims) as unknown as T
if (value && typeof value === 'object') {
for (const [key, inner] of Object.entries(value)) {
;(value as Record<string, unknown>)[key] = absolutizeShims(inner)
}
}
return value
}

/** nodePolyfills() with every bare shim reference resolved to a real file. */
function nodePolyfillsResolved(): Plugin[] {
const plugins = [nodePolyfills()].flat() as Plugin[]
for (const plugin of plugins) {
const original = plugin.config
if (typeof original !== 'function') continue
plugin.config = async function config(
this: ThisParameterType<typeof original>,
...args: Parameters<typeof original>
) {
return absolutizeShims(await original.apply(this, args))
}
}
return [
{
name: 'resolve-node-polyfill-shims',
enforce: 'pre',
resolveId(id) {
const match = SHIM_RE.exec(id)
return match ? shimPath(match[1]) : null
},
},
...plugins,
]
}

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), EnvCompatible()],
plugins: [react(), nodePolyfillsResolved()],
server: {
port: 3000,
open: true,
Expand Down
33 changes: 8 additions & 25 deletions pnpm-lock.yaml

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