Skip to content

Finally got a template that works BEN-783 #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2025
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
121 changes: 29 additions & 92 deletions lib/e2b.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,107 +9,44 @@ if (!E2B_API_KEY) {
}

export async function createSandbox({ files }: { files: z.infer<typeof benchifyFileSchema> }) {
const sandbox = await Sandbox.create('vite-template', { apiKey: E2B_API_KEY });

// Debug: Log template files before writing anything
try {
console.log("TEMPLATE VERIFICATION:");
const { stdout: templateFiles } = await sandbox.commands.run('ls -la /app', { cwd: '/app' });
console.log("Template files in /app:", templateFiles);

const { stdout: templatePkgJson } = await sandbox.commands.run('cat /app/package.json', { cwd: '/app' });
console.log("Template package.json:", templatePkgJson);
} catch (error) {
console.error("Error checking template:", error);
// Create sandbox from the improved template
const sandbox = await Sandbox.create('vite-support', { apiKey: E2B_API_KEY });
console.log(`Sandbox created: ${sandbox.sandboxId}`);

// Check if the user provided CSS files with old Tailwind syntax
const cssFiles = files.filter(file => file.path.endsWith('.css'));
for (const cssFile of cssFiles) {
// If the file contains @tailwind directives, replace with the new v4 syntax
if (cssFile.content.includes('@tailwind')) {
console.log(`Updating Tailwind v4 syntax in ${cssFile.path}`);
cssFile.content = '@import "tailwindcss";';
}
}

// Find AI-generated package.json to extract dependencies
const aiPackageJsonFile = files.find(file => file.path === 'package.json');

// Filter out package.json from files to write (we'll handle it separately)
const filesToWrite = files
.filter(file => file.path !== 'package.json')
.map(file => ({
path: `/app/${file.path}`,
data: file.content
}));

// Write all files to the sandbox EXCEPT package.json
await sandbox.files.write(filesToWrite);

console.log("sandbox created", sandbox.sandboxId);

// Debug: Verify files after writing
try {
console.log("AFTER WRITING FILES:");
const { stdout: rootContents } = await sandbox.commands.run('ls -la /app', { cwd: '/app' });
console.log("Files in /app:", rootContents);

const { stdout: packageJson } = await sandbox.commands.run('cat /app/package.json', { cwd: '/app' });
console.log("Current package.json:", packageJson);

const { stdout: scriptsList } = await sandbox.commands.run('npm run', { cwd: '/app' });
console.log("Available npm scripts:", scriptsList);
} catch (error) {
console.error("Error in debug commands:", error);
// Check if the user provided a postcss.config.js and if it needs to be updated for Tailwind v4
const postcssFile = files.find(file => file.path === 'postcss.config.js');
if (postcssFile && postcssFile.content.includes('tailwindcss')) {
// Fix postcss config to use @tailwindcss/postcss
const fixedContent = postcssFile.content.replace(/['"]tailwindcss['"]/, '"@tailwindcss/postcss"');
// Update the file with fixed content
postcssFile.content = fixedContent;
}

// Process dependencies if AI provided a package.json
if (aiPackageJsonFile) {
try {
const aiPackageJson = JSON.parse(aiPackageJsonFile.content);
const dependencies = aiPackageJson.dependencies || {};
const devDependencies = aiPackageJson.devDependencies || {};
// Write files directly to the working directory (/app)
const filesToWrite = files.map(file => ({
path: `/app/${file.path}`,
data: file.content
}));

// Filter out pre-installed dependencies
const preInstalled = [
'react', 'react-dom', '@tailwindcss/vite', 'tailwindcss',
'@types/react', '@types/react-dom', '@vitejs/plugin-react',
'typescript', 'vite', 'postcss', 'autoprefixer'
];

// Get new deps that need to be installed
const newDeps = Object.keys(dependencies).filter(dep => !preInstalled.includes(dep));
const newDevDeps = Object.keys(devDependencies).filter(dep => !preInstalled.includes(dep));

// Install only new dependencies if any exist
if (newDeps.length > 0) {
console.log("Installing new dependencies:", newDeps.join(", "));
await sandbox.commands.run(`cd /app && npm install --legacy-peer-deps ${newDeps.join(' ')}`);
}

if (newDevDeps.length > 0) {
console.log("Installing new dev dependencies:", newDevDeps.join(", "));
await sandbox.commands.run(`cd /app && npm install --legacy-peer-deps --save-dev ${newDevDeps.join(' ')}`);
}
} catch (error) {
console.error("Error parsing package.json:", error);
}
}

// Fix permissions with sudo before starting
try {
await sandbox.commands.run('sudo rm -rf /app/node_modules/.vite', { cwd: '/app' });
await sandbox.commands.run('sudo mkdir -p /app/node_modules/.vite', { cwd: '/app' });
await sandbox.commands.run('sudo chmod -R 777 /app/node_modules/.vite', { cwd: '/app' });
} catch (error) {
console.error("Error fixing permissions:", error);
}
await sandbox.files.write(filesToWrite);

// Run the Vite app
try {
await sandbox.commands.run('npm run dev -- --host', {
cwd: '/app',
timeoutMs: 0,
});
} catch (error) {
console.error("Error running Vite:", error);
}
const previewUrl = `https://${sandbox.getHost(5173)}`;
console.log('Preview URL: ', previewUrl);

return {
sbxId: sandbox.sandboxId,
template: 'vite-template',
url: `https://${sandbox.getHost(5173)}`
template: 'vite-support',
url: previewUrl
};
}

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev": "next dev --port 5173",
"build": "next build",
"start": "next start",
"lint": "next lint"
Expand Down Expand Up @@ -43,4 +43,4 @@
"tw-animate-css": "^1.2.9",
"typescript": "^5"
}
}
}
21 changes: 21 additions & 0 deletions templates/vite-support/compile_page.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# This script runs during building the sandbox template
# and makes sure the Vite app is (1) running and (2) accessible
function ping_server() {
counter=0
response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:5173")
while [[ ${response} -ne 200 ]]; do
let counter++
if (( counter % 20 == 0 )); then
echo "Waiting for Vite dev server to start..."
sleep 0.1
fi

response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:5173")
done
}

# Start the Vite dev server
ping_server &
cd /home/user && npm run dev
29 changes: 29 additions & 0 deletions templates/vite-support/e2b.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Simpler Dockerfile
FROM node:21-slim

# Install necessary tools
RUN apt-get update && apt-get install -y bash curl && rm -rf /var/lib/apt/lists/*

# Set working directory directly
WORKDIR /app

# Set up Vite with React + TypeScript
RUN npm create vite@latest . -- --template react-ts

# Install all dependencies
RUN npm install

# Install Tailwind CSS with Vite plugin (v4 approach)
RUN npm install -D tailwindcss @tailwindcss/vite

# Update vite.config.ts to use the Tailwind plugin and include allowedHosts
RUN echo 'import { defineConfig } from "vite"\nimport react from "@vitejs/plugin-react"\nimport tailwindcss from "@tailwindcss/vite"\n\nexport default defineConfig({\n plugins: [\n react(),\n tailwindcss(),\n ],\n server: {\n host: true,\n allowedHosts: [".e2b.app"],\n },\n})' > vite.config.ts

# Configure Tailwind CSS (simplified import for v4)
RUN echo '@import "tailwindcss";' > ./src/index.css

# Make directory writable (this is crucial)
RUN chmod -R 777 /app

# Set proper entrypoint
ENTRYPOINT ["bash", "-c", "cd /app && npm run dev -- --host --port 5173"]
18 changes: 18 additions & 0 deletions templates/vite-support/e2b.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This is a config for E2B sandbox template.
# You can use template ID (5harom00c0l7yk46ewmn) or template name (vite-support) to create a sandbox:

# Python SDK
# from e2b import Sandbox, AsyncSandbox
# sandbox = Sandbox("vite-support") # Sync sandbox
# sandbox = await AsyncSandbox.create("vite-support") # Async sandbox

# JS SDK
# import { Sandbox } from 'e2b'
# const sandbox = await Sandbox.create('vite-support')

team_id = "35f2ed91-a6af-4e6c-a693-9e9e244fcdbd"
memory_mb = 1_024
start_cmd = "cd /app && npm run dev -- --host --port 5173"
dockerfile = "e2b.Dockerfile"
template_name = "vite-support"
template_id = "5harom00c0l7yk46ewmn"
11 changes: 11 additions & 0 deletions templates/vite-support/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
host: true,
allowedHosts: [".e2b.app"],
},
});
56 changes: 0 additions & 56 deletions templates/vite-template/e2b.Dockerfile

This file was deleted.

16 changes: 0 additions & 16 deletions templates/vite-template/e2b.toml

This file was deleted.

24 changes: 0 additions & 24 deletions templates/vite-template/template/.gitignore

This file was deleted.

54 changes: 0 additions & 54 deletions templates/vite-template/template/README.md

This file was deleted.

Loading