Hook
Hệ thống hook là phiên bản Tapable của webpack trong pyssg. Nó cung cấp ba loại hook đồng bộ - đủ để diễn đạt mọi nhu cầu của một SSG.
Ba loại hook
SyncHook
Phát một sự kiện và gọi mọi tap theo thứ tự. Giá trị trả về bị bỏ qua. Dùng cho các tác dụng phụ (side effect) như ghi file.
builder.hooks.emit.tap("WriteFile", self._emit)
SyncBailHook
Gọi các tap theo thứ tự và dừng lại ở tap đầu tiên trả về giá trị khác None,
rồi trả về giá trị đó. Hoàn hảo cho câu hỏi "plugin nào xử lý cái này?".
# "Ai đọc được loại file này?" - reader đầu tiên thắng.
SyncWaterfallHook
Luồn một giá trị qua mọi tap: kết quả của tap này trở thành đầu vào của tap kế
tiếp. Tap trả về None nghĩa là "không thay đổi". Đây là trái tim của việc biến
đổi nội dung.
builder.hooks.transform.tap("Markdown", self._render)
# Markdown -> HTML -> thêm anchor -> highlight code -> ...
Sắp thứ tự với stage
Mỗi tap mang một stage (mặc định 0). Các tap chạy theo thứ tự stage tăng dần;
trong cùng một stage, thứ tự đăng ký được giữ nguyên. Đây là cách các plugin dùng
chung một hook phối hợp với nhau mà không cần biết nhau.
builder.hooks.transform.tap("base", fn, stage=0)
builder.hooks.transform.tap("wrap", fn, stage=10) # chạy sau "base"
Các plugin tier-2 dùng stage để sắp thứ tự công việc bên trong cùng một pass
collect: Permalink (-200) gán URL trước, rồi Collections (-100) gom nhóm
các trang, rồi Listing (0) dựng các trang danh sách, rồi Navigation (100)
dựng menu khi mọi trang (kể cả trang sinh ra tự động) đã tồn tại.
Kiểu (typing)
Hook là generic theo các tham số vị trí của nó nhờ TypeVarTuple, cho ra chữ ký
tự nhiên:
self.transform: SyncWaterfallHook[Source, Build]
self.render: SyncHook[Source, Build]