09: Build Tools - TypeScript Compiler vs PHP
Build Tools: TypeScript Compiler vs PHP
Section titled “Build Tools: TypeScript Compiler vs PHP”Overview
Section titled “Overview”Coming from TypeScript, you’re used to compilation steps. PHP is different—it’s interpreted and runs directly without compilation. However, PHP projects still use build tools for assets, optimization, and distribution. This chapter explains when and why.
Learning Objectives
Section titled “Learning Objectives”By the end of this chapter, you’ll be able to:
- ✅ Understand why PHP doesn’t require compilation
- ✅ Use Vite/Webpack for frontend asset bundling
- ✅ Create PHAR archives for distribution
- ✅ Optimize PHP with OPcache
- ✅ Set up production-ready deployments
- ✅ Use Docker for consistent environments
Code Examples
Section titled “Code Examples”📁 View Code Examples on GitHub
This chapter includes build tool examples:
- Vite configuration for Laravel
- PHAR creation scripts
- OPcache configuration
- Docker setup examples
Explore the examples:
cd code/php-typescript-developers/chapter-09# Review configurationscat vite.config.jscat docker-compose.ymlThe Fundamental Difference
Section titled “The Fundamental Difference”TypeScript/JavaScript Build Process
Section titled “TypeScript/JavaScript Build Process”# TypeScript needs compilationnpm run build
# What happens:# 1. TypeScript → JavaScript (tsc)# 2. Bundle modules (Webpack/Vite/esbuild)# 3. Minify (Terser)# 4. Tree-shake unused code# 5. Generate source maps# Output: dist/ directory with compiled filestsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "outDir": "./dist", "sourceMap": true }}Result: You deploy the dist/ directory, not src/.
PHP: No Compilation Needed
Section titled “PHP: No Compilation Needed”# PHP runs directlyphp index.php
# No build step required!# 1. PHP interpreter reads .php files# 2. Executes immediately# 3. No compilation neededYou deploy your src/ directory as-is.
When PHP Projects DO Need Build Tools
Section titled “When PHP Projects DO Need Build Tools”1. Frontend Assets (CSS, JS)
Section titled “1. Frontend Assets (CSS, JS)”Even though PHP doesn’t need compilation, your frontend assets do:
Vite (Modern, Fast)
npm install --save-dev vitevite.config.js:
import { defineConfig } from 'vite';import laravel from 'laravel-vite-plugin';
export default defineConfig({ plugins: [ laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), ],});Build:
npm run build
# Output:# public/build/assets/app-[hash].cssLaravel Mix (Laravel’s Webpack wrapper)
npm install --save-dev laravel-mixwebpack.mix.js:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css') .version(); // Cache bustingBuild:
npm run production2. TypeScript in PHP Projects
Section titled “2. TypeScript in PHP Projects”Yes, you can use TypeScript for your frontend while using PHP for backend!
package.json:
{ "scripts": { "dev": "vite", "build": "vite build" }, "devDependencies": { "typescript": "^5.0.0", "vite": "^4.0.0" }}Your project:
project/├── src/ # PHP backend (no build needed)│ └── *.php├── resources/ # TypeScript frontend (needs build)│ ├── ts/│ └── css/├── public/ # Build output + entry point│ ├── index.php # PHP entry point│ └── build/ # Compiled TS/CSS└── package.jsonPHAR: PHP Archives (Like npm packages)
Section titled “PHAR: PHP Archives (Like npm packages)”JavaScript Bundle
Section titled “JavaScript Bundle”# Webpack bundles everything into one filenpm run buildPHP PHAR
Section titled “PHP PHAR”PHAR files package your PHP application into a single executable:
Create PHAR:
<?php$phar = new Phar('myapp.phar');$phar->startBuffering();$phar->buildFromDirectory(__DIR__ . '/src');$phar->setStub($phar->createDefaultStub('index.php'));$phar->stopBuffering();Build:
php build-phar.phpRun:
php myapp.phar# or./myapp.phar # If made executableUse Cases:
- CLI tools (like Composer, PHPUnit)
- Distributable applications
- Self-contained packages
Example: Composer is a PHAR:
php composer.phar installBox: PHAR Builder
Section titled “Box: PHAR Builder”Box is a more advanced PHAR builder:
composer require --dev humbug/boxbox.json:
{ "main": "bin/app.php", "output": "build/app.phar", "directories": ["src"], "files": ["composer.json"], "stub": true, "compression": "GZ"}Build:
vendor/bin/box compileOptimization for Production
Section titled “Optimization for Production”TypeScript/JavaScript Optimization
Section titled “TypeScript/JavaScript Optimization”{ "scripts": { "build": "webpack --mode production" }}What happens:
- Minification
- Tree-shaking
- Code splitting
- Compression
PHP Optimization
Section titled “PHP Optimization”PHP doesn’t need minification, but it has OPcache:
OPcache caches compiled PHP bytecode in memory.
Enable in php.ini:
; Enable OPcacheopcache.enable=1opcache.memory_consumption=128opcache.max_accelerated_files=10000opcache.revalidate_freq=0
; Production settingsopcache.validate_timestamps=0 ; Never check for file changesopcache.fast_shutdown=1Check OPcache status:
<?phpvar_dump(opcache_get_status());Performance impact: 2-3x faster responses!
Autoload Optimization
Section titled “Autoload Optimization”Composer can optimize autoloading:
# Developmentcomposer dump-autoload
# Production (optimized)composer dump-autoload --optimizecomposer install --optimize-autoloader --no-devWhat it does:
- Creates a classmap (like tree-shaking)
- Removes dev dependencies
- Faster class loading
Deployment Comparison
Section titled “Deployment Comparison”Node.js/TypeScript Deployment
Section titled “Node.js/TypeScript Deployment”# 1. Build applicationnpm run build
# 2. Deploy dist/ directoryrsync -av dist/ user@server:/var/www/app/
# 3. Start applicationpm2 start dist/server.js
# 4. Set up reverse proxy (nginx)Directory structure on server:
/var/www/app/└── dist/ # Only compiled code ├── server.js └── assets/PHP Deployment
Section titled “PHP Deployment”# 1. NO BUILD STEP (just copy source)rsync -av src/ user@server:/var/www/app/
# 2. Install dependenciescomposer install --no-dev --optimize-autoloader
# 3. Configure web server (Apache/Nginx)# PHP runs via PHP-FPMDirectory structure on server:
/var/www/app/├── src/ # Source code (uncompiled)├── vendor/ # Dependencies└── public/ # Web root └── index.php # Entry pointDocker for PHP
Section titled “Docker for PHP”Node.js Dockerfile
Section titled “Node.js Dockerfile”FROM node:18-alpine
WORKDIR /app
COPY package*.json ./RUN npm ci --only=production
COPY dist/ ./dist/
CMD ["node", "dist/server.js"]PHP Dockerfile
Section titled “PHP Dockerfile”FROM php:8.2-fpm-alpine
WORKDIR /var/www/app
# Install dependenciesRUN apk add --no-cache \ composer \ nginx
# Copy applicationCOPY --chown=www-data:www-data . .
# Install Composer dependenciesRUN composer install --no-dev --optimize-autoloader
# Enable OPcacheRUN docker-php-ext-install opcache
# Configure PHPCOPY php.ini /usr/local/etc/php/conf.d/custom.ini
EXPOSE 80CMD ["php-fpm"]Key differences:
- Node.js: Copy
dist/(built files) - PHP: Copy
src/(source files) + run Composer - PHP: Use PHP-FPM + Nginx (not standalone server like Node)
Asset Bundling in PHP Projects
Section titled “Asset Bundling in PHP Projects”Modern Stack (Vite + PHP)
Section titled “Modern Stack (Vite + PHP)”Directory structure:
project/├── app/ # PHP application│ └── Controllers/├── resources/ # Frontend source│ ├── js/│ │ └── app.ts│ └── css/│ └── app.css├── public/ # Web root│ ├── index.php # PHP entry│ └── build/ # Vite output├── vite.config.js└── package.jsonpackage.json:
{ "type": "module", "scripts": { "dev": "vite", "build": "vite build" }, "devDependencies": { "vite": "^4.0.0", "typescript": "^5.0.0", "@vitejs/plugin-vue": "^4.0.0" }}vite.config.js:
import { defineConfig } from 'vite';
export default defineConfig({ root: 'resources', build: { outDir: '../public/build', manifest: true, rollupOptions: { input: 'resources/js/app.ts' } }});Use in PHP:
<!DOCTYPE html><html><head> <?php // Read Vite manifest $manifest = json_decode(file_get_contents('build/manifest.json'), true); $jsFile = $manifest['resources/js/app.ts']['file']; $cssFile = $manifest['resources/js/app.ts']['css'][0] ?? null; ?>
<?php if ($cssFile): ?> <link rel="stylesheet" href="/build/<?= $cssFile ?>"> <?php endif; ?></head><body> <div id="app"></div> <script type="module" src="/build/<?= $jsFile ?>"></script></body></html>CI/CD Pipeline Comparison
Section titled “CI/CD Pipeline Comparison”TypeScript/Node.js
Section titled “TypeScript/Node.js”name: Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18'
# Build step required - run: npm ci - run: npm run build - run: npm test
# Deploy compiled code - name: Deploy run: rsync -av dist/ ${{ secrets.DEPLOY_SERVER }}:/var/www/app/name: Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: '8.2'
# NO build step for PHP code - run: composer install --no-dev --optimize-autoloader - run: composer test
# Deploy source code directly - name: Deploy run: rsync -av --exclude 'node_modules' --exclude '.git' . ${{ secrets.DEPLOY_SERVER }}:/var/www/app/PHP + Frontend Assets
Section titled “PHP + Frontend Assets”jobs: deploy: steps: # ...
# Build frontend assets - uses: actions/setup-node@v3 - run: npm ci - run: npm run build
# Install PHP dependencies - run: composer install --no-dev
# Deploy everything - name: Deploy run: | rsync -av \ --exclude 'node_modules' \ --exclude 'resources/js' \ --exclude 'resources/css' \ . ${{ secrets.DEPLOY_SERVER }}:/var/www/app/Development Workflow
Section titled “Development Workflow”TypeScript Development
Section titled “TypeScript Development”# Terminal 1: Watch and rebuildnpm run dev
# Terminal 2: Run servernpm startPHP Development
Section titled “PHP Development”# Option 1: Built-in server (dev only)php -S localhost:8000
# Option 2: Laravel Artisanphp artisan serve
# Option 3: Dockerdocker-compose up
# If using frontend assets:# Terminal 2: Watch assetsnpm run devPerformance Considerations
Section titled “Performance Considerations”TypeScript/Node.js
Section titled “TypeScript/Node.js”Optimization happens at build time:
- Dead code elimination
- Minification
- Compression
- Code splitting
Optimization happens at runtime:
- OPcache (bytecode caching)
- Autoload optimization
- Database query caching
- Application-level caching (Redis, Memcached)
No dead code elimination needed because PHP only loads what it uses.
Key Takeaways
Section titled “Key Takeaways”- PHP is interpreted - No compilation/transpilation step required (unlike TypeScript)
- Frontend assets still need bundling - Use Vite/Webpack for JS/CSS
- PHAR files package PHP apps into single executable (like bundled JS)
- OPcache is PHP’s runtime optimization (bytecode cache, not build step)
- Deployment is simpler - Deploy source code directly, no build artifacts
- Composer optimization replaces some build steps (
composer install --optimize-autoloader) - Docker works differently - No
npm run buildin Dockerfile, justcomposer install - Laravel Mix/Vite handle frontend assets in full-stack PHP apps
- No source maps needed for PHP - errors show actual source lines
composer dump-autoloadis closest to “rebuild” - regenerates autoloader- Production optimization via OPcache config, not build tooling
- Monorepo tools less common - PHP projects often self-contained
Comparison Table
Section titled “Comparison Table”| Aspect | TypeScript/Node.js | PHP |
|---|---|---|
| Compilation | Required | Not needed |
| Build Output | dist/ directory | N/A |
| Deploy | Compiled files | Source files |
| Optimization | Build-time | Runtime (OPcache) |
| Frontend Assets | Webpack/Vite | Same (Webpack/Vite) |
| Dependencies | node_modules/ | vendor/ |
| Production Prep | npm run build | composer install --optimize |
| Caching | Application level | OPcache + application level |
Quick Reference
Section titled “Quick Reference”| Task | TypeScript/Node.js | PHP |
|---|---|---|
| Start dev server | npm run dev | php -S localhost:8000 |
| Build for production | npm run build | N/A (or composer install --optimize) |
| Build assets | npm run build | npm run build (same!) |
| Optimize code | Build-time minification | OPcache configuration |
| Deploy | Upload dist/ | Upload src/ + run Composer |
| Create package | npm pack | Create PHAR |
Next Steps
Section titled “Next Steps”Now that you understand the build process (or lack thereof), let’s explore debugging tools.
Next Chapter: 10: Debugging: Node Inspector vs Xdebug
Resources
Section titled “Resources”Questions or feedback? Open an issue on GitHub