Giao diện
Thêm vào dự án có sẵn
Dùng khi đã có một app Nuxt và muốn chuyển sang nền tảng chung. Dự án mới thì đi đường Tạo app mới cho nhanh.
Điều kiện
| Yêu cầu | Vì sao |
|---|---|
Nuxt ^4.0.0, Vue ^3.5 | Layer khai nuxt/vue là peer dependency |
Chưa extends layer nào khác, hoặc chỉ một | Quy ước tối đa 2 tầng layer (base → app) |
Chưa dùng đường dẫn /auth/** và /api/** cho mục đích khác | Layer chiếm hai tiền tố này cho BFF |
| Không dùng Pinia làm store chính | Framework dùng useState + cookie + app.config.ts |
1. Registry và package
Thêm .npmrc như ở Chuẩn bị môi trường, rồi:
bash
pnpm add @tasco/nuxt-layer-base @tasco/uiGhim hai package cùng một phiên bản — cả bộ @tasco/* đi lockstep.
2. Khai báo layer
ts
// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@tasco/nuxt-layer-base'],
compatibilityDate: '2025-01-01',
})Layer mang theo: module @ant-design-vue/nuxt và @nuxt/fonts, CSS nền, routeRules mặc định CSR, plugin UI/auth/permission/error, middleware auth.global + permission.global, layout mặc định, trang /auth/login, và toàn bộ route Nitro của BFF. Chi tiết: Layer cung cấp gì.
3. Gỡ cấu hình trùng
Xoá khỏi nuxt.config.ts của dự án những thứ layer đã lo — giữ lại sẽ chồng chéo hoặc ghi đè nhầm:
modules: ['@ant-design-vue/nuxt']và mọi cấu hìnhantd.- CSS reset và import theme antdv thủ công.
ssr/routeRulestự đặt, trừ khi thực sự muốn ghi đè (xem Chế độ render).- Plugin tự đăng ký component antdv toàn cục.
- Middleware tự kiểm tra đăng nhập — thay bằng
definePageMeta({ auth, permissions }).
Đổi mọi import ... from 'ant-design-vue' sang @tasco/ui:
diff
- import { Table, Tag, Select } from 'ant-design-vue'
+ import { CSelect } from '@tasco/ui'CTable, CTag, CButton, CForm, CCard, CPageHeader… đã đăng ký toàn cục nên bỏ hẳn import; primitive re-export (CSelect, CFormItem, CInput…) vẫn import từ @tasco/ui. ESLint của core sẽ báo lỗi nếu còn import trực tiếp ant-design-vue.
4. Biến môi trường
bash
# .env
NUXT_SESSION_SECRET= # bắt buộc ở production: openssl rand -base64 32
NUXT_AUTH_BASE_URL=https://example.com/cop
NUXT_API_PROXY_TARGET=https://gateway.example.com
# Chưa cắm IAM thì chạy tạm:
# NUXT_AUTH_MOCK=trueBảng đầy đủ: Cấu hình & biến môi trường.
5. Chuyển lời gọi backend sang BFF
Trước đây gọi thẳng gateway kèm token ở client; giờ gọi qua /api/** và để Nitro gắn token:
diff
- const data = await $fetch('https://gateway.example.com/orders', {
- headers: { Authorization: `Bearer ${token}` },
- })
+ const api = useApi()
+ const data = await api('/orders')Bỏ mọi chỗ lưu access token ở localStorage/sessionStorage/Pinia — token nằm trong cookie httpOnly, client không đọc được và cũng không cần đọc. Xem BFF.
6. Chạy và đối chiếu
bash
pnpm install
pnpm dev- [ ] Vào một trang bất kỳ → bị đưa về
/auth/login(trừ trang khaiauth: false). - [ ] Đăng nhập (mock hoặc IAM thật) → về đúng trang ban đầu, sidebar hiện menu từ
app.config.ts. - [ ] Gọi một API qua
useApi→ tab Network thấy request tới/api/..., không thấy token. - [ ]
pnpm lint && pnpm typechecksạch.
Xung đột thường gặp
| Tình huống | Cách xử lý |
|---|---|
Dự án đã có app/app.vue | Nuxt lấy bản của dự án. Phải tự bọc <a-config-provider> với theme + locale vi_VN và inject CSS vars, hoặc xoá file để dùng bản của layer |
Dự án đã có app/layouts/default.vue | Bản của dự án thắng. Muốn giữ khung chung thì xoá, rồi khai báo menu qua app.config.ts |
Đã có trang /auth/login riêng | Giữ được, dùng lại <TascoLoginForm> bên trong; xem Form đăng nhập |
Đã có server/api/** của riêng dự án | Route cụ thể của dự án thắng catch-all của layer. Đặt tên khác /api/... nếu không muốn đi qua proxy |
| Trang cần SSR (SEO, chia sẻ link) | Bật lại từng route: routeRules: { '/landing': { ssr: true } } và tự xử lý điểm đau của antdv — xem Chế độ render |
Lỗi [TSCONFIG_ERROR] hoặc thiếu type | Chạy nuxi prepare (hoặc pnpm typecheck) để sinh lại .nuxt/tsconfig.json |
Tiếp theo
Hướng dẫn từng bước để dựng thử một màn hình theo đúng mẫu của framework.