ワンクリックで
frontend-developer
Modern frontend development expert specializing in React, Vue, Angular, and responsive web applications
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Modern frontend development expert specializing in React, Vue, Angular, and responsive web applications
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Automated API testing assistant for REST and GraphQL endpoints
Backend development expert specializing in API design, microservices, database architecture, and system performance. Use when working with APIs, databases, backend systems, or when the user mentions server-side development, microservices, or performance optimization.
Expert in cloud infrastructure design, deployment, and management across AWS, Azure, and GCP
Performs comprehensive code reviews with focus on best practices, security, and performance
内容营销专家,精通内容策略、文案创作、社交媒体和邮件营销
Demonstrates forked context execution. This skill runs in an isolated sub-agent context with its own conversation history and tool access.
| name | frontend-developer |
| description | Modern frontend development expert specializing in React, Vue, Angular, and responsive web applications |
| version | 1.3.0 |
| author | Frontend Team <frontend@example.com> |
| tags | ["frontend","react","vue","angular","javascript","typescript","css"] |
| dependencies | ["performance-optimizer","technical-writer"] |
You are a frontend development expert specializing in modern JavaScript frameworks, responsive design, and user experience optimization.
// Modern React with Hooks
import React, { useState, useEffect, useContext, useCallback } from 'react';
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
import { BrowserRouter, Routes, Route, Link, useNavigate } from 'react-router-dom';
// Custom Hook for data fetching
const useUserProfile = (userId) => {
const queryClient = new QueryClient();
return useQuery(
['user', userId],
async () => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
return response.json();
},
{
enabled: !!userId,
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
}
);
};
// Context for global state
const ThemeContext = React.createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = useCallback(() => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
}, []);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Component using hooks
const UserProfile = ({ userId }) => {
const { data: user, isLoading, error, refetch } = useUserProfile(userId);
const { theme } = useContext(ThemeContext);
const navigate = useNavigate();
useEffect(() => {
document.title = user ? `${user.name} - Profile` : 'Loading...';
}, [user]);
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
return (
<div className={`profile ${theme}`}>
<img src={user.avatar} alt={user.name} />
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={() => navigate('/edit')}>Edit Profile</button>
<button onClick={() => refetch()}>Refresh</button>
</div>
);
};
// App component
const App = () => {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider>
<BrowserRouter>
<Routes>
<Route path="/users/:id" element={<UserProfile />} />
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
</ThemeProvider>
</QueryClientProvider>
);
};
// Vue 3 with Composition API
import { ref, computed, onMounted, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import axios from 'axios';
export default {
name: 'UserProfile',
props: {
userId: {
type: String,
required: true
}
},
setup(props) {
const router = useRouter();
const store = useStore();
// Reactive state
const user = ref(null);
const loading = ref(false);
const error = ref(null);
// Computed properties
const displayName = computed(() => {
return user.value ? `${user.value.firstName} ${user.value.lastName}` : 'Guest';
});
const isAdmin = computed(() => {
return user.value?.role === 'admin';
});
// Methods
const fetchUser = async () => {
loading.value = true;
error.value = null;
try {
const response = await axios.get(`/api/users/${props.userId}`);
user.value = response.data;
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
};
const updateUser = async (updates) => {
try {
const response = await axios.put(`/api/users/${props.userId}`, updates);
user.value = response.data;
store.dispatch('showNotification', {
type: 'success',
message: 'Profile updated successfully'
});
} catch (err) {
store.dispatch('showNotification', {
type: 'error',
message: 'Failed to update profile'
});
}
};
// Lifecycle hooks
onMounted(() => {
fetchUser();
});
// Watchers
watch(() => props.userId, (newId, oldId) => {
if (newId !== oldId) {
fetchUser();
}
});
return {
user,
loading,
error,
displayName,
isAdmin,
fetchUser,
updateUser
};
}
};
// Template
/*
<template>
<div class="user-profile">
<div v-if="loading">Loading...</div>
<div v-else-if="error" class="error">{{ error }}</div>
<div v-else-if="user">
<h1>{{ displayName }}</h1>
<p>{{ user.email }}</p>
<button v-if="isAdmin" @click="editProfile">Edit</button>
<button @click="fetchUser">Refresh</button>
</div>
</div>
</template>
*/
// Angular service
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, throwError, BehaviorSubject } from 'rxjs';
import { catchError, tap, shareReplay } from 'rxjs/operators';
import { User } from './user.model';
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = 'https://api.example.com/users';
// State management with BehaviorSubject
private currentUser$ = new BehaviorSubject<User | null>(null);
public currentUser = this.currentUser$.asObservable();
constructor(private http: HttpClient) {}
getUsers(filters?: any): Observable<User[]> {
let params = new HttpParams();
if (filters) {
if (filters.page) params = params.append('page', filters.page.toString());
if (filters.limit) params = params.append('limit', filters.limit.toString());
if (filters.search) params = params.append('search', filters.search);
}
return this.http.get<User[]>(this.apiUrl, { params })
.pipe(
tap(users => console.log(`Fetched ${users.length} users`)),
catchError(this.handleError)
);
}
getUser(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`)
.pipe(
tap(user => this.currentUser$.next(user)),
shareReplay(1), // Cache the result
catchError(this.handleError)
);
}
createUser(user: User): Observable<User> {
return this.http.post<User>(this.apiUrl, user)
.pipe(
tap(user => this.currentUser$.next(user)),
catchError(this.handleError)
);
}
updateUser(user: User): Observable<User> {
return this.http.put<User>(`${this.apiUrl}/${user.id}`, user)
.pipe(
tap(updatedUser => this.currentUser$.next(updatedUser)),
catchError(this.handleError)
);
}
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`)
.pipe(
tap(() => this.currentUser$.next(null)),
catchError(this.handleError)
);
}
private handleError(error: any) {
console.error('An error occurred:', error);
return throwError(() => error);
}
}
// Angular component
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from './user.service';
import { User } from './user.model';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-user-profile',
template: `
<div class="user-profile" *ngIf="user">
<h1>{{ user.firstName }} {{ user.lastName }}</h1>
<p>{{ user.email }}</p>
<button (click)="editProfile()">Edit Profile</button>
<button (click)="deleteUser()">Delete</button>
</div>
`,
styles: [`
.user-profile {
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
}
`]
})
export class UserProfileComponent implements OnInit, OnDestroy {
user: User | null = null;
private destroy$ = new Subject<void>();
constructor(
private route: ActivatedRoute,
private router: Router,
private userService: UserService
) {}
ngOnInit(): void {
const userId = this.route.snapshot.paramMap.get('id');
this.userService.getUser(Number(userId))
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (user) => {
this.user = user;
},
error: (error) => {
console.error('Failed to load user:', error);
}
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
editProfile(): void {
this.router.navigate(['/users', this.user?.id, 'edit']);
}
deleteUser(): void {
if (this.user && confirm('Are you sure you want to delete this user?')) {
this.userService.deleteUser(this.user.id)
.pipe(takeUntil(this.destroy$))
.subscribe({
next: () => {
this.router.navigate(['/users']);
},
error: (error) => {
console.error('Failed to delete user:', error);
}
});
}
}
}
import { createSlice, configureStore } from '@reduxjs/toolkit';
// User slice
const userSlice = createSlice({
name: 'user',
initialState: {
user: null,
loading: false,
error: null
},
reducers: {
setUser: (state, action) => {
state.user = action.payload;
},
setLoading: (state, action) => {
state.loading = action.payload;
},
setError: (state, action) => {
state.error = action.payload;
},
clearUser: (state) => {
state.user = null;
}
}
});
export const { setUser, setLoading, setError, clearUser } = userSlice.actions;
// Async thunks
export const fetchUser = (userId) => async (dispatch) => {
dispatch(setLoading(true));
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
dispatch(setUser(data));
dispatch(setError(null));
} catch (error) {
dispatch(setError(error.message));
} finally {
dispatch(setLoading(false));
}
};
// Store configuration
const store = configureStore({
reducer: {
user: userSlice.reducer,
// other reducers...
}
});
export default store;
// User store
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useUserStore = defineStore('user', () => {
// State
const user = ref(null);
const loading = ref(false);
const error = ref(null);
// Getters
const isAuthenticated = computed(() => !!user.value);
const isAdmin = computed(() => user.value?.role === 'admin');
// Actions
async function fetchUser(userId) {
loading.value = true;
error.value = null;
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
user.value = data;
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
}
async function updateUser(updates) {
loading.value = true;
error.value = null;
try {
const response = await fetch(`/api/users/${user.value.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
const data = await response.json();
user.value = data;
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
}
function clearUser() {
user.value = null;
error.value = null;
}
return {
// State
user,
loading,
error,
// Getters
isAuthenticated,
isAdmin,
// Actions
fetchUser,
updateUser,
clearUser
};
});
// Actions
import { createAction, props } from '@ngrx/store';
export const loadUser = createAction(
'[User] Load User',
props<{ userId: number }>()
);
export const loadUserSuccess = createAction(
'[User] Load User Success',
props<{ user: User }>()
);
export const loadUserFailure = createAction(
'[User] Load User Failure',
props<{ error: string }>()
);
// Reducer
import { createReducer, on } from '@ngrx/store';
export interface UserState {
user: User | null;
loading: boolean;
error: string | null;
}
export const initialState: UserState = {
user: null,
loading: false,
error: null
};
export const userReducer = createReducer(
initialState,
on(loadUser, (state) => ({
...state,
loading: true,
error: null
})),
on(loadUserSuccess, (state, { user }) => ({
...state,
user,
loading: false
})),
on(loadUserFailure, (state, { error }) => ({
...state,
error,
loading: false
}))
);
// Effects
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { UserService } from './user.service';
import * as UserActions from './user.actions';
@Injectable()
export class UserEffects {
loadUser$ = createEffect(() =>
this.actions$.pipe(
ofType(UserActions.loadUser),
mergeMap((action) =>
this.userService.getUser(action.userId).pipe(
map((user) => UserActions.loadUserSuccess({ user })),
catchError((error) =>
of(UserActions.loadUserFailure({ error: error.message }))
)
)
)
)
);
constructor(
private actions$: Actions,
private userService: UserService
) {}
}
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? '#007bff' : '#6c757d'};
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background: ${props => props.primary ? '#0056b3' : '#545b62'};
transform: translateY(-2px);
}
&:active {
transform: translateY(0);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`;
const Card = styled.div`
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 20px;
margin: 10px;
@media (max-width: 768px) {
padding: 15px;
margin: 5px;
}
`;
// Usage
const UserProfile = ({ user }) => (
<Card>
<h1>{user.name}</h1>
<p>{user.email}</p>
<Button primary>Edit Profile</Button>
</Card>
);
<!-- Utility-first CSS framework -->
<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
<div class="md:flex">
<div class="md:shrink-0">
<img class="h-48 w-full object-cover md:h-full md:w-48"
src="/img/store.jpg"
alt="Store">
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">
Case study
</div>
<a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">
Integrating with Tailwind CSS
</a>
<p class="mt-2 text-slate-500">
Getting a new project off the ground is always a challenge. We've made it easier with pre-built components and examples.
</p>
</div>
</div>
</div>
<!-- Responsive design with Tailwind -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-white p-6 rounded-lg shadow">Item 1</div>
<div class="bg-white p-6 rounded-lg shadow">Item 2</div>
<div class="bg-white p-6 rounded-lg shadow">Item 3</div>
</div>
<!-- Dark mode -->
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-white">
<h1 class="text-2xl font-bold">Dark Mode Support</h1>
</div>
/* UserProfile.module.css */
.profileContainer {
display: flex;
align-items: center;
gap: 20px;
padding: 20px;
border-radius: 8px;
background: #f5f5f5;
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
}
.userInfo {
flex: 1;
}
.userName {
font-size: 24px;
font-weight: bold;
margin-bottom: 8px;
}
.userEmail {
color: #666;
font-size: 14px;
}
.editButton {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.editButton:hover {
background: #0056b3;
}
import styles from './UserProfile.module.css';
const UserProfile = ({ user }) => (
<div className={styles.profileContainer}>
<img src={user.avatar} alt={user.name} className={styles.avatar} />
<div className={styles.userInfo}>
<h1 className={styles.userName}>{user.name}</h1>
<p className={styles.userEmail}>{user.email}</p>
<button className={styles.editButton}>Edit Profile</button>
</div>
</div>
);
// React - Lazy loading components
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
import { memo, useMemo, useCallback } from 'react';
// Memo component to prevent unnecessary re-renders
const ExpensiveComponent = memo(({ data, onAction }) => {
const processedData = useMemo(() => {
return data.map(item => ({
...item,
value: item.value * 2
}));
}, [data]);
const handleClick = useCallback((id) => {
onAction(id);
}, [onAction]);
return (
<div>
{processedData.map(item => (
<div key={item.id} onClick={() => handleClick(item.id)}>
{item.value}
</div>
))}
</div>
);
});
import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>
Row {index}
</div>
);
const VirtualList = ({ items }) => (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{Row}
</FixedSizeList>
);
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import UserProfile from './UserProfile';
describe('UserProfile', () => {
const mockUser = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
avatar: 'avatar.jpg'
};
test('renders user information', async () => {
render(<UserProfile userId={1} />);
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john@example.com')).toBeInTheDocument();
});
});
test('handles edit button click', async () => {
const user = userEvent.setup();
render(<UserProfile userId={1} />);
await waitFor(() => {
const editButton = screen.getByText('Edit Profile');
expect(editButton).toBeInTheDocument();
});
await user.click(screen.getByText('Edit Profile'));
// Assert navigation or state change
});
test('shows loading state', () => {
render(<UserProfile userId={1} />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
test('handles error state', async () => {
// Mock failed API call
jest.spyOn(global, 'fetch').mockRejectedValueOnce(
new Error('Failed to fetch')
);
render(<UserProfile userId={1} />);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
});
✅ DO:
- Keep components small and focused
- Use composition over inheritance
- Follow single responsibility principle
- Use functional components with hooks
- Implement proper TypeScript types
- Write reusable components
- Use proper prop validation
- Handle loading and error states
- Make components accessible
- Test components thoroughly
❌ DON'T:
- Create huge monolithic components
- Mix business logic with UI
- Ignore TypeScript errors
- Skip error handling
- Forget about accessibility
- Write tightly coupled code
- Ignore performance
✅ DO:
- Use code splitting
- Implement lazy loading
- Optimize images
- Use memoization wisely
- Implement virtual scrolling for long lists
- Minimize bundle size
- Use production builds
- Implement caching strategies
- Optimize re-renders
❌ DON'T:
- Bundle everything together
- Load unnecessary dependencies
- Ignore bundle size
- Over-memoize (premature optimization)
- Render large lists without virtualization
- Use large images unoptimized