Skip to main content
Glama
webdev.ts33.3 kB
import { exec } from 'child_process'; import { promisify } from 'util'; import fs from 'fs-extra'; import path from 'path'; const execAsync = promisify(exec); export const webDevTools = new Map([ [ 'create_component', { name: 'create_component', description: 'Create frontend component (React, Vue, Angular)', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Component name' }, framework: { type: 'string', enum: ['react', 'vue', 'angular', 'svelte'], description: 'Frontend framework' }, type: { type: 'string', enum: ['functional', 'class', 'page', 'layout', 'hook', 'service'], description: 'Component type' }, props: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, type: { type: 'string' }, required: { type: 'boolean', default: false }, default: { type: 'string' } } }, description: 'Component props/properties' }, projectPath: { type: 'string', description: 'Project path' }, withTests: { type: 'boolean', default: true }, withStories: { type: 'boolean', default: false }, styling: { type: 'string', enum: ['css', 'scss', 'styled-components', 'tailwind', 'module'], default: 'css' } }, required: ['name', 'framework', 'projectPath'] }, async execute(args: any) { const { name, framework, type = 'functional', props = [], projectPath, withTests = true, withStories = false, styling = 'css' } = args; switch (framework) { case 'react': return await createReactComponent(name, type, props, projectPath, withTests, withStories, styling); case 'vue': return await createVueComponent(name, props, projectPath, withTests, styling); case 'angular': return await createAngularComponent(name, props, projectPath, withTests); case 'svelte': return await createSvelteComponent(name, props, projectPath, withTests, styling); default: throw new Error(`Unsupported framework: ${framework}`); } } } ], [ 'setup_styling', { name: 'setup_styling', description: 'Setup CSS framework or styling solution', inputSchema: { type: 'object', properties: { type: { type: 'string', enum: ['tailwind', 'bootstrap', 'material-ui', 'chakra-ui', 'ant-design', 'styled-components', 'emotion', 'sass'], description: 'Styling solution' }, projectPath: { type: 'string', description: 'Project path' }, framework: { type: 'string', enum: ['react', 'vue', 'angular'], description: 'Frontend framework' } }, required: ['type', 'projectPath', 'framework'] }, async execute(args: any) { const { type, projectPath, framework } = args; switch (type) { case 'tailwind': return await setupTailwind(projectPath, framework); case 'bootstrap': return await setupBootstrap(projectPath, framework); case 'material-ui': return await setupMaterialUI(projectPath); case 'styled-components': return await setupStyledComponents(projectPath); default: throw new Error(`Unsupported styling solution: ${type}`); } } } ], [ 'create_page', { name: 'create_page', description: 'Create page/route with routing setup', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Page name' }, path: { type: 'string', description: 'Route path' }, framework: { type: 'string', enum: ['react', 'vue', 'angular', 'nextjs', 'nuxtjs'] }, projectPath: { type: 'string', description: 'Project path' }, components: { type: 'array', items: { type: 'string' }, description: 'Components to include in page' }, layout: { type: 'string', description: 'Layout to use' }, metadata: { type: 'object', properties: { title: { type: 'string' }, description: { type: 'string' }, keywords: { type: 'array', items: { type: 'string' } } } } }, required: ['name', 'path', 'framework', 'projectPath'] }, async execute(args: any) { const { name, path: routePath, framework, projectPath, components = [], layout, metadata } = args; switch (framework) { case 'react': return await createReactPage(name, routePath, projectPath, components, layout, metadata); case 'nextjs': return await createNextJSPage(name, routePath, projectPath, components, metadata); case 'vue': return await createVuePage(name, routePath, projectPath, components, layout, metadata); case 'nuxtjs': return await createNuxtPage(name, routePath, projectPath, components, metadata); case 'angular': return await createAngularPage(name, routePath, projectPath, components); default: throw new Error(`Unsupported framework: ${framework}`); } } } ], [ 'setup_routing', { name: 'setup_routing', description: 'Setup routing configuration', inputSchema: { type: 'object', properties: { framework: { type: 'string', enum: ['react', 'vue', 'angular'] }, projectPath: { type: 'string', description: 'Project path' }, router: { type: 'string', enum: ['react-router', 'vue-router', 'angular-router'], description: 'Router library to use' }, routes: { type: 'array', items: { type: 'object', properties: { path: { type: 'string' }, component: { type: 'string' }, name: { type: 'string' }, guards: { type: 'array', items: { type: 'string' } } } }, description: 'Initial routes to setup' } }, required: ['framework', 'projectPath'] }, async execute(args: any) { const { framework, projectPath, router, routes = [] } = args; switch (framework) { case 'react': return await setupReactRouter(projectPath, routes); case 'vue': return await setupVueRouter(projectPath, routes); case 'angular': return await setupAngularRouter(projectPath, routes); default: throw new Error(`Unsupported framework: ${framework}`); } } } ], [ 'setup_state_management', { name: 'setup_state_management', description: 'Setup state management solution', inputSchema: { type: 'object', properties: { type: { type: 'string', enum: ['redux', 'zustand', 'jotai', 'recoil', 'vuex', 'pinia', 'ngrx'], description: 'State management solution' }, framework: { type: 'string', enum: ['react', 'vue', 'angular'] }, projectPath: { type: 'string', description: 'Project path' }, stores: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, state: { type: 'object' }, actions: { type: 'array', items: { type: 'string' } } } }, description: 'Initial stores to create' } }, required: ['type', 'framework', 'projectPath'] }, async execute(args: any) { const { type, framework, projectPath, stores = [] } = args; switch (type) { case 'redux': return await setupRedux(projectPath, stores); case 'zustand': return await setupZustand(projectPath, stores); case 'vuex': return await setupVuex(projectPath, stores); case 'pinia': return await setupPinia(projectPath, stores); case 'ngrx': return await setupNgRx(projectPath, stores); default: throw new Error(`Unsupported state management: ${type}`); } } } ], [ 'setup_forms', { name: 'setup_forms', description: 'Setup form handling and validation', inputSchema: { type: 'object', properties: { framework: { type: 'string', enum: ['react', 'vue', 'angular'] }, library: { type: 'string', enum: ['react-hook-form', 'formik', 'vee-validate', 'reactive-forms'], description: 'Form library to use' }, validation: { type: 'string', enum: ['yup', 'joi', 'zod', 'class-validator'], description: 'Validation library' }, projectPath: { type: 'string', description: 'Project path' }, forms: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, fields: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, type: { type: 'string' }, validation: { type: 'object' } } } } } }, description: 'Forms to create' } }, required: ['framework', 'projectPath'] }, async execute(args: any) { const { framework, library, validation, projectPath, forms = [] } = args; switch (framework) { case 'react': return await setupReactForms(projectPath, library, validation, forms); case 'vue': return await setupVueForms(projectPath, library, validation, forms); case 'angular': return await setupAngularForms(projectPath, validation, forms); default: throw new Error(`Unsupported framework: ${framework}`); } } } ], [ 'optimize_bundle', { name: 'optimize_bundle', description: 'Optimize webpack/vite bundle configuration', inputSchema: { type: 'object', properties: { bundler: { type: 'string', enum: ['webpack', 'vite', 'parcel', 'rollup'] }, projectPath: { type: 'string', description: 'Project path' }, optimizations: { type: 'array', items: { type: 'string', enum: ['code-splitting', 'tree-shaking', 'compression', 'lazy-loading', 'preloading', 'caching'] }, description: 'Optimizations to apply' }, target: { type: 'string', enum: ['development', 'production'], default: 'production' } }, required: ['bundler', 'projectPath'] }, async execute(args: any) { const { bundler, projectPath, optimizations = [], target = 'production' } = args; switch (bundler) { case 'webpack': return await optimizeWebpack(projectPath, optimizations, target); case 'vite': return await optimizeVite(projectPath, optimizations, target); default: throw new Error(`Unsupported bundler: ${bundler}`); } } } ] ]); async function createReactComponent(name: string, type: string, props: any[], projectPath: string, withTests: boolean, withStories: boolean, styling: string) { const componentDir = path.join(projectPath, 'src/components', name); await fs.ensureDir(componentDir); // Generate props interface let propsInterface = ''; if (props.length > 0) { propsInterface = `interface ${name}Props {\n`; for (const prop of props) { propsInterface += ` ${prop.name}${prop.required ? '' : '?'}: ${prop.type};\n`; } propsInterface += '}\n\n'; } // Generate component content let componentContent = `import React from 'react';\n`; if (styling === 'styled-components') { componentContent += `import styled from 'styled-components';\n`; } else if (styling !== 'tailwind') { componentContent += `import './${name}.${styling === 'module' ? 'module.' : ''}css';\n`; } componentContent += `\n${propsInterface}`; if (type === 'functional') { componentContent += `const ${name}: React.FC${props.length > 0 ? `<${name}Props>` : ''} = (${props.length > 0 ? `{ ${props.map(p => p.name).join(', ')} }` : ''}) => {\n`; componentContent += ` return (\n`; componentContent += ` <div className="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">\n`; componentContent += ` <h2>Hello from ${name}!</h2>\n`; if (props.length > 0) { componentContent += ` <pre>{JSON.stringify({ ${props.map(p => p.name).join(', ')} }, null, 2)}</pre>\n`; } componentContent += ` </div>\n`; componentContent += ` );\n`; componentContent += `};\n\n`; } else if (type === 'class') { componentContent += `class ${name} extends React.Component${props.length > 0 ? `<${name}Props>` : ''} {\n`; componentContent += ` render() {\n`; componentContent += ` return (\n`; componentContent += ` <div className="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">\n`; componentContent += ` <h2>Hello from ${name}!</h2>\n`; if (props.length > 0) { componentContent += ` <pre>{JSON.stringify(this.props, null, 2)}</pre>\n`; } componentContent += ` </div>\n`; componentContent += ` );\n`; componentContent += ` }\n`; componentContent += `}\n\n`; } else if (type === 'hook') { componentContent = `import { useState, useEffect } from 'react';\n\n`; componentContent += `export const use${name} = () => {\n`; componentContent += ` const [data, setData] = useState(null);\n`; componentContent += ` const [loading, setLoading] = useState(false);\n`; componentContent += ` const [error, setError] = useState(null);\n\n`; componentContent += ` useEffect(() => {\n`; componentContent += ` // Hook logic here\n`; componentContent += ` }, []);\n\n`; componentContent += ` return { data, loading, error };\n`; componentContent += `};\n\n`; componentContent += `export default use${name};\n`; } if (type !== 'hook') { componentContent += `export default ${name};\n`; } await fs.writeFile(path.join(componentDir, `${name}.tsx`), componentContent); // Create styling file if (styling !== 'tailwind' && styling !== 'styled-components' && type !== 'hook') { const styleExt = styling === 'scss' ? 'scss' : 'css'; const isModule = styling === 'module'; const styleFileName = isModule ? `${name}.module.${styleExt}` : `${name}.${styleExt}`; const styleContent = `.${name.toLowerCase()} { padding: 1rem; h2 { color: #333; margin-bottom: 1rem; } }`; await fs.writeFile(path.join(componentDir, styleFileName), styleContent); } // Create test file if (withTests && type !== 'hook') { const testContent = `import React from 'react'; import { render, screen } from '@testing-library/react'; import ${name} from './${name}'; describe('${name}', () => { it('renders without crashing', () => { render(<${name} />); expect(screen.getByText(/Hello from ${name}!/)).toBeInTheDocument(); }); });`; await fs.writeFile(path.join(componentDir, `${name}.test.tsx`), testContent); } // Create Storybook story if (withStories && type !== 'hook') { const storyContent = `import type { Meta, StoryObj } from '@storybook/react'; import ${name} from './${name}'; const meta: Meta<typeof ${name}> = { title: 'Components/${name}', component: ${name}, parameters: { layout: 'centered', }, tags: ['autodocs'], }; export default meta; type Story = StoryObj<typeof meta>; export const Default: Story = { args: { ${props.map(p => `${p.name}: ${p.default || `'sample ${p.name}'`}`).join(',\n ')} }, };`; await fs.writeFile(path.join(componentDir, `${name}.stories.tsx`), storyContent); } // Create index file const indexContent = `export { default } from './${name}';${type === 'hook' ? `\nexport { use${name} } from './${name}';` : ''}`; await fs.writeFile(path.join(componentDir, 'index.ts'), indexContent); return `React component ${name} created successfully at ${componentDir}`; } async function createVueComponent(name: string, props: any[], projectPath: string, withTests: boolean, styling: string) { const componentDir = path.join(projectPath, 'src/components'); await fs.ensureDir(componentDir); let componentContent = `<template> <div class="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}"> <h2>Hello from ${name}!</h2> <pre v-if="Object.keys($props).length">{{ $props }}</pre> </div> </template> <script setup lang="ts"> ${props.length > 0 ? `interface Props { ${props.map(p => ` ${p.name}${p.required ? '' : '?'}: ${p.type};`).join('\n')} } defineProps<Props>();` : ''} </script> ${styling !== 'tailwind' ? `<style scoped> .${name.toLowerCase()} { padding: 1rem; } .${name.toLowerCase()} h2 { color: #333; margin-bottom: 1rem; } </style>` : ''}`; await fs.writeFile(path.join(componentDir, `${name}.vue`), componentContent); if (withTests) { const testContent = `import { describe, it, expect } from 'vitest'; import { mount } from '@vue/test-utils'; import ${name} from './${name}.vue'; describe('${name}', () => { it('renders properly', () => { const wrapper = mount(${name}); expect(wrapper.text()).toContain('Hello from ${name}!'); }); });`; await fs.writeFile(path.join(componentDir, `${name}.spec.ts`), testContent); } return `Vue component ${name} created successfully`; } async function createAngularComponent(name: string, props: any[], projectPath: string, withTests: boolean) { await execAsync(`cd "${projectPath}" && ng generate component ${name}`); return `Angular component ${name} created successfully`; } async function createSvelteComponent(name: string, props: any[], projectPath: string, withTests: boolean, styling: string) { const componentDir = path.join(projectPath, 'src/lib/components'); await fs.ensureDir(componentDir); let componentContent = `<script lang="ts"> ${props.map(p => ` export let ${p.name}: ${p.type}${p.default ? ` = ${p.default}` : ''};`).join('\n')} </script> <div class="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}"> <h2>Hello from ${name}!</h2> ${props.length > 0 ? `<pre>{JSON.stringify({ ${props.map(p => p.name).join(', ')} }, null, 2)}</pre>` : ''} </div> ${styling !== 'tailwind' ? `<style> .${name.toLowerCase()} { padding: 1rem; } .${name.toLowerCase()} h2 { color: #333; margin-bottom: 1rem; } </style>` : ''}`; await fs.writeFile(path.join(componentDir, `${name}.svelte`), componentContent); return `Svelte component ${name} created successfully`; } async function setupTailwind(projectPath: string, framework: string) { await execAsync(`cd "${projectPath}" && npm install -D tailwindcss postcss autoprefixer`); await execAsync(`cd "${projectPath}" && npx tailwindcss init -p`); const tailwindConfig = `/** @type {import('tailwindcss').Config} */ export default { content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx,vue,svelte}", ], theme: { extend: {}, }, plugins: [], }`; await fs.writeFile(path.join(projectPath, 'tailwind.config.js'), tailwindConfig); const cssPath = framework === 'vue' ? 'src/style.css' : 'src/index.css'; const cssContent = `@tailwind base; @tailwind components; @tailwind utilities;`; await fs.writeFile(path.join(projectPath, cssPath), cssContent); return 'Tailwind CSS setup completed'; } async function setupBootstrap(projectPath: string, framework: string) { await execAsync(`cd "${projectPath}" && npm install bootstrap`); const importPath = framework === 'vue' ? 'src/main.ts' : 'src/index.tsx'; let mainContent = await fs.readFile(path.join(projectPath, importPath), 'utf-8'); mainContent = `import 'bootstrap/dist/css/bootstrap.min.css';\n${mainContent}`; await fs.writeFile(path.join(projectPath, importPath), mainContent); return 'Bootstrap setup completed'; } async function setupMaterialUI(projectPath: string) { await execAsync(`cd "${projectPath}" && npm install @mui/material @emotion/react @emotion/styled`); return 'Material-UI setup completed'; } async function setupStyledComponents(projectPath: string) { await execAsync(`cd "${projectPath}" && npm install styled-components`); await execAsync(`cd "${projectPath}" && npm install -D @types/styled-components`); return 'Styled Components setup completed'; } async function createReactPage(name: string, routePath: string, projectPath: string, components: string[], layout?: string, metadata?: any) { const pagesDir = path.join(projectPath, 'src/pages'); await fs.ensureDir(pagesDir); let pageContent = `import React from 'react';\n`; if (layout) { pageContent += `import ${layout} from '../layouts/${layout}';\n`; } for (const component of components) { pageContent += `import ${component} from '../components/${component}';\n`; } pageContent += `\nconst ${name}Page: React.FC = () => {\n`; pageContent += ` return (\n`; if (layout) { pageContent += ` <${layout}>\n`; } pageContent += ` <div className="page-${name.toLowerCase()}">\n`; pageContent += ` <h1>${name} Page</h1>\n`; for (const component of components) { pageContent += ` <${component} />\n`; } pageContent += ` </div>\n`; if (layout) { pageContent += ` </${layout}>\n`; } pageContent += ` );\n`; pageContent += `};\n\n`; pageContent += `export default ${name}Page;\n`; await fs.writeFile(path.join(pagesDir, `${name}.tsx`), pageContent); return `React page ${name} created successfully`; } async function createNextJSPage(name: string, routePath: string, projectPath: string, components: string[], metadata?: any) { const pagesDir = path.join(projectPath, 'pages'); await fs.ensureDir(pagesDir); let pageContent = `import Head from 'next/head';\n`; for (const component of components) { pageContent += `import ${component} from '../components/${component}';\n`; } pageContent += `\nexport default function ${name}() {\n`; pageContent += ` return (\n`; pageContent += ` <>\n`; if (metadata) { pageContent += ` <Head>\n`; if (metadata.title) pageContent += ` <title>${metadata.title}</title>\n`; if (metadata.description) pageContent += ` <meta name="description" content="${metadata.description}" />\n`; pageContent += ` </Head>\n`; } pageContent += ` <main>\n`; pageContent += ` <h1>${name} Page</h1>\n`; for (const component of components) { pageContent += ` <${component} />\n`; } pageContent += ` </main>\n`; pageContent += ` </>\n`; pageContent += ` );\n`; pageContent += `}\n`; await fs.writeFile(path.join(pagesDir, `${routePath}.tsx`), pageContent); return `Next.js page ${name} created successfully`; } async function createVuePage(name: string, routePath: string, projectPath: string, components: string[], layout?: string, metadata?: any) { const pagesDir = path.join(projectPath, 'src/views'); await fs.ensureDir(pagesDir); let pageContent = `<template> <div class="page-${name.toLowerCase()}"> <h1>${name} Page</h1> `; for (const component of components) { pageContent += ` <${component} />\n`; } pageContent += ` </div> </template> <script setup lang="ts"> `; for (const component of components) { pageContent += `import ${component} from '@/components/${component}.vue';\n`; } if (metadata) { pageContent += ` import { useMeta } from '@unhead/vue'; useMeta({ title: '${metadata.title || name}', meta: [ { name: 'description', content: '${metadata.description || ''}' } ] });`; } pageContent += ` </script> <style scoped> .page-${name.toLowerCase()} { padding: 2rem; } </style>`; await fs.writeFile(path.join(pagesDir, `${name}.vue`), pageContent); return `Vue page ${name} created successfully`; } async function createNuxtPage(name: string, routePath: string, projectPath: string, components: string[], metadata?: any) { const pagesDir = path.join(projectPath, 'pages'); await fs.ensureDir(pagesDir); let pageContent = `<template> <div> <Head> <Title>${metadata?.title || name}</Title> <Meta name="description" :content="'${metadata?.description || ''}'" /> </Head> <main> <h1>${name} Page</h1> `; for (const component of components) { pageContent += ` <${component} />\n`; } pageContent += ` </main> </div> </template> <script setup lang="ts"> `; for (const component of components) { pageContent += `import ${component} from '~/components/${component}.vue';\n`; } pageContent += `</script>`; await fs.writeFile(path.join(pagesDir, `${routePath}.vue`), pageContent); return `Nuxt page ${name} created successfully`; } async function createAngularPage(name: string, routePath: string, projectPath: string, components: string[]) { await execAsync(`cd "${projectPath}" && ng generate component pages/${name}`); return `Angular page ${name} created successfully`; } async function setupReactRouter(projectPath: string, routes: any[]) { await execAsync(`cd "${projectPath}" && npm install react-router-dom`); await execAsync(`cd "${projectPath}" && npm install -D @types/react-router-dom`); const routerContent = `import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; // Import your pages here import Home from './pages/Home'; import About from './pages/About'; const AppRouter: React.FC = () => { return ( <Router> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> ${routes.map(route => `<Route path="${route.path}" element={<${route.component} />} />`).join('\n ')} </Routes> </Router> ); }; export default AppRouter;`; await fs.writeFile(path.join(projectPath, 'src/AppRouter.tsx'), routerContent); return 'React Router setup completed'; } async function setupVueRouter(projectPath: string, routes: any[]) { await execAsync(`cd "${projectPath}" && npm install vue-router@4`); const routerContent = `import { createRouter, createWebHistory } from 'vue-router'; const routes = [ { path: '/', name: 'Home', component: () => import('../views/Home.vue') }, { path: '/about', name: 'About', component: () => import('../views/About.vue') }, ${routes.map(route => `{ path: '${route.path}', name: '${route.name}', component: () => import('../views/${route.component}.vue') }`).join(',\n ')} ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;`; await fs.ensureDir(path.join(projectPath, 'src/router')); await fs.writeFile(path.join(projectPath, 'src/router/index.ts'), routerContent); return 'Vue Router setup completed'; } async function setupAngularRouter(projectPath: string, routes: any[]) { // Angular CLI already sets up routing return 'Angular Router already configured'; } async function setupRedux(projectPath: string, stores: any[]) { await execAsync(`cd "${projectPath}" && npm install @reduxjs/toolkit react-redux`); const storeContent = `import { configureStore } from '@reduxjs/toolkit'; export const store = configureStore({ reducer: { // Add your reducers here }, }); export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch;`; await fs.ensureDir(path.join(projectPath, 'src/store')); await fs.writeFile(path.join(projectPath, 'src/store/index.ts'), storeContent); return 'Redux Toolkit setup completed'; } async function setupZustand(projectPath: string, stores: any[]) { await execAsync(`cd "${projectPath}" && npm install zustand`); for (const store of stores) { const storeContent = `import { create } from 'zustand'; interface ${store.name}State { ${Object.keys(store.state || {}).map(key => `${key}: ${typeof store.state[key]};`).join('\n ')} ${store.actions?.map((action: string) => `${action}: () => void;`).join('\n ') || ''} } export const use${store.name}Store = create<${store.name}State>((set) => ({ ${Object.entries(store.state || {}).map(([key, value]) => `${key}: ${JSON.stringify(value)},`).join('\n ')} ${store.actions?.map((action: string) => `${action}: () => set((state) => ({ ...state })),`).join('\n ') || ''} }));`; await fs.ensureDir(path.join(projectPath, 'src/stores')); await fs.writeFile(path.join(projectPath, `src/stores/${store.name}.ts`), storeContent); } return 'Zustand stores setup completed'; } async function setupVuex(projectPath: string, stores: any[]) { await execAsync(`cd "${projectPath}" && npm install vuex@next`); return 'Vuex setup completed'; } async function setupPinia(projectPath: string, stores: any[]) { await execAsync(`cd "${projectPath}" && npm install pinia`); return 'Pinia setup completed'; } async function setupNgRx(projectPath: string, stores: any[]) { await execAsync(`cd "${projectPath}" && npm install @ngrx/store @ngrx/effects @ngrx/store-devtools`); return 'NgRx setup completed'; } async function setupReactForms(projectPath: string, library?: string, validation?: string, forms: any[] = []) { if (library === 'react-hook-form') { await execAsync(`cd "${projectPath}" && npm install react-hook-form`); } else if (library === 'formik') { await execAsync(`cd "${projectPath}" && npm install formik`); } if (validation === 'yup') { await execAsync(`cd "${projectPath}" && npm install yup`); } else if (validation === 'zod') { await execAsync(`cd "${projectPath}" && npm install zod`); } return 'React forms setup completed'; } async function setupVueForms(projectPath: string, library?: string, validation?: string, forms: any[] = []) { if (library === 'vee-validate') { await execAsync(`cd "${projectPath}" && npm install vee-validate`); } if (validation === 'yup') { await execAsync(`cd "${projectPath}" && npm install yup`); } return 'Vue forms setup completed'; } async function setupAngularForms(projectPath: string, validation?: string, forms: any[] = []) { // Angular forms are built-in return 'Angular forms already available'; } async function optimizeWebpack(projectPath: string, optimizations: string[], target: string) { const webpackConfigPath = path.join(projectPath, 'webpack.config.js'); const config = `const path = require('path'); const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { mode: '${target}', entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[contenthash].js', clean: true, }, optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\\\/]node_modules[\\\\/]/, name: 'vendors', chunks: 'all', }, }, }, usedExports: true, sideEffects: false, }, plugins: [ ${optimizations.includes('compression') ? 'new CompressionPlugin(),' : ''} ], resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, };`; await fs.writeFile(webpackConfigPath, config); if (optimizations.includes('compression')) { await execAsync(`cd "${projectPath}" && npm install -D compression-webpack-plugin`); } return 'Webpack optimization completed'; } async function optimizeVite(projectPath: string, optimizations: string[], target: string) { const viteConfigPath = path.join(projectPath, 'vite.config.ts'); let config = `import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { target: '${target}', rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], }, }, }, }, });`; await fs.writeFile(viteConfigPath, config); return 'Vite optimization completed'; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rajawatrajat/mcp-software-engineer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server