-
Notifications
You must be signed in to change notification settings - Fork 14
Description
Problem
When using @chainlink/ccip-sdk@0.95.0 in a browser-based application with Vite, the SDK causes build failures because it bundles all blockchain dependencies (Solana, Sui, Aptos, TON) even when only EVM functionality is needed.
Error Messages
ERROR: No matching export in "@coral-xyz/anchor/dist/browser/index.js" for import "eventDiscriminator"
ERROR: No matching export for "BorshAccountsCoder"
ERROR: No matching export for "AnchorProvider"
Root Cause
The main entry point (@chainlink/ccip-sdk) imports all chain implementations in dist/index.js, which includes:
@coral-xyz/anchor(Solana) - Not browser-compatible@mysten/sui(Sui)@aptos-labs/ts-sdk(Aptos)@ton/core(TON)
These dependencies are required in package.json even though most applications only use EVM chains.
Workaround Implementation
We've implemented a multi-layered workaround until the SDK provides proper modular exports:
1. Vite Plugin to Stub Non-EVM Modules
In vite.config.ts, we created a plugin that intercepts imports from non-EVM chains and replaces them with empty stubs:
function ccipSdkStubPlugin(): Plugin {
const stubCode = `
// Mock class that can be instantiated
class MockClass {
constructor(...args) {}
}
// Mock function that returns a mock
const mockFunction = (...args) => ({});
// @coral-xyz/anchor exports - all as MockClass
export const AnchorProvider = MockClass;
export const BorshCoder = MockClass;
export const BorshAccountsCoder = MockClass;
// ... all other exports
export default {};
`;
const shouldStub = (id: string): boolean => {
const normalizedId = id.replace(/\\/g, '/');
return (
normalizedId.includes('@chainlink/ccip-sdk/dist/solana') ||
normalizedId.includes('@chainlink/ccip-sdk/dist/sui') ||
normalizedId.includes('@chainlink/ccip-sdk/dist/aptos') ||
normalizedId.includes('@chainlink/ccip-sdk/dist/ton') ||
normalizedId.includes('@coral-xyz/anchor')
);
};
return {
name: 'ccip-sdk-stub',
enforce: 'pre',
resolveId(id, importer) {
if (shouldStub(id)) {
return '\0ccip-sdk-stub';
}
if (importer && shouldStub(importer)) {
return '\0ccip-sdk-stub';
}
return null;
},
load(id) {
if (id === '\0ccip-sdk-stub') {
return stubCode;
}
return null;
},
};
}2. ESBuild Configuration
Added esbuild options to handle optimization phase:
optimizeDeps: {
exclude: [
'@chainlink/ccip-sdk/dist/solana',
'@chainlink/ccip-sdk/dist/sui',
'@chainlink/ccip-sdk/dist/aptos',
'@chainlink/ccip-sdk/dist/ton',
'@coral-xyz/anchor',
],
esbuildOptions: {
plugins: [
{
name: 'ignore-non-evm-chains',
setup(build) {
build.onResolve({ filter: /@coral-xyz\/anchor/ }, () => ({
path: 'data:text/javascript,export default {};',
external: false,
}));
build.onResolve({
filter: /@chainlink\/ccip-sdk\/dist\/(solana|sui|aptos|ton)/
}, () => ({
path: 'data:text/javascript,export default {};',
external: false,
}));
},
},
],
},
}Future Improvements
This is a temporary workaround. Ideally, the SDK should:
-
Make non-EVM dependencies optional in
package.json:{ "optionalDependencies": { "@coral-xyz/anchor": "^0.29.0", "@mysten/sui": "^1.45.2", "@aptos-labs/ts-sdk": "^5.2.1", "@ton/core": "0.63.0" } } -
Provide separate entry points per chain:
{ "exports": { "./evm": "./dist/evm.js", "./solana": "./dist/solana.js", "./sui": "./dist/sui.js" } } -
Use conditional/dynamic imports for non-EVM chains