Refactoring With React + TS + Vite
Project Overview
In this article, we will guide you through the process of modernizing a portfolio website that currently uses vanilla JavaScript with React integrated directly into the JS files using in-browser Babel transpilation (no build system). The project has separate French and English versions (indexFR.html/js and indexEN.html/js) and uses class components with direct ReactDOM.render() calls.
Current Project Structure
The current project structure is as follows:
Project Root/
βββ babel.min.js // In-browser Babel transpilation
βββ react.production.min.js // React library
βββ react-dom.production.min.js // ReactDOM library
βββ indexFR.html // French HTML entry
βββ indexFR.js // French JS with React components
βββ indexEN.html // English HTML entry
βββ indexEN.js // English JS with React components
βββ style.css // Global CSS
βββ icofont/ // Icon fonts
βββ images/ // Image assets
β βββ profil.jpg
β βββ activiter/
β βββ Csharp/
β βββ HCJ/
β βββ java/
β βββ Linux/
β βββ logo/
β βββ Python/
β βββ SQL/
βββ pdf/ // PDF documents (CV, project reports)
βββ Video/ // Video content
Current Implementation Details
React Integration
- React components are defined directly in JS files as classes
- Components are rendered using
ReactDOM.render()
- No JSX preprocessing or module system
Component Examples
class ProjetJava extends React.Component {
render() {
const items = [
<img class='image odomo' src={imgProjetJava1} alt='odomo' />,
<img class='image biosphère' src={imgProjetJava2} alt='Biosphère' />
];
const java = <img class='logo' src='./images/java/javalogo.png' alt='javalogo'></img>;
const lis = items.map(item => <div><h1 class="resumer"></h1><li>{java}{item}</li>{lien}</div>);
return <ul>{lis}</ul>;
}
}
DOM Manipulation
buttonJava.addEventListener("click", () => {
listprojet.classList.add("colorJava");
buttonJava.classList.add("up");
ReactDOM.render(<ProjetJava />, listprojet);
// More DOM manipulation...
});
CSS Integration
- Uses a single global CSS file
- Classes are added/removed directly via JS
- Animations handled via CSS classes and JS
Internationalization
- Separate HTML and JS files for different languages
- Language switching via links between files
Modernization Requirements
Modern React & TypeScript
- Convert all components to functional components with TypeScript (.tsx)
- Implement proper typing for components, props, and state
- Replace class-based components with functional components using hooks
- Remove direct DOM manipulation in favor of React state management
Build System & Project Structure
- Set up Vite.js with TypeScript configuration
- Create a proper component structure (components/, hooks/, pages/, etc.)
- Remove Babel browser transpilation in favor of Vite
- Implement proper module imports/exports
Component Architecture
- Break down components into smaller, reusable pieces
- Implement proper prop typing with interfaces
- Convert the following key components:
- Project display components (ProjetJava, ProjetCsharp, etc.)
- Modal windows (FenetreProjet, FenetreProjetVideo, etc.)
- Timeline components with scroll animations
- Navigation system
State Management
- Replace direct DOM manipulation with React state
- Implement custom hooks for shared functionality
- Convert animations to use React state or animation libraries
Styling Strategy
- Convert global CSS to a more modular approach (CSS Modules or styled-components)
- Organize styles by component
- Keep visual design consistent with the original
Internationalization
- Implement React-based i18n solution
- Centralize language resources instead of separate files
- Support language switching without page reload
Detailed Implementation Tasks
Project Setup
- Create
package.json
with Vite, React, TypeScript, and other dependencies - Configure Vite with
vite.config.ts
for TypeScript support - Set up TypeScript configuration in
tsconfig.json
- Create proper directory structure
Core Components to Migrate
Timeline
component with animation (currently usescheckVisibility()
)ProjectDisplay
components (currentlyProjetJava
,ProjetCsharp
, etc.)- Modal components (currently
FenetreProjet
,FenetreProjetVideo
, etc.) - Header, navigation, and contact components
State Management Hooks
- Create
useVisibility
hook to replacecheckVisibility()
function - Develop
useProjects
hook to manage project selection/filtering - Implement
useLanguage
hook for internationalization
Sample Component Transformation
class FenetreProjet extends React.Component {
render() {
return <div class="contenu">
<i class="icofont-close-line-circled icofont-5x"></i>
<h1>{this.props.title}</h1>
<img class='reTEX' src={this.props.image}></img>
<p>{this.props.text}</p>
<form action={this.props.url}>
<button class="Download" type="submit"><i class="icofont-download"></i>PDF</button>
</form>
</div>
}
}
interface ProjectDetailProps {
title: string;
image: string;
text: string;
url: string;
onClose: () => void;
}
const ProjectDetail: React.FC<ProjectDetailProps> = ({
title, image, text, url, onClose
}) => {
return (
<div className="contenu">
<i className="icofont-close-line-circled icofont-5x" onClick={onClose}></i>
<h1>{title}</h1>
<img className="reTEX" src={image} alt={title} />
<p>{text}</p>
<form action={url}>
<button className="Download" type="submit">
<i className="icofont-download"></i>PDF
</button>
</form>
</div>
);
};
Animation and Effects
useEffect(() => {
const animationInterval = setInterval(() => {
// Animation logic
}, 2000);
return () => clearInterval(animationInterval);
}, []);
Project Structure
src/
βββ assets/ // Static assets
βββ components/ // React components
β βββ common/ // Shared components
β βββ layout/ // Layout components
β βββ sections/ // Page sections
βββ hooks/ // Custom hooks
βββ pages/ // Page components
βββ styles/ // CSS modules
βββ types/ // TypeScript interfaces
βββ utils/ // Helper functions
βββ i18n/ // Internationalization
βββ App.tsx // Main app component
βββ main.tsx // Entry point
Conclusion
Q: What is the main goal of refactoring a legacy project?
A: The main goal of refactoring a legacy project is to improve its maintainability, scalability, and performance by updating its architecture and codebase to modern standards.
Q: Why is it necessary to refactor a legacy project?
A: Refactoring a legacy project is necessary to address issues such as:
- Technical debt: Outdated technologies, frameworks, and libraries that are no longer supported or maintained.
- Performance issues: Slow loading times, crashes, and other performance-related problems.
- Security vulnerabilities: Outdated security measures that leave the project vulnerable to attacks.
- Maintenance difficulties: Complex codebases that are hard to understand and maintain.
Q: What are the benefits of refactoring a legacy project?
A: The benefits of refactoring a legacy project include:
- Improved maintainability: Easier to understand and modify the codebase.
- Enhanced scalability: Ability to handle increased traffic and user growth.
- Better performance: Faster loading times and improved user experience.
- Improved security: Reduced risk of security vulnerabilities and attacks.
- Increased flexibility: Ability to adapt to changing requirements and technologies.
Q: What is the difference between refactoring and rewriting a legacy project?
A: Refactoring a legacy project involves updating its architecture and codebase to modern standards while preserving its existing functionality. Rewriting a legacy project involves starting from scratch and rebuilding it from the ground up.
Q: What are the key steps involved in refactoring a legacy project?
A: The key steps involved in refactoring a legacy project include:
- Assessment: Evaluate the project's current state, identify areas for improvement, and determine the scope of the refactoring effort.
- Planning: Create a detailed plan for the refactoring effort, including timelines, resources, and budget.
- Refactoring: Update the project's architecture and codebase to modern standards, using techniques such as code splitting, modularization, and testing.
- Testing: Thoroughly test the refactored project to ensure that it meets the required standards and functionality.
- Deployment: Deploy the refactored project to production, ensuring a smooth transition for users.
Q: What are some common challenges encountered during the refactoring process?
A: Some common challenges encountered during the refactoring process include:
- Resistance to change: Developers may be hesitant to adopt new technologies or approaches.
- Complexity: Refactoring a complex codebase can be time-consuming and challenging.
- Testing: Ensuring that the refactored project meets the required standards and functionality can be difficult.
- Deployment: Deploying the refactored project to production can be a complex process.
Q: How can I ensure that the refactored project meets the required standards and functionality?
A: To ensure that the refactored project meets the required standards and functionality, follow these best practices:
- Thorough testing: Conduct comprehensive testing to identify and fix any issues.
- Code reviews: Regularly review the code to ensure that it meets the required standards and best practices.
- Continuous integration: Use continuous integration tools to automate testing and deployment.
- Collaboration: Work closely with stakeholders and team members to ensure that the refactored project meets their needs and expectations.
Q: What are some best practices for refactoring a legacy project?
A: Some best practices for refactoring a legacy project include:
- Start small: Begin with a small scope and gradually expand to larger areas.
- Use incremental changes: Make incremental changes to the codebase, rather than making large, sweeping changes.
- Test thoroughly: Conduct comprehensive testing to ensure that the refactored project meets the required standards and functionality.
- Collaborate: Work closely with stakeholders and team members to ensure that the refactored project meets their needs and expectations.
Q: How can I measure the success of the refactoring effort?
A: To measure the success of the refactoring effort, track metrics such as:
- Performance: Measure the project's performance, including loading times and user experience.
- Security: Evaluate the project's security, including vulnerability scanning and penetration testing.
- Maintainability: Assess the project's maintainability, including code complexity and modularity.
- User satisfaction: Measure user satisfaction, including feedback and surveys.
By following these best practices and guidelines, you can successfully refactor a legacy project and improve its maintainability, scalability, and performance.