Giao diện
Layer cung cấp gì
@tasco/nuxt-layer-base là điểm vào duy nhất của framework. Một dòng extends mang theo toàn bộ plugin, middleware, layout, route BFF và cấu hình mặc định. Trang này liệt kê chính xác những gì dự án nhận được, thứ tự chúng chạy, và cách ghi đè từng phần.
ts
// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@tasco/nuxt-layer-base'],
})Nuxt layer hoạt động thế nào
Layer là một dự án Nuxt đóng gói thành package. Khi extends, Nuxt gộp file theo đường dẫn: file cùng đường dẫn ở dự án luôn thắng file của layer; file chỉ có ở layer thì vẫn được nạp. Không có cơ chế "gộp một nửa" — ghi đè là thay cả file.
Với cấu hình thì ngược lại: nuxt.config.ts và app.config.ts được merge sâu, dự án chỉ cần khai phần muốn đổi. Mảng thì được nối (phần tử của dự án đứng trước, của layer nối sau) — nhờ vậy modules và css của layer không bị mất khi dự án khai thêm. Layer để nav và topNav rỗng nên menu hiển thị đúng những gì dự án khai.
Tối đa 2 tầng
Quy ước của core: @tasco/nuxt-layer-base → app sản phẩm. Thêm tầng thứ ba (layer dùng chung cho vài sản phẩm) làm thứ tự ghi đè khó lần và phải mở RFC trước.
Bảng những gì layer mang theo
| Nhóm | Nội dung | Ghi đè bằng cách |
|---|---|---|
| Module | @ant-design-vue/nuxt (có extractStyle), @nuxt/fonts (self-host Quicksand + Montserrat) | Khai thêm modules trong dự án — danh sách được nối, không thay thế |
| CSS nền | @tasco/theme/base.css, @tasco/ui/style.css | Thêm CSS của dự án qua css: [...], nạp sau |
| Render | ssr: true + routeRules: { '/**': { ssr: false } } | routeRules của dự án, xem Chế độ render |
| Auto-import | useApi, useAuth, usePermission, useTable, useThemeMode | — |
| Component toàn cục | 17 component C* thương hiệu (plugin 01.ui) | — |
| Plugin | 01.ui → 02.auth → 03.permission → 04.error | Tạo plugin cùng tên trong app/plugins/ |
| Middleware | auth.global, permission.global | Tạo file cùng tên trong app/middleware/ |
| Layout | app/layouts/default.vue — khung sider + header + content | Tạo app/layouts/default.vue trong dự án |
| Trang | app/pages/auth/login.vue, app/error.vue | Tạo file cùng đường dẫn |
| Component | <TascoLoginForm>, <Can> (auto-import) | — |
| Server | server/api/[...].ts (proxy /api/**), server/routes/auth/* | Xem mục dưới |
| Cấu hình | runtimeConfig mặc định, app.config.ts (tasco.*) | .env / app.config.ts của dự án |
Thứ tự chạy khi mở một trang
1. Nitro khởi động — routeRules áp dụng (mặc định trang render phía client)
2. Plugin 01.ui → đăng ký component C* toàn cục
3. Plugin 02.auth → GET /auth/session, đổ vào useState('tasco:auth:user')
4. Plugin 03.permission → đăng ký directive v-can
5. Plugin 04.error → gắn errorHandler toàn cục, cung cấp $tascoError
6. Middleware auth.global → chưa đăng nhập, route không khai auth:false → /auth/login
7. Middleware permission.global → thiếu quyền trong meta.permissions → ném 403
8. app.vue → <a-config-provider> (theme Tasco + locale vi_VN) + biến CSS --tasco-*
9. layouts/default.vue → sider (menu từ app.config, đã lọc quyền) + header + nội dung trangTiền tố số trong tên plugin quyết định thứ tự: 02.auth phải chạy trước 03.permission vì directive đọc user từ state. Middleware chạy theo thứ tự tên file, nên auth.global trước permission.global.
Ghi đè từng phần
Menu, tiêu đề, chế độ theme
Không cần ghi đè layout — khai báo trong app.config.ts của dự án:
ts
export default defineAppConfig({
tasco: {
appTitle: 'Quản lý đơn hàng',
footerText: '© Tập đoàn Tasco',
themeMode: 'light',
topNav: [{ label: 'Điều hành', path: '/ops' }],
nav: [{ label: 'Đơn hàng', path: '/orders', permission: '/orders/search' }],
},
})Layout riêng
Tạo app/layouts/default.vue trong dự án là layer không còn tác dụng cho layout đó. Khi đó dự án tự chịu trách nhiệm: lọc menu theo quyền (usePermission().filterByPermission), nút đổi sáng/tối (useThemeMode), menu tài khoản và logout. Cân nhắc dùng lại CAppLayout + CSideNav + CTopNav thay vì dựng từ đầu.
Trang đăng nhập riêng
vue
<!-- app/pages/auth/login.vue -->
<script setup lang="ts">
definePageMeta({ auth: false, layout: false })
</script>
<template>
<div class="login-brand">
<TascoLoginForm title="ONE AUTO" subtitle="Đăng nhập hệ thống" @success="navigateTo('/')" />
</div>
</template>app.vue riêng
Hạn chế ghi đè. Nếu buộc phải, giữ lại <a-config-provider> với theme + vi_VN và phần inject biến CSS — thiếu chúng thì toàn bộ màu, mật độ và bản địa hoá của antdv sai. Chép từ @tasco/nuxt-layer-base/app/app.vue rồi sửa.
Route server riêng
Route cụ thể trong server/ của dự án thắng catch-all server/api/[...].ts của layer. Dùng khi cần tổng hợp nhiều lời gọi, hoặc khi backend trả định dạng khác hẳn:
ts
// server/api/orders/summary.get.ts — thắng catch-all cho đúng đường dẫn này
export default defineEventHandler(async (event) => {
// Cần token thì đọc session của layer, đừng tự giải mã cookie.
const session = getTascoSession(event)
// ...
})Xem BFF: /api/** đi đâu.
Kiểm tra layer đã nạp đúng
bash
npx nuxi info # liệt kê layer đang extendsDấu hiệu layer chưa nạp: <CTable> báo unknown component, useApi không auto-import, vào trang không bị chuyển về /auth/login.
Liên quan
- Kiến trúc — bức tranh package và phụ thuộc.
- Cấu hình & biến môi trường — toàn bộ khoá cấu hình.
- Chế độ render — vì sao mặc định là CSR.