隨著前端生態爆發,單一框架難以涵蓋所有需求。Laravel(PHP 後端)+ Grunt(自動化建置)+ Bower(前端套件管理) 曾是 2014-2016 年經典「全棧」組合。雖然 Bower/Grunt 已被 npm/Yarn + Webpack/Vite 取代,但其架構思想——後端框架專注業務邏輯、前端工具鏈專注資產管線、套件管理器解耦依賴——仍具參考價值。本文重現經典架構並標註現代替代方案。
# 1. Laravel 專案(需 Composer)
composer create-project laravel/laravel myproject --prefer-dist
# 2. 進入專案根目錄
cd myproject
# 3. 初始化 npm(產生 package.json)
npm init -y
# 4. 安裝 Grunt CLI 與核心
npm install -g grunt-cli
npm install grunt --save-dev
# 5. 安裝 Bower
npm install -g bower
bower init -f
myproject/
├── app/ # Laravel 核心程式碼
├── public/ # 公開入口
│ ├── index.php
│ ├── assets/ # 建置後靜態資產(CSS/JS/Fonts)
│ │ ├── css/
│ │ ├── js/
│ │ └── fonts/
│ └── packages/ # 兼容舊套件
├── resources/ # 原始前端資源(Sass/Less/ES6)
│ ├── assets/
│ │ ├── sass/
│ │ └── js/
│ └── views/
├── public/assets/bower/ # Bower 安裝目錄(.bowerrc 指定)
├── Gruntfile.js # Grunt 任務定義
├── package.json # npm 相依
├── bower.json # Bower 相依
└── .bowerrc # Bower 設定
{
"directory": "public/assets/bower"
}
bower install bootstrap jquery --save
自動解析相依:Bootstrap 依賴 jQuery,bower.json 記錄版本鎖定。
npm install grunt-contrib-sass grunt-contrib-uglify grunt-contrib-concat \
grunt-contrib-cssmin grunt-contrib-copy grunt-contrib-clean \
grunt-contrib-watch grunt-bower-concat --save-dev
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// 1. 清理舊建置
clean: {
dist: ['public/assets/css/*', 'public/assets/js/*', 'public/assets/fonts/*']
},
// 2. Bower 套件合併(JS/CSS)
bower_concat: {
all: {
dest: 'resources/assets/js/vendor.js',
cssDest: 'resources/assets/css/vendor.css',
bowerOptions: { relative: false }
}
},
// 3. Sass 編譯
sass: {
dist: {
files: {
'public/assets/css/app.css': 'resources/assets/sass/app.scss'
}
}
},
// 4. JS 合併(vendor + app)
concat: {
js: {
src: [
'resources/assets/js/vendor.js',
'resources/assets/js/app.js'
],
dest: 'public/assets/js/app.js'
}
},
// 5. 壓縮
uglify: {
dist: {
src: 'public/assets/js/app.js',
dest: 'public/assets/js/app.min.js'
}
},
cssmin: {
dist: {
src: ['public/assets/css/app.css', 'resources/assets/css/vendor.css'],
dest: 'public/assets/css/app.min.css'
}
},
// 6. 複製字型
copy: {
fonts: {
expand: true,
cwd: 'public/assets/bower/bootstrap-sass/assets/fonts/bootstrap/',
src: ['**'],
dest: 'public/assets/fonts/bootstrap/'
}
},
// 7. 監視開發模式
watch: {
sass: {
files: ['resources/assets/sass/**/*.scss'],
tasks: ['sass', 'cssmin']
},
js: {
files: ['resources/assets/js/**/*.js'],
tasks: ['concat', 'uglify']
}
}
});
// 載入外掛
require('load-grunt-tasks')(grunt);
// 任務別名
grunt.registerTask('default', ['clean', 'bower_concat', 'sass', 'concat', 'uglify', 'cssmin', 'copy']);
grunt.registerTask('dev', ['default', 'watch']);
};
{{-- resources/views/layouts/app.blade.php --}}
@yield('content')
| 傳統工具 | 現代替代 | 遷移優勢 |
|---|---|---|
| Bower | npm / Yarn / pnpm | 單一套件登錄、語義化版本、lockfile、無需額外設定檔 |
| Grunt | Webpack / Vite / esbuild / Laravel Mix | 模組熱替換(HMR)、Tree-shaking、代碼分割、TypeScript 原生、極速建置 |
| 手動 concat/uglify | Webpack entry + optimization.splitChunks | 自動依賴圖、長期快取哈希、動態匯入 |
# 安裝
npm install laravel-mix --save-dev
# webpack.mix.js
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.version(); // 產生哈希檔名
# 執行
npx mix # 開發
npx mix --production # 生產壓縮
Laravel + Grunt + Bower 見證了前端工程化從「手動複製檔案」到「自動化管線」的演進。理解其核心痛點——依賴解析、預處理編譯、合併壓縮、版本快取——有助於評估現代工具鏈的設計哲學。新專案請直接採用 Laravel + Vite(或 Mix)+ npm,舊專案可參考本文逐步遷移。