Bài trước ta viết một file SCSS và khai nó vào manifest. Nhưng chuyện gì thực sự xảy ra sau đó? Trình duyệt không tải file .scss của bạn — nó tải một tệp .min.css khổng lồ gộp hàng trăm file lại. Cơ chế đứng sau là assets bundling: Odoo gom mọi file khai trong một bó (bundle), biên dịch SCSS, minify, rồi phục vụ ở một URL duy nhất. Bài này mổ xẻ nó — và tôi sẽ grep tận trong bó thật để chứng minh file của mình nằm đó.
Khai file vào một bó trong manifest
Trong __manifest__.py, key assets là một dict: mỗi khoá là một bó, giá trị là danh sách file (hỗ trợ glob **):

Hình 1: assets với bó web.assets_backend. Danh sách nhận .css, .scss (được biên dịch), .js (OWL), .xml (template QWeb-OWL), và glob **/*.scss để gom nhiều file. Bên dưới là các bó khác và bộ chỉ dẫn chèn tương đối.
Nhiều bó cho nhiều nơi
Điểm cốt lõi: khai file vào bó nào thì chỉ nơi đó nạp nó. Vài bó hay gặp:
web.assets_backend— khu quản trị (form, list, kanban...). CSS/JS cho giao diện nội bộ vào đây.web.assets_frontend— website công khai. Style cho trang khách xem.point_of_sale._assets_pos— màn hình điểm bán hàng POS.web.assets_common— dùng chung mọi nơi.
Đặt sai bó là lỗi âm thầm điển hình: file CSS backend mà nhét vào assets_frontend thì khu quản trị không bao giờ thấy nó, và ngược lại — không báo lỗi, chỉ là "không có tác dụng".
Bằng chứng: file của tôi nằm trong bó
Nói suông thì dễ. Tôi đăng nhập, tìm thẻ <link> tới bó CSS backend, tải nó về và grep:

Hình 2: Bó backend thật (web.assets_web.min.css) nặng 1.231.058 byte — đã minify, gộp hàng trăm file. Grep trong đó thấy đúng .o_quan_form .oe_title h1{color: #6f4e37; ...} — chính quy tắc SCSS của module (biến $ca-phe-nau đã biên dịch thành #6f4e37). File .scss của tôi thật sự bị nuốt vào bó và biến thành CSS thường.
Đây là chứng cứ cho toàn bộ cơ chế: bạn khai .scss, Odoo biên dịch → gộp → minify → phục vụ dưới một URL có băm phiên bản. Trình duyệt tải một tệp, không phải hàng trăm.
Chèn tương đối và thứ tự
Thứ tự file trong list chính là thứ tự nạp (quan trọng với CSS: quy tắc sau đè quy tắc trước). Khi cần xen file của bạn vào giữa các file có sẵn của Odoo, dùng bộ chỉ dẫn:
('prepend', path)— nạp trước toàn bộ bó.('after', target, path)/('before', target, path)— nạp ngay sau/trước một file cụ thể.('replace', target, path)— thay một file;('remove', target)— gỡ một file khỏi bó.
Những cái này hiếm dùng nhưng cứu bạn khi cần ghi đè một style/JS của core mà không được sửa core.
Vài lưu ý
- Thêm/bớt file cần
-u. Sửa nội dung file thì Odoo build lại bó khi tải trang (chế độ dev), nhưng thay đổi danh sách trong manifest thì phải nâng cấp module để nạp lại. - URL có băm phiên bản (
/web/assets/<hash>/...) — đổi file là đổi hash, nên trình duyệt luôn lấy bản mới, không kẹt cache. - Kiểm tra bằng DevTools hoặc fetch bó như trên: cách chắc chắn nhất để biết file đã vào bó chưa, thay vì đoán.
Ba ý mang về
assetstrong manifest gom file vào các bó; mỗi khoá (web.assets_backend,web.assets_frontend,._assets_pos...) là một bó — Odoo biên dịch SCSS, gộp, minify thành một tệp phục vụ ở/web/assets/<hash>/<bó>.min.css.- Khai đúng bó cho đúng nơi: backend cho quản trị, frontend cho website, POS cho điểm bán — đặt sai bó là "không có tác dụng" âm thầm.
- Thứ tự trong list = thứ tự nạp; dùng
prepend/after/before/replace/removeđể chèn tương đối; thêm/bớt file cần-u; kiểm bằng cách grep chính bó thật.
Xong chuyện giao diện và asset. Bài sau quay lại luồng điều hướng: Phần sau đào sâu window action — mọi trường của ir.actions.act_window (target, res_id, domain, context, view_id...) quyết định action mở ra cái gì và mở như thế nào.