Skip to main content
Glama
build-tools.ts19.8 kB
import { GeminiHelper } from '../utils/gemini-helper.js'; import { ProjectConfig } from '../adapters/framework-adapter.js'; // Build tool integrations for different platforms export interface BuildToolIntegration { name: string; configFile: string; extensions: string[]; generateConfig(options: BuildConfigOptions): Promise<BuildConfig>; addTailwindSupport(config: any): any; optimizeForProduction(config: any): any; addDevTools(config: any): any; } export interface BuildConfigOptions { framework: string; features: string[]; outputDir: string; publicDir: string; entryPoint: string; cssFramework: 'tailwind' | 'bootstrap' | 'bulma'; optimization: 'development' | 'production'; bundleAnalysis?: boolean; sourceMaps?: boolean; hotReload?: boolean; } export interface BuildConfig { configFile: string; content: string; dependencies: Record<string, string>; devDependencies: Record<string, string>; scripts: Record<string, string>; } // Vite Integration export class ViteIntegration implements BuildToolIntegration { name = 'Vite'; configFile = 'vite.config.js'; extensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte']; async generateConfig(options: BuildConfigOptions): Promise<BuildConfig> { const plugins = this.getPluginsForFramework(options.framework); const tailwindConfig = options.cssFramework === 'tailwind' ? this.getTailwindConfig() : ''; const config = `import { defineConfig } from 'vite' ${plugins.imports.join('\n')} export default defineConfig({ plugins: [ ${plugins.list.join(',\n ')} ], css: { postcss: { plugins: [ require('tailwindcss'), require('autoprefixer'), ], }, }, build: { outDir: '${options.outputDir}', sourcemap: ${options.sourceMaps !== false}, rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], utils: ['lodash', 'date-fns'] } } } }, server: { port: 3000, hot: ${options.hotReload !== false} }, resolve: { alias: { '@': '/src' } } })`; return { configFile: this.configFile, content: config, dependencies: { 'vite': '^5.0.0', ...(options.cssFramework === 'tailwind' && { 'tailwindcss': '^3.4.0', 'autoprefixer': '^10.4.0', 'postcss': '^8.4.0' }) }, devDependencies: plugins.devDependencies, scripts: { 'dev': 'vite', 'build': 'vite build', 'preview': 'vite preview', ...(options.bundleAnalysis && { 'analyze': 'vite-bundle-analyzer' }) } }; } addTailwindSupport(config: any): any { return { ...config, css: { ...config.css, postcss: { plugins: [ require('tailwindcss'), require('autoprefixer'), ], }, }, }; } optimizeForProduction(config: any): any { return { ...config, build: { ...config.build, minify: 'terser', terserOptions: { compress: { drop_console: true, drop_debugger: true, }, }, rollupOptions: { ...config.build?.rollupOptions, output: { ...config.build?.rollupOptions?.output, manualChunks: { vendor: ['react', 'react-dom'], utils: ['lodash', 'date-fns'] } } } } }; } addDevTools(config: any): any { return { ...config, server: { ...config.server, hmr: true, open: true, }, define: { __DEV__: true, } }; } private getPluginsForFramework(framework: string) { switch (framework.toLowerCase()) { case 'react': return { imports: ["import react from '@vitejs/plugin-react'"], list: ['react()'], devDependencies: { '@vitejs/plugin-react': '^4.2.0' } }; case 'vue': return { imports: ["import vue from '@vitejs/plugin-vue'"], list: ['vue()'], devDependencies: { '@vitejs/plugin-vue': '^5.0.0' } }; case 'svelte': return { imports: ["import { svelte } from '@sveltejs/vite-plugin-svelte'"], list: ['svelte()'], devDependencies: { '@sveltejs/vite-plugin-svelte': '^3.0.0' } }; default: return { imports: [], list: [], devDependencies: {} }; } } private getTailwindConfig(): string { return `/** @type {import('tailwindcss').Config} */ export default { content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx,vue,svelte}", ], theme: { extend: { colors: { primary: { 50: '#eff6ff', 500: '#3b82f6', 900: '#1e3a8a', }, }, }, }, plugins: [], }`; } } // Webpack Integration export class WebpackIntegration implements BuildToolIntegration { name = 'Webpack'; configFile = 'webpack.config.js'; extensions = ['.js', '.ts', '.jsx', '.tsx']; async generateConfig(options: BuildConfigOptions): Promise<BuildConfig> { const config = `const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { entry: './src/index.${this.getExtension(options.framework)}', output: { path: path.resolve(__dirname, '${options.outputDir}'), filename: '[name].[contenthash].js', clean: true, }, module: { rules: [ { test: /\\.(js|jsx|ts|tsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ '@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript' ] } } }, { test: /\\.css$/, use: [ ${options.optimization === 'production' ? 'MiniCssExtractPlugin.loader' : "'style-loader'"}, 'css-loader', 'postcss-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' }), ${options.optimization === 'production' ? 'new MiniCssExtractPlugin(),' : ''} ], resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'], alias: { '@': path.resolve(__dirname, 'src') } }, devServer: { contentBase: path.join(__dirname, '${options.publicDir}'), hot: ${options.hotReload !== false}, port: 3000, } };`; return { configFile: this.configFile, content: config, dependencies: {}, devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0', 'webpack-dev-server': '^4.15.0', 'html-webpack-plugin': '^5.6.0', 'mini-css-extract-plugin': '^2.7.6', 'babel-loader': '^9.1.3', '@babel/core': '^7.23.6', '@babel/preset-env': '^7.23.6', '@babel/preset-react': '^7.23.3', '@babel/preset-typescript': '^7.23.3', 'css-loader': '^6.8.1', 'style-loader': '^3.3.3', 'postcss-loader': '^7.3.3', ...(options.cssFramework === 'tailwind' && { 'tailwindcss': '^3.4.0', 'autoprefixer': '^10.4.0', 'postcss': '^8.4.0' }) }, scripts: { 'start': 'webpack serve --mode development', 'build': 'webpack --mode production', 'dev': 'webpack serve --mode development --open' } }; } addTailwindSupport(config: any): any { // Add PostCSS configuration for Tailwind return config; } optimizeForProduction(config: any): any { return { ...config, optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all', }, }, }, }, }; } addDevTools(config: any): any { return { ...config, devtool: 'eval-source-map', }; } private getExtension(framework: string): string { switch (framework.toLowerCase()) { case 'react': return 'tsx'; case 'vue': return 'ts'; default: return 'js'; } } } // Next.js Integration export class NextJSIntegration implements BuildToolIntegration { name = 'Next.js'; configFile = 'next.config.js'; extensions = ['.js', '.ts', '.jsx', '.tsx']; async generateConfig(options: BuildConfigOptions): Promise<BuildConfig> { const config = `/** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, swcMinify: true, images: { domains: ['example.com'], }, experimental: { appDir: true, }, webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => { // Custom webpack configuration return config; }, ${options.optimization === 'production' ? ` compiler: { removeConsole: true, },` : ''} } module.exports = nextConfig`; return { configFile: this.configFile, content: config, dependencies: { 'next': '^14.0.0', 'react': '^18.2.0', 'react-dom': '^18.2.0', ...(options.cssFramework === 'tailwind' && { 'tailwindcss': '^3.4.0', 'autoprefixer': '^10.4.0', 'postcss': '^8.4.0' }) }, devDependencies: { '@types/node': '^20.10.0', '@types/react': '^18.2.0', '@types/react-dom': '^18.2.0', 'typescript': '^5.3.0' }, scripts: { 'dev': 'next dev', 'build': 'next build', 'start': 'next start', 'lint': 'next lint' } }; } addTailwindSupport(config: any): any { return config; } optimizeForProduction(config: any): any { return { ...config, compiler: { ...config.compiler, removeConsole: true, }, experimental: { ...config.experimental, optimizeCss: true, } }; } addDevTools(config: any): any { return { ...config, reactStrictMode: true, }; } } // Nuxt.js Integration export class NuxtIntegration implements BuildToolIntegration { name = 'Nuxt.js'; configFile = 'nuxt.config.ts'; extensions = ['.vue', '.ts', '.js']; async generateConfig(options: BuildConfigOptions): Promise<BuildConfig> { const config = `export default defineNuxtConfig({ devtools: { enabled: true }, css: [${options.cssFramework === 'tailwind' ? "'~/assets/css/main.css'" : ''}], modules: [ ${options.cssFramework === 'tailwind' ? "'@nuxtjs/tailwindcss'," : ''} ], build: { transpile: [] }, nitro: { prerender: { routes: ['/'] } } })`; return { configFile: this.configFile, content: config, dependencies: { 'nuxt': '^3.8.0', ...(options.cssFramework === 'tailwind' && { '@nuxtjs/tailwindcss': '^6.8.0' }) }, devDependencies: {}, scripts: { 'build': 'nuxt build', 'dev': 'nuxt dev', 'generate': 'nuxt generate', 'preview': 'nuxt preview' } }; } addTailwindSupport(config: any): any { return { ...config, modules: [ ...config.modules, '@nuxtjs/tailwindcss' ] }; } optimizeForProduction(config: any): any { return { ...config, nitro: { ...config.nitro, minify: true, } }; } addDevTools(config: any): any { return { ...config, devtools: { enabled: true } }; } } // SvelteKit Integration export class SvelteKitIntegration implements BuildToolIntegration { name = 'SvelteKit'; configFile = 'svelte.config.js'; extensions = ['.svelte', '.ts', '.js']; async generateConfig(options: BuildConfigOptions): Promise<BuildConfig> { const config = `import adapter from '@sveltejs/adapter-auto'; import { vitePreprocess } from '@sveltejs/kit/vite'; /** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: [vitePreprocess()], kit: { adapter: adapter(), alias: { '@': './src' } } }; export default config;`; return { configFile: this.configFile, content: config, dependencies: { '@sveltejs/adapter-auto': '^2.1.0', '@sveltejs/kit': '^1.27.0', 'svelte': '^4.2.0', ...(options.cssFramework === 'tailwind' && { 'tailwindcss': '^3.4.0', 'autoprefixer': '^10.4.0', 'postcss': '^8.4.0' }) }, devDependencies: { '@sveltejs/vite-plugin-svelte': '^2.5.0', 'vite': '^4.5.0' }, scripts: { 'dev': 'vite dev', 'build': 'vite build', 'preview': 'vite preview' } }; } addTailwindSupport(config: any): any { return config; } optimizeForProduction(config: any): any { return config; } addDevTools(config: any): any { return config; } } // Build Tool Factory export class BuildToolFactory { private static integrations: Map<string, BuildToolIntegration> = new Map([ ['vite', new ViteIntegration()], ['webpack', new WebpackIntegration()], ['nextjs', new NextJSIntegration()], ['nuxt', new NuxtIntegration()], ['sveltekit', new SvelteKitIntegration()] ]); static getIntegration(tool: string): BuildToolIntegration | null { return this.integrations.get(tool.toLowerCase()) || null; } static getSupportedTools(): string[] { return Array.from(this.integrations.keys()); } static registerIntegration(name: string, integration: BuildToolIntegration): void { this.integrations.set(name.toLowerCase(), integration); } } // Universal project generator export interface UniversalProjectOptions { name: string; framework: 'react' | 'vue' | 'svelte' | 'angular' | 'nextjs' | 'nuxt' | 'sveltekit'; buildTool?: 'vite' | 'webpack' | 'rollup' | 'parcel'; cssFramework: 'tailwind' | 'bootstrap' | 'bulma'; features: string[]; typescript: boolean; testing: boolean; linting: boolean; formatting: boolean; husky: boolean; storybook: boolean; } export async function generateUniversalProject(options: UniversalProjectOptions): Promise<{ files: Array<{ path: string; content: string }>; instructions: string[]; }> { const files: Array<{ path: string; content: string }> = []; const instructions: string[] = []; // Determine build tool based on framework let buildTool = options.buildTool; if (!buildTool) { buildTool = options.framework === 'nextjs' ? 'webpack' : options.framework === 'nuxt' ? 'webpack' : options.framework === 'sveltekit' ? 'vite' : 'vite'; } // Get framework adapter const { AdapterFactory } = await import('../adapters/framework-adapter'); const adapter = AdapterFactory.getAdapter(options.framework); if (!adapter) { throw new Error(`Unsupported framework: ${options.framework}`); } // Get build tool integration const integration = BuildToolFactory.getIntegration(buildTool); if (!integration) { throw new Error(`Unsupported build tool: ${buildTool}`); } // Generate project structure const projectConfig: ProjectConfig = { name: options.name, framework: options.framework, features: options.features, buildTool, cssFramework: options.cssFramework, stateManagement: (options as any).stateManagement, routing: (options as any).routing }; const projectStructure = await adapter.generateProject(projectConfig); files.push(...projectStructure.files.map((f: any) => ({ path: f.path, content: f.content }))); // Generate build configuration const buildConfig = await integration.generateConfig({ framework: options.framework, features: options.features, outputDir: 'dist', publicDir: 'public', entryPoint: 'src/main', cssFramework: options.cssFramework, optimization: 'development', bundleAnalysis: true, sourceMaps: true, hotReload: true }); files.push({ path: buildConfig.configFile, content: buildConfig.content }); // Add additional configurations if (options.typescript) { files.push({ path: 'tsconfig.json', content: generateTSConfig(options.framework) }); } if (options.cssFramework === 'tailwind') { files.push({ path: 'tailwind.config.js', content: generateTailwindConfig(options.framework) }); files.push({ path: 'postcss.config.js', content: `module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }` }); } if (options.linting) { files.push({ path: '.eslintrc.js', content: generateESLintConfig(options.framework, options.typescript) }); } if (options.formatting) { files.push({ path: '.prettierrc', content: JSON.stringify({ semi: true, trailingComma: 'es5', singleQuote: true, printWidth: 80, tabWidth: 2 }, null, 2) }); } // Generate instructions instructions.push( `1. Install dependencies: npm install`, `2. Start development server: npm run dev`, `3. Build for production: npm run build`, ...(options.linting ? ['4. Run linting: npm run lint'] : []), ...(options.testing ? ['5. Run tests: npm run test'] : []) ); return { files, instructions }; } function generateTSConfig(framework: string): string { const baseConfig = { compilerOptions: { target: 'ES2020', lib: ['ES2020', 'DOM', 'DOM.Iterable'], module: 'ESNext', skipLibCheck: true, moduleResolution: 'bundler', allowImportingTsExtensions: true, resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: framework === 'react' ? 'react-jsx' : 'preserve', strict: true, noUnusedLocals: true, noUnusedParameters: true, noFallthroughCasesInSwitch: true, baseUrl: '.', paths: { '@/*': ['./src/*'] } }, include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'], references: [{ path: './tsconfig.node.json' }] }; return JSON.stringify(baseConfig, null, 2); } function generateTailwindConfig(framework: string): string { const contentPaths = { react: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], vue: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], svelte: ['./src/**/*.{html,js,svelte,ts}'], angular: ['./src/**/*.{html,ts}'] }; return `/** @type {import('tailwindcss').Config} */ export default { content: ${JSON.stringify(contentPaths[framework as keyof typeof contentPaths] || contentPaths.react)}, theme: { extend: {}, }, plugins: [], }`; } function generateESLintConfig(framework: string, typescript: boolean): string { const config = { env: { browser: true, es2020: true }, extends: [ 'eslint:recommended', ...(typescript ? ['@typescript-eslint/recommended'] : []), ...(framework === 'react' ? ['plugin:react-hooks/recommended'] : []) ], parser: typescript ? '@typescript-eslint/parser' : undefined, parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, plugins: [ ...(framework === 'react' ? ['react-refresh'] : []), ...(typescript ? ['@typescript-eslint'] : []) ], rules: { ...(framework === 'react' ? { 'react-refresh/only-export-components': 'warn' } : {}) } }; return `module.exports = ${JSON.stringify(config, null, 2)}`; }

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/Tai-DT/mcp-tailwind-gemini'

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