Bundler Internals
All Tevm bundler plugins share a unified core (@tevm/base-bundler). Each plugin adapts the same pipeline to its build tool.
1. Import Detection & Resolution
For each .sol import the bundler:
- Parses the import statement and converts relative paths to absolute paths.
- Applies remappings from tsconfig paths, foundry remappings, and
tevm.config.json. - Resolves node_modules for npm packages.
- Special-cases
.s.solfor bytecode inclusion.
User Import → Node.js Resolution + Foundry Remappings → Absolute File Path2. Compilation
- Builds a dependency graph of imported Solidity files.
- Passes the graph to solc.
.s.solemits ABI + bytecode;.solemits ABI only.- Extracts metadata, NatSpec, and optionally the AST.
3. Code Generation
- Emits a TypeScript (or JavaScript) module exporting a Tevm Contract instance.
- Generates types for methods, events, and errors.
- Maps Solidity types to TS (uint256 → bigint, address → string, etc.).
- Preserves NatSpec as JSDoc for editor hovers.
- Adds
.read/.writemethod interfaces.
4. Caching
- Stores compiled artifacts in
.tevm/. - Hashes file content for invalidation.
- Stores artifacts (ABI, bytecode) separately from generated code.
- Invalidates only affected entries when deps or compiler settings change.
5. LSP & TS Plugin Integration
@tevm/ts-pluginhooks into the TypeScript compiler.- Provides type info for
.solimports from bundler outputs. - Powers auto-completion, go-to-definition, hover docs, and type checking.
Internal Implementation Details
Module Factory
function moduleFactory(entry, source, remappings, libs) {
const modules = new Map()
const queue = [{ path: entry, source }]
while (queue.length > 0) {
const { path, source } = queue.shift()
if (modules.has(path)) continue
const imports = resolveImports(path, source, remappings, libs)
modules.set(path, { id: path, source, imports: imports.map((i) => i.path) })
for (const imp of imports) {
if (!modules.has(imp.path)) {
queue.push({ path: imp.path, source: readFile(imp.path) })
}
}
}
return modules
}Solidity Compiler Integration
function compile(sources, settings) {
const input = {
language: 'Solidity',
sources: Object.fromEntries(
Array.from(sources.entries()).map(([path, { content }]) => [path, { content }]),
),
settings: {
outputSelection: {
'*': { '*': ['abi', 'evm.bytecode', 'evm.deployedBytecode', 'metadata', 'userdoc', 'devdoc'] },
},
...settings,
},
}
return solc.compile(JSON.stringify(input), { import: resolveImport })
}Contract Instance Generation
import { createContract } from 'tevm/contract'
export const MyContract = createContract({
abi: [...],
bytecode: '0x...', // only for .s.sol
deployedBytecode: '0x...', // only for .s.sol
})
