-
Notifications
You must be signed in to change notification settings - Fork 0
frontend
Mile Shi edited this page May 26, 2025
·
1 revision
This guide covers frontend development for the Intelligent IDE VS Code extension, built with TypeScript and the VS Code Extension API.
The frontend is a VS Code extension that provides:
- User authentication and management
- Course management interface
- File upload and organization
- Command palette integration
- Real-time collaboration features
- Custom webview components
- Language: TypeScript 4.8+
- Platform: VS Code Extension API
- Build Tool: esbuild
- Package Manager: npm
- Testing: VS Code Extension Test Suite
Based on the actual frontend structure:
frontend/intelligent-ide/
├── package.json # Extension manifest and configuration
├── tsconfig.json # TypeScript configuration
├── esbuild.js # Build configuration
├── .gitignore # Git ignore rules
├── .vscodeignore # VS Code packaging ignore
├── CHANGELOG.md # Change log
├── README.md # Documentation
└── src/ # Source code
├── extension.ts # Main extension entry point
├── commands/ # Command implementations
│ ├── loginCommand.ts # Login command logic
│ ├── registerCommand.ts # Registration command logic
│ └── updateCommand.ts # Update command logic
├── services/ # Backend API integration
│ └── userService.ts # User-related API calls
├── utils/ # Utility functions
│ └── responseParser.ts # Response data parsing
├── resources/ # Configuration and resources
│ └── configs/
│ └── config.ts # API endpoints and settings
└── test/ # Test files
└── extension.test.ts # Extension tests
- VS Code: Latest version recommended
- Node.js: 16.0.0+ for development
- npm: Package management
-
Navigate to Frontend Directory
cd frontend/intelligent-ide
-
Install Dependencies
npm install
-
Compile TypeScript
npm run compile
-
Launch Extension Development Host
- Open the project in VS Code
- Ensure you're in the
intelligent-ide
directory - Press
F5
to launch Extension Development Host - A new VS Code window opens with the extension loaded
-
Check Extension Activation
- Look for "Congratulations, your extension 'intelligent-ide' is now active!" in the Debug Console
- Window title should show "[Extension Development Host]"
-
Test Commands
- Press
Ctrl+Shift+P
(orCmd+Shift+P
on Mac) - Type "intelligent-ide" to see available commands:
intelligent-ide.login
intelligent-ide.register
intelligent-ide.update
- Press
The extension.ts
file is the main entry point:
// src/extension.ts
import * as vscode from 'vscode';
import { registerLoginCommand } from './commands/loginCommand';
import { registerRegisterCommand } from './commands/registerCommand';
import { registerUpdateCommand } from './commands/updateCommand';
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "intelligent-ide" is now active!');
// Register all commands
registerLoginCommand(context);
registerRegisterCommand(context);
registerUpdateCommand(context);
}
export function deactivate() {
// Cleanup when extension is deactivated
}
Each command follows a consistent pattern:
// src/commands/loginCommand.ts
import * as vscode from 'vscode';
import { UserService } from '../services/userService';
import { parseResponse } from '../utils/responseParser';
export function registerLoginCommand(context: vscode.ExtensionContext) {
const disposable = vscode.commands.registerCommand(
'intelligent-ide.login',
async () => {
try {
// Get user input
const username = await vscode.window.showInputBox({
prompt: 'Enter your username',
placeHolder: 'Username'
});
if (!username) {
return;
}
const password = await vscode.window.showInputBox({
prompt: 'Enter your password',
placeHolder: 'Password',
password: true
});
if (!password) {
return;
}
// Call backend service
const userService = new UserService();
const response = await userService.login(username, password);
const result = parseResponse(response);
if (result.success) {
// Store token securely
await context.globalState.update('accessToken', result.data.access_token);
vscode.window.showInformationMessage('Login successful!');
} else {
vscode.window.showErrorMessage(`Login failed: ${result.message}`);
}
} catch (error) {
vscode.window.showErrorMessage(`Login error: ${error}`);
}
}
);
context.subscriptions.push(disposable);
}
The service layer handles backend communication:
// src/services/userService.ts
import { API_BASE_URL } from '../resources/configs/config';
export interface LoginRequest {
username: string;
password: string;
}
export interface RegisterRequest {
username: string;
email: string;
password: string;
verification_code: string;
role: 'teacher' | 'student';
}
export class UserService {
private baseUrl: string;
constructor() {
this.baseUrl = API_BASE_URL;
}
async login(username: string, password: string): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/user/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
return response.json();
}
async register(registerData: RegisterRequest): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/user/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(registerData)
});
return response.json();
}
async getVerificationCode(email: string): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/user/register/code?email=${email}`, {
method: 'GET'
});
return response.json();
}
async updateUser(updateData: any, token: string): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/user`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Access-Token': token
},
body: JSON.stringify(updateData)
});
return response.json();
}
async getCurrentUser(token: string): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/user`, {
method: 'GET',
headers: {
'Access-Token': token
}
});
return response.json();
}
}
// src/resources/configs/config.ts
export const API_BASE_URL = 'http://localhost:8080';
export const CONFIG = {
api: {
baseUrl: API_BASE_URL,
timeout: 30000,
retries: 3
},
ui: {
defaultTheme: 'dark',
animations: true
},
cache: {
tokenExpiry: 24 * 60 * 60 * 1000, // 24 hours
maxCacheSize: 100
}
};
// src/utils/responseParser.ts
export interface ParsedResponse {
success: boolean;
data?: any;
message?: string;
error?: string;
}
export function parseResponse(response: any): ParsedResponse {
try {
if (response.status === 'success' || response.access_token) {
return {
success: true,
data: response,
message: response.message || 'Operation successful'
};
} else {
return {
success: false,
message: response.message || 'Unknown error occurred',
error: response.error
};
}
} catch (error) {
return {
success: false,
message: 'Failed to parse response',
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
export function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
export function validatePassword(password: string): boolean {
// At least 8 characters, 1 uppercase, 1 lowercase, 1 number
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$/;
return passwordRegex.test(password);
}
// State management using VS Code's global state
export class StateManager {
constructor(private context: vscode.ExtensionContext) {}
async setToken(token: string): Promise<void> {
await this.context.globalState.update('accessToken', token);
}
getToken(): string | undefined {
return this.context.globalState.get('accessToken');
}
async clearToken(): Promise<void> {
await this.context.globalState.update('accessToken', undefined);
}
async setUserData(userData: any): Promise<void> {
await this.context.globalState.update('userData', userData);
}
getUserData(): any {
return this.context.globalState.get('userData');
}
}
// Error handling utilities
export class ErrorHandler {
static handle(error: any, context?: string): void {
let message = 'An unexpected error occurred';
if (error instanceof Error) {
message = error.message;
} else if (typeof error === 'string') {
message = error;
}
if (context) {
message = `${context}: ${message}`;
}
vscode.window.showErrorMessage(message);
console.error('Extension Error:', error);
}
static async handleAsync(operation: () => Promise<void>, context?: string): Promise<void> {
try {
await operation();
} catch (error) {
this.handle(error, context);
}
}
}
// Creating custom webviews for complex UI
export class CourseWebviewProvider implements vscode.WebviewViewProvider {
public static readonly viewType = 'intelligent-ide.courseView';
constructor(private readonly _extensionUri: vscode.Uri) {}
public resolveWebviewView(
webviewView: vscode.WebviewView,
context: vscode.WebviewViewResolveContext,
_token: vscode.CancellationToken,
) {
webviewView.webview.options = {
enableScripts: true,
localResourceRoots: [this._extensionUri]
};
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
// Handle messages from webview
webviewView.webview.onDidReceiveMessage(async (data) => {
switch (data.type) {
case 'loadCourses':
await this.loadCourses(webviewView.webview);
break;
case 'createCourse':
await this.createCourse(data.courseData);
break;
}
});
}
private _getHtmlForWebview(webview: vscode.Webview) {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Course Management</title>
</head>
<body>
<div id="app">
<h2>My Courses</h2>
<div id="course-list"></div>
<button onclick="createCourse()">Create New Course</button>
</div>
<script>
const vscode = acquireVsCodeApi();
function createCourse() {
vscode.postMessage({
type: 'createCourse',
courseData: { name: 'New Course' }
});
}
// Load courses on startup
vscode.postMessage({ type: 'loadCourses' });
</script>
</body>
</html>`;
}
private async loadCourses(webview: vscode.Webview) {
// Load courses from backend and update webview
}
private async createCourse(courseData: any) {
// Create course via backend API
}
}
// Working with VS Code file system
export class FileManager {
static async uploadFile(uri: vscode.Uri, courseId: number): Promise<void> {
try {
const fileData = await vscode.workspace.fs.readFile(uri);
const fileName = path.basename(uri.fsPath);
// Convert to base64 for upload
const base64Data = Buffer.from(fileData).toString('base64');
// Upload to backend
const userService = new UserService();
const token = await this.getToken();
if (token) {
await userService.uploadFile({
fileName,
fileData: base64Data,
courseId
}, token);
vscode.window.showInformationMessage(`File ${fileName} uploaded successfully`);
}
} catch (error) {
ErrorHandler.handle(error, 'File upload');
}
}
private static async getToken(): Promise<string | undefined> {
// Get token from global state
return vscode.workspace.getConfiguration('intelligent-ide').get('token');
}
}
// src/test/extension.test.ts
import * as assert from 'assert';
import * as vscode from 'vscode';
import { activate } from '../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Extension should be present', () => {
assert.ok(vscode.extensions.getExtension('publisher.intelligent-ide'));
});
test('Should activate extension', async () => {
const extension = vscode.extensions.getExtension('publisher.intelligent-ide');
if (extension) {
await extension.activate();
assert.ok(extension.isActive);
}
});
test('Should register commands', async () => {
const commands = await vscode.commands.getCommands();
assert.ok(commands.includes('intelligent-ide.login'));
assert.ok(commands.includes('intelligent-ide.register'));
assert.ok(commands.includes('intelligent-ide.update'));
});
});
# Run extension tests
npm run test
# Compile and run tests
npm run compile && npm run test
// esbuild.js
const esbuild = require('esbuild');
const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');
async function main() {
const ctx = await esbuild.context({
entryPoints: ['src/extension.ts'],
bundle: true,
format: 'cjs',
minify: production,
sourcemap: !production,
sourcesContent: false,
platform: 'node',
outfile: 'out/extension.js',
external: ['vscode'],
logLevel: 'silent',
plugins: [{
name: 'umd2esm',
setup(build) {
build.onResolve({ filter: /^(vscode-.*|estree-walker|d3-color)/ }, args => {
const pathUmdMay = require.resolve(args.path, { paths: [args.resolveDir] })
const pathEsm = pathUmdMay.replace('/umd/', '/esm/')
return { path: pathEsm }
})
},
}],
});
if (watch) {
await ctx.watch();
} else {
await ctx.rebuild();
await ctx.dispose();
}
}
main().catch(e => {
console.error(e);
process.exit(1);
});
// package.json scripts
{
"scripts": {
"compile": "esbuild src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node",
"watch": "npm run compile -- --watch",
"package": "vsce package",
"test": "node ./out/test/runTest.js"
}
}
// package.json (key sections)
{
"name": "intelligent-ide",
"displayName": "Intelligent IDE",
"description": "Educational collaboration platform for VS Code",
"version": "0.0.1",
"engines": {
"vscode": "^1.60.0"
},
"categories": ["Education", "Other"],
"activationEvents": [
"onCommand:intelligent-ide.login"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "intelligent-ide.login",
"title": "Login to Intelligent IDE"
},
{
"command": "intelligent-ide.register",
"title": "Register for Intelligent IDE"
},
{
"command": "intelligent-ide.update",
"title": "Update Profile"
}
],
"views": {
"explorer": [
{
"id": "intelligent-ide.courseView",
"name": "Courses",
"when": "intelligent-ide.authenticated"
}
]
}
}
}
- Separation of Concerns: Keep commands, services, and utilities separate
- Error Handling: Implement comprehensive error handling
- User Feedback: Provide clear user feedback for all operations
- Security: Store sensitive data securely using VS Code's state management
- Lazy Loading: Load resources only when needed
- Caching: Cache frequently accessed data
- Async Operations: Use async/await for non-blocking operations
- Resource Cleanup: Properly dispose of resources
- Hot Reload: Use watch mode during development
- Debugging: Utilize VS Code's debugging features
- Testing: Write tests for all major functionality
- Documentation: Document all public APIs and complex logic
This frontend development guide provides comprehensive information for contributing to and extending the Intelligent IDE VS Code extension.
🏠 Home
- Getting Started
- Installation Guide
- Authentication
- Course Management
- Collaborative Editing
- Assignments
- Notebook Features
- File Management
- Troubleshooting
- Setup & Development
- Architecture Overview
- Backend Development
- Frontend Development
- API Reference
- Contributing
- Deployment