Build Tooling & Project Setup
Comprehensive guide for setting up TachUI projects with modern build tools, development workflows, and best practices.
🛠️ Recommended Development Stack
Core Tools
Bundler: Vite (Recommended)
npm create vite@latest my-app -- --template vanilla
# or
npm create vite@latest my-app -- --template vanilla-tsWhy Vite?
- ⚡ Lightning fast - Native ESM dev server
- 🔥 Hot Module Replacement - Instant updates
- 📦 Optimized builds - Rollup-based production builds
- 🔧 Zero config - Works out of the box with TachUI
- 🌐 Framework agnostic - Perfect for TachUI's approach
Alternative: Webpack + Babel
npm install webpack webpack-cli webpack-dev-server
npm install babel-loader @babel/core @babel/preset-envDevelopment Tools
TypeScript (Highly Recommended)
npm install -D typescript @types/nodeCode Quality
npm install -D eslint prettier
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-pluginTesting
npm install -D vitest @vitest/ui
# or
npm install -D jest @types/jest📁 Project Structure
Recommended Layout
my-tachui-app/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── common/ # Generic components (Button, Input, etc.)
│ │ ├── layout/ # Layout components (Header, Sidebar, etc.)
│ │ └── feature/ # Feature-specific components
│ ├── stores/ # State management
│ │ ├── app-store.js # Global app state
│ │ ├── user-store.js # User-specific state
│ │ └── index.js # Store exports
│ ├── utils/ # Helper functions
│ │ ├── api.js # API utilities
│ │ ├── storage.js # LocalStorage helpers
│ │ └── validation.js # Form validation
│ ├── styles/ # Global styles
│ │ ├── globals.css # Global CSS
│ │ ├── variables.css # CSS custom properties
│ │ └── components.css # Component-specific styles
│ ├── assets/ # Static assets
│ │ ├── images/ # Images
│ │ ├── icons/ # SVG icons
│ │ └── fonts/ # Custom fonts
│ ├── libs/ # External libraries
│ │ └── tachui/ # TachUI framework
│ ├── types/ # TypeScript type definitions
│ │ ├── api.ts # API types
│ │ ├── components.ts # Component types
│ │ └── global.d.ts # Global type declarations
│ ├── main.js # Application entry point
│ └── app.js # Main app component
├── public/ # Static public assets
│ ├── favicon.ico
│ ├── robots.txt
│ └── manifest.json
├── dist/ # Build output (generated)
├── tests/ # Test files
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
├── docs/ # Project documentation
├── .env # Environment variables
├── .env.local # Local environment overrides
├── .gitignore # Git ignore rules
├── vite.config.js # Vite configuration
├── tsconfig.json # TypeScript configuration
├── package.json # Dependencies and scripts
└── README.md # Project documentation⚙️ Configuration Files
Vite Configuration
Basic Vite Config (vite.config.js):
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
// TachUI alias for cleaner imports
resolve: {
alias: {
'@tachui/core': './src/libs/tachui/index.js',
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@stores': resolve(__dirname, 'src/stores'),
'@utils': resolve(__dirname, 'src/utils'),
'@styles': resolve(__dirname, 'src/styles'),
'@assets': resolve(__dirname, 'src/assets')
}
},
// Development server configuration
server: {
port: 3000,
host: true, // Listen on all addresses
open: true // Auto-open browser
},
// Build configuration
build: {
// Output directory
outDir: 'dist',
// Generate source maps for debugging
sourcemap: true,
// Optimize bundle size
rollupOptions: {
output: {
manualChunks: {
vendor: ['@tachui/core'],
utils: ['./src/utils']
}
}
},
// Asset handling
assetsDir: 'assets',
assetsInlineLimit: 4096,
// Modern build optimizations
target: 'esnext',
minify: 'esbuild'
},
// Environment variables
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
__BUILD_TIME__: JSON.stringify(new Date().toISOString())
},
// CSS configuration
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@styles/variables.scss";`
}
},
modules: {
localsConvention: 'camelCase'
}
}
})Advanced Vite Config with Plugins:
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
plugins: [
// Auto-import TachUI functions
{
name: 'tachui-auto-import',
transform(code, id) {
if (id.endsWith('.js') || id.endsWith('.ts')) {
// Auto-import frequently used TachUI functions
const autoImports = [
'createSignal',
'createComputed',
'createEffect'
]
const hasImports = autoImports.some(fn =>
code.includes(fn) && !code.includes(`import.*${fn}`)
)
if (hasImports) {
const importStatement = `import { ${autoImports.join(', ')} } from '@tachui/core';\n`
return importStatement + code
}
}
return null
}
}
],
resolve: {
alias: {
'@tachui/core': './src/libs/tachui/index.js',
'@': resolve(__dirname, 'src')
}
}
})TypeScript Configuration
Base TypeScript Config (tsconfig.json):
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "node",
"skipLibCheck": true,
/* Bundler mode */
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* Path mapping */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@stores/*": ["src/stores/*"],
"@utils/*": ["src/utils/*"],
"@styles/*": ["src/styles/*"],
"@assets/*": ["src/assets/*"],
"@tachui/core": ["src/libs/tachui/index.js"]
},
/* Output */
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": [
"src/**/*.ts",
"src/**/*.js",
"src/**/*.tsx",
"src/**/*.jsx"
],
"exclude": [
"node_modules",
"dist",
"tests"
]
}Package.json Scripts
Recommended Scripts:
{
"name": "my-tachui-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"serve": "vite preview --port 4173",
"type-check": "tsc --noEmit",
"lint": "eslint src --ext .js,.ts,.jsx,.tsx",
"lint:fix": "eslint src --ext .js,.ts,.jsx,.tsx --fix",
"format": "prettier --write src/**/*.{js,ts,jsx,tsx,css,md}",
"test": "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"clean": "rm -rf dist node_modules/.vite",
"reset": "npm run clean && npm install",
"analyze": "npx vite-bundle-analyzer",
"size": "npm run build && bundlesize"
},
"dependencies": {
"@tachui/core": "file:./src/libs/tachui"
},
"devDependencies": {
"vite": "^5.0.0",
"typescript": "^5.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0",
"vitest": "^1.0.0",
"@vitest/ui": "^1.0.0",
"bundlesize": "^0.18.0"
}
}🎯 Development Workflow
Local Development
Start Development Server:
npm run devFeatures Available:
- ✅ Hot Module Replacement - Changes reflect instantly
- ✅ Error Overlay - Build errors shown in browser
- ✅ Source Maps - Debug original code
- ✅ Live Reloading - Page refreshes on file changes
- ✅ TypeScript Checking - Real-time type checking
Development Best Practices:
// Use environment variables for configuration
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001'
// Enable development debugging
if (import.meta.env.DEV) {
console.log('🚀 TachUI App in Development Mode')
// Add development helpers
window.debugTachUI = {
signals: [], // Track signals for debugging
stores: [] // Track stores for debugging
}
}
// Conditional development features
if (import.meta.env.DEV) {
// Development-only code
import('./dev-tools.js').then(devTools => {
devTools.init()
})
}Code Quality
ESLint Configuration (.eslintrc.js):
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'@typescript-eslint/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [
'@typescript-eslint'
],
rules: {
// TachUI-specific rules
'no-unused-vars': 'warn',
'prefer-const': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
// Import organization
'import/order': ['error', {
'groups': ['builtin', 'external', 'internal', 'parent', 'sibling'],
'newlines-between': 'always'
}]
},
settings: {
'import/resolver': {
alias: {
map: [
['@', './src'],
['@tachui/core', './src/libs/tachui']
]
}
}
}
}Prettier Configuration (.prettierrc):
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "avoid"
}Testing Setup
Vitest Configuration (vite.config.js):
export default defineConfig({
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./tests/setup.js'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'tests/',
'dist/'
]
}
}
})Test Setup (tests/setup.js):
import { beforeEach } from 'vitest'
// Global test setup
beforeEach(() => {
// Reset TachUI state between tests
if (window.TachUI) {
window.TachUI.resetGlobalState()
}
// Clear DOM
document.body.innerHTML = ''
// Reset local storage
localStorage.clear()
})
// Mock browser APIs if needed
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
})🚀 Production Build
Build Configuration
Optimized Production Build:
# Build for production
npm run build
# Preview production build locally
npm run preview
# Analyze bundle size
npm run analyzeBuild Optimization Tips:
- Code Splitting:
// Dynamic imports for code splitting
const HeavyComponent = lazy(() => import('./components/HeavyComponent'))
// Route-based splitting
const routes = [
{
path: '/dashboard',
component: () => import('./pages/Dashboard')
}
]- Tree Shaking:
// Import only what you need
import { createSignal, createComputed } from '@tachui/core'
// Instead of
import * as TachUI from '@tachui/core'- Asset Optimization:
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'assets/[name]-[hash].js',
entryFileNames: 'assets/[name]-[hash].js'
}
}
}
})Environment Configuration
Environment Variables (.env):
# Development
VITE_APP_TITLE=My TachUI App
VITE_API_URL=http://localhost:3001
VITE_DEBUG=true
# Production (.env.production)
VITE_APP_TITLE=My TachUI App
VITE_API_URL=https://api.myapp.com
VITE_DEBUG=falseUsing Environment Variables:
// Access environment variables
const config = {
apiUrl: import.meta.env.VITE_API_URL,
debug: import.meta.env.VITE_DEBUG === 'true',
version: import.meta.env.VITE_APP_VERSION
}
// Environment-specific behavior
if (import.meta.env.PROD) {
// Production-only code
console.log = () => {} // Disable console.log in production
}📊 Performance Monitoring
Bundle Analysis
Analyze Bundle Size:
# Install bundle analyzer
npm install -D vite-bundle-analyzer
# Add to package.json scripts
"analyze": "vite-bundle-analyzer"
# Run analysis
npm run analyzeBundle Size Monitoring:
// package.json
"bundlesize": [
{
"path": "./dist/assets/*.js",
"maxSize": "250kb",
"compression": "gzip"
},
{
"path": "./dist/assets/*.css",
"maxSize": "50kb",
"compression": "gzip"
}
]Performance Optimizations
Lazy Loading:
// Component lazy loading
const LazyComponent = createSignal(null)
// Load component when needed
function loadComponent() {
import('./components/HeavyComponent.js')
.then(module => {
LazyComponent[1](module.default)
})
}Memory Management:
// Cleanup effects when components unmount
const cleanup = createEffect(() => {
const interval = setInterval(() => {
// Periodic task
}, 1000)
// Return cleanup function
return () => clearInterval(interval)
})🚀 Deployment
Static Hosting
Vercel:
npm install -g vercel
vercel --prodNetlify:
# Build command: npm run build
# Publish directory: dist
npm install -g netlify-cli
netlify deploy --prod --dir=distGitHub Pages:
# Add to package.json
"deploy": "npm run build && gh-pages -d dist"Server Deployment
Express.js Static Server:
// server.js
import express from 'express'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const app = express()
const port = process.env.PORT || 3000
// Serve static files
app.use(express.static(join(__dirname, 'dist')))
// SPA fallback
app.get('*', (req, res) => {
res.sendFile(join(__dirname, 'dist', 'index.html'))
})
app.listen(port, () => {
console.log(`Server running on port ${port}`)
})Docker Deployment:
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
COPY server.js ./
EXPOSE 3000
CMD ["node", "server.js"]🎯 Best Practices Summary
Development
- ✅ Use Vite for fast development
- ✅ Enable TypeScript for type safety
- ✅ Set up ESLint and Prettier
- ✅ Configure path aliases for clean imports
- ✅ Use environment variables for configuration
Code Organization
- ✅ Organize components by feature
- ✅ Separate stores for state management
- ✅ Create reusable utility functions
- ✅ Use consistent naming conventions
Performance
- ✅ Implement code splitting
- ✅ Optimize bundle size
- ✅ Monitor performance metrics
- ✅ Clean up resources properly
Production
- ✅ Enable source maps for debugging
- ✅ Configure proper caching headers
- ✅ Monitor bundle size limits
- ✅ Test production builds locally
This comprehensive setup provides a solid foundation for building scalable TachUI applications with modern development practices.