MkDocs 外掛程式
安裝、使用與建立 MkDocs 外掛程式的指南
安裝外掛程式
外掛程式在使用前都必須先在系統上安裝。如果你使用的是 MkDocs 附帶的外掛程式,則外掛程式會在你安裝 MkDocs 時一併安裝。不過,如果你要安裝第三方外掛程式,你必須先確定正確的套件名稱,再使用 pip
安裝。
pip install mkdocs-foo-plugin
警告
安裝 MkDocs 外掛程式等於安裝一個 Python 套件,並執行作者寫入其中的所有程式碼。因此,請保持應有的謹慎;程式並未嘗試進行沙箱化。
外掛程式成功安裝後即可使用。只需在設定檔中將它 啟用 即可。在 目錄 資料庫中包含大量外掛程式分級清單,你可以安裝並使用。
使用外掛程式
plugins
設定選項應包含在建立網站時要使用的外掛程式清單。每個「外掛程式」必須是指定給外掛程式的字串名稱(請參閱特定外掛程式的文件說明,以找出它的「名稱」)。這裡列出的外掛程式都必須已 安裝。
plugins:
- search
有些外掛程式可能提供自己的設定選項。如果你想要設定任何設定選項,你可以將任何外掛程式支援的選項的鍵/值對應(選項名稱:選項值
)嵌套。請注意,外掛程式名稱後面必須跟一個冒號(:
),然後在新的一行中,選項名稱和值必須縮排並用冒號分開。如果你要定義單一外掛程式的多個選項,每個選項都必須定義在單獨的一行中。
plugins:
- search:
lang: en
foo: bar
有關特定外掛程式可用的設定選項資訊,請參閱該外掛程式的文件說明。
有關預設外掛程式的清單以及如何覆寫它們的方法,請參閱 設定 文件說明。
開發外掛程式
就像 MkDocs,外掛程式也必須使用 Python 編寫。通常,每個外掛程式都預計會以一個獨立的 Python 模組的形式發行,儘管也可以在同一個模組中定義多個外掛程式。MkDocs 外掛程式至少必須包含一個 BasePlugin 子類別以及一個指向它的 進入點。
BasePlugin
mkdocs.plugins.BasePlugin
的子類別應定義外掛程式的行為。該類別通常包括在建置流程中特定事件上執行的動作,以及一個針對外掛程式的設定架構。
所有 BasePlugin
子類別都包含以下屬性
config_scheme
組態驗證實例的組。每個項目必須包含一個兩項目組,其第一個項目為組態選項的字串名稱,而第二個項目為 mkdocs.config.config_options.BaseConfigOption
或任何其子類別的實例。
例如,下列的 config_scheme
定義了三個組態選項:foo
(接受字串);bar
(接受整數);以及 baz
(接受布林值)。
class MyPlugin(mkdocs.plugins.BasePlugin):
config_scheme = (
('foo', mkdocs.config.config_options.Type(str, default='a default value')),
('bar', mkdocs.config.config_options.Type(int, default=0)),
('baz', mkdocs.config.config_options.Type(bool, default=True))
)
版本 1.4 新功能
將 Config
分成子類別以指定組態架構
要取得安全性好處,如果您只針對 MkDocs 1.4 以上,請定義組態架構為一個類別
class MyPluginConfig(mkdocs.config.base.Config):
foo = mkdocs.config.config_options.Type(str, default='a default value')
bar = mkdocs.config.config_options.Type(int, default=0)
baz = mkdocs.config.config_options.Type(bool, default=True)
class MyPlugin(mkdocs.plugins.BasePlugin[MyPluginConfig]):
...
組態定義的範例
範例
from mkdocs.config import base, config_options as c
class _ValidationOptions(base.Config):
enabled = c.Type(bool, default=True)
verbose = c.Type(bool, default=False)
skip_checks = c.ListOfItems(c.Choice(('foo', 'bar', 'baz')), default=[])
class MyPluginConfig(base.Config):
definition_file = c.File(exists=True) # required
checksum_file = c.Optional(c.File(exists=True)) # can be None but must exist if specified
validation = c.SubConfig(_ValidationOptions)
從使用者的角度來看,SubConfig
類似於 Type(dict)
,只不過它也保留了完整的驗證功能:您可以定義所有有效的金鑰以及每個值應遵守的內容。
而 ListOfItems
類似於 Type(list)
,不過,我們定義每個值必須遵守的限制。
它接受組態如下
my_plugin:
definition_file: configs/test.ini # relative to mkdocs.yml
validation:
enabled: !ENV [CI, false]
verbose: true
skip_checks:
- foo
- baz
範例
import numbers
from mkdocs.config import base, config_options as c
class _Rectangle(base.Config):
width = c.Type(numbers.Real) # required
height = c.Type(numbers.Real) # required
class MyPluginConfig(base.Config):
add_rectangles = c.ListOfItems(c.SubConfig(_Rectangle)) # required
在這個範例中,我們定義了一個複雜項目的清單,並透過將具體的 SubConfig
傳遞給 ListOfItems
來達成。
它接受組態如下
my_plugin:
add_rectangles:
- width: 5
height: 7
- width: 12
height: 2
當載入使用者的組態時,上方的架構將用於驗證組態,並填入使用者未提供的任何設定的預設值。驗證類別可以是 mkdocs.config.config_options
中提供的任何類別,或是外掛程式中定義的第三方子類別。
使用者提供的任何設定,如果驗證失敗或未在 config_scheme
中定義,都將引發 mkdocs.config.base.ValidationError
。
config
外掛程式的組態選項字典,在組態驗證完成後,會由 load_config
方法填入。使用此屬性可以存取使用者提供的選項。
def on_pre_build(self, config, **kwargs):
if self.config['baz']:
# implement "baz" functionality here...
版本 1.4 新功能
安全的基於屬性的存取
要取得安全性好處,如果您只針對 MkDocs 1.4 以上,請存取選項作為屬性
def on_pre_build(self, config, **kwargs):
if self.config.baz:
print(self.config.bar ** 2) # OK, `int ** 2` is valid.
所有 BasePlugin
子類別都包含以下方法
load_config(options)
從選項字典載入組態。傳回 (errors, warnings)
的組。此方法會在組態驗證期間由 MkDocs 呼叫,不需要外掛程式呼叫。
on_<event_name>()
定義特定事件行為的選用方法。外掛程式應在這些方法中定義其行為。用事件的實際名稱取代 <event_name>
。例如,pre_build
事件會在 on_pre_build
方法中定義。
大多數事件接受一個位置引數和各種關鍵字引數。一般而言,預期位置引數會由外掛程式修改(或取代),並傳回。如果未傳回任何內容(方法傳回 None
),則使用原始的未修改物件。關鍵字引數只是提供給背景和/或提供資料,可根據這些資料決定如何修改位置引數。以下做法是個好習慣:將關鍵字引數當作 **kwargs
接受。在 MkDocs 的未來版本中,萬一事件中提供了其他關鍵字,您將不需要變更外掛程式。
例如,以下事件將其他靜態範本新增至佈景主題組態
class MyPlugin(BasePlugin):
def on_config(self, config, **kwargs):
config['theme'].static_templates.add('my_template.html')
return config
版本 1.4 新功能
要取得安全性好處,如果您只針對 MkDocs 1.4 以上,請存取組態選項作為屬性
def on_config(self, config: MkDocsConfig):
config.theme.static_templates.add('my_template.html')
return config
事件
檢視一個顯示所有外掛事件關聯之關聯圖。
- 事件本身顯示為黃色,其中包含其參數。
- 箭頭顯示每個事件的引數和輸出順序。有時它們會被省略。
- 這些事件根據時間順序從上到下排列。
- 在從全局事件分割為部分事件時,會出現虛線。
- 按一下事件標題以跳至其描述。
一次性事件
一次性事件在每次mkdocs
呼叫時執行一次。這些事件與全局事件顯然不同的唯一情況是mkdocs serve
:與這些一次性事件不同,全局事件將執行多次--每個建置執行一次。
on_startup
startup
事件在mkdocs
呼叫的一開始執行一次。
MkDocs 1.4 中的新增功能。
不論是否為空,on_startup
方法的存在將外掛轉移至新的系統,在新的系統中,外掛物件在一個mkdocs serve
中的多個建置中會被保留。
請注意,用於初始化變數時,__init__
方法仍然較為推薦。用於初始化特定建置變數時(以及任何有疑問時),請使用on_config
事件。
參數
-
command
(Literal['build', 'gh-deploy', 'serve']
) –MkDocs 以其呼叫的命令,例如「serve」,表示
mkdocs serve
。 -
dirty
(bool
) –已傳遞
--dirty
旗標。
on_shutdown
在mkdocs
呼叫的最後,退出前執行shutdown
事件一次。
此事件僅與mkdocs serve
支援相關,否則,不論是在單一建置中,它與on_post_build
無法區分。
MkDocs 1.4 中的新增功能。
不論是否為空,on_shutdown
方法の存在將外掛轉移至新的系統,在新的系統中,外掛物件在一個mkdocs serve
中的多個建置中會被保留。
請注意,如果可行,建議持續使用on_post_build
方法進行清除工作,因為實際觸發的機會較高。on_shutdown
是「盡力而為」,因為它仰賴偵測 MkDocs 的正常關閉。
on_serve
僅在開發期間使用serve
指令時會呼叫serve
事件。它只執行一次,在第一個建置完成後。它會傳遞Server
實體,在啟動之前可以修改這個實體。例如,可以將其他的檔案或目錄新增至自動重新載入之「觀察」檔案清單中。
參數
-
server
(LiveReloadServer
) –livereload.Server
實體 -
config
(MkDocsConfig
) –全球組態物件
-
builder
(Callable
) –可呼叫函數,傳遞至
server.watch
的每個呼叫
傳回值
-
LiveReloadServer | None
–livereload.Server
實體
全局事件
在建置過程中,全局事件在建置的開始或結束處會呼叫一次。在這些事件中進行的任何變更,都將對整個網站產生全局影響。
on_config
config
事件是在建置時呼叫的第一個事件,並在使用者組態載入並驗證後立即執行。應在此變更任何組態。
參數
-
config
(MkDocsConfig
) –全球組態物件
傳回值
-
MkDocsConfig | None
–全球組態物件
on_pre_build
pre_build
事件不會變更任何變數。請使用此事件來呼叫前建置指令碼。
參數
-
config
(MkDocsConfig
) –全球組態物件
on_files
on_nav
on_env
on_post_build
post_build
事件不會變更任何變數。使用這個事件來呼叫建置後指令碼。
參數
-
config
(MkDocsConfig
) –全球組態物件
on_build_error
build_error
事件會在建置過程中 MkDocs 捕捉到任何類型的例外狀況後呼叫。使用這個事件在 MkDocs 終止前進行清理。請注意,預定在錯誤發生後執行的其他事件都會被略過。請參閱 處理錯誤 以取得更多詳細資訊。
參數
-
error
(例外狀況
) –引發的例外狀況
範本事件
針對每個非頁面範本呼叫範本事件一次。每個範本事件會針對在 extra_templates 組態設定中定義的每個範本以及主題中定義的任何 static_templates 呼叫一次。所有範本事件都會在 env 事件之後以及所有 頁面事件 之前呼叫。
on_pre_template
on_template_context
on_post_template
post_template
事件會在範本被渲染後,但寫入磁碟之前被呼叫,且可以使用來變動範本的輸出。如果回傳空字串,範本會被略過,且不會有任何內容寫入磁碟。
參數
-
output_content
(str
) –已渲染範本的輸出內容,為字串
-
範本_名稱
(字串
) –範本的字串檔名
-
config
(MkDocsConfig
) –全球組態物件
傳回值
-
str | None
–已渲染範本的輸出內容,為字串
頁面事件
頁面事件會對網站中的每個 Markdown 頁面呼叫一次。所有頁面事件都會在 post_template 事件之後並在 post_build 事件之前被呼叫。
on_pre_page
on_page_read_source
已棄用
建議使用以下其中一個替代方案,而不要使用這個事件
- 從 MkDocs 1.6 開始,改為設定
on_files
中,一個File
內的content_bytes
/content_string
。 - 通常來說,(雖然它不是一個明確的替代方案),
on_page_markdown
可以用相同的目的。
on_page_read_source
事件可以取代從檔案系統中讀取頁面原始碼預設的機制。
參數
-
page
(Page
) –mkdocs.structure.pages.Page
實例 -
config
(MkDocsConfig
) –全球組態物件
傳回值
-
str | None
–以 unicode 字串顯示一頁的原始碼。如果回傳
None
,將執行預設的從讀取檔案。
on_page_markdown
on_page_content
on_page_context
on_post_page
post_page
事件會在範本被渲染後,但寫入磁碟之前被呼叫,且可以使用來變動頁面的輸出。如果回傳空字串,頁面會被略過,且不會有任何內容寫入磁碟。
參數
-
output
(str
) –已渲染範本的輸出內容,為字串
-
page
(Page
) –mkdocs.structure.pages.Page
實例 -
config
(MkDocsConfig
) –全球組態物件
傳回值
-
str | None
–已渲染範本的輸出內容,為字串
事件優先順序
對於每個事件類型,外掛程式的對應方法會依據外掛程式在 plugins
設定 中出現的順序被呼叫。
從 MkDocs 1.4 開始,外掛程式可以選擇設定它們事件的優先順序。優先順序較高的事件會先被呼叫。如果沒有選擇優先順序的事件,會採用預設的 0。優先順序相同的事件則會按照它們在設定中出現的順序排序。
mkdocs.plugins.event_priority(priority: float) -> Callable[[T], T]
一個設定事件處理方法事件優先順序的裝飾程式。
建議的優先順序值:100
"第一順位"、50
"早先"、0
"預設"、-50
"晚"、-100
"最後順位"。由於不同的外掛程式會發現彼此有更明確的關聯,所以這些值應該進一步微調。
範例用法
@plugins.event_priority(-100) # Wishing to run this after all other plugins' `on_files` events.
def on_files(self, files, config, **kwargs):
...
MkDocs 1.4 新功能:建議使用 shim 以保持向後相容性
try:
from mkdocs.plugins import event_priority
except ImportError:
event_priority = lambda priority: lambda f: f # No-op fallback
1.6 版本新功能
還可能需要註冊多個不同優先順序的相同事件處理常式。
CombinedEvent
可以實現這一點。
mkdocs.plugins.CombinedEvent
基礎類別:Generic[P, T]
描述符,允許定義多個事件處理常式並將其宣告於一個事件名稱下。
範例用法
@plugins.event_priority(100)
def _on_page_markdown_1(self, markdown: str, **kwargs):
...
@plugins.event_priority(-50)
def _on_page_markdown_2(self, markdown: str, **kwargs):
...
on_page_markdown = plugins.CombinedEvent(_on_page_markdown_1, _on_page_markdown_2)
注意
子方法的名稱不可以 on_
開頭;相反,它們可以使用 _on_
開頭,如以上範例所示,或者其他方式。
錯誤處理
MkDocs 定義了四種類型的錯誤
mkdocs.exceptions.MkDocsException
基礎類別:ClickException
所有 MkDocs 例外狀況衍生的基礎類別。不應直接引發此狀況。應改為引發某個子類別。
mkdocs.exceptions.ConfigurationError
基礎類別:MkDocsException
當發生驗證錯誤時,會由組態驗證引發此錯誤。應由外掛程式 config_scheme 中所定義的任何組態選項來引發此錯誤。
mkdocs.exceptions.BuildError
基礎類別:MkDocsException
MkDocs 可能在構建過程中引發此錯誤。外掛程式不應引發此錯誤。
mkdocs.exceptions.PluginError
基礎類別:BuildError
mkdocs.exceptions.BuildError
的子類別,可以用於引發外掛程式事件。
意外與未捕獲的例外狀況會中斷構建程序並產生典型的 Python 追蹤回溯,這有助於除錯您的程式碼。但是,使用者通常會覺得追蹤回溯令人不知所措,而且經常會錯過有用的錯誤訊息。因此,MkDocs 會捕獲上述任何錯誤,擷取錯誤訊息,並立即結束,只會顯示有用的訊息給使用者。
因此,您可能希望捕捉外掛程式中的任何例外狀況,並引發 PluginError
,傳入您自己建立的訊息,以便使用有用的訊息中止構建程序。
任何例外狀況都將觸發 on_build_error 事件。
例如
from mkdocs.exceptions import PluginError
from mkdocs.plugins import BasePlugin
class MyPlugin(BasePlugin):
def on_post_page(self, output, page, config, **kwargs):
try:
# some code that could throw a KeyError
...
except KeyError as error:
raise PluginError(f"Failed to find the item by key: '{error}'")
def on_build_error(self, error, **kwargs):
# some code to clean things up
...
外掛程式中的記錄
為確保外掛程式的記錄訊息符合 MkDocs 的格式規範和 --verbose
/--debug
標記,請將記錄寫入 mkdocs.plugins.
名稱空間下的記錄器。
範例
import logging
log = logging.getLogger(f"mkdocs.plugins.{__name__}")
log.warning("File '%s' not found. Breaks the build if --strict is passed", my_file_name)
log.info("Shown normally")
log.debug("Shown only with `--verbose`")
if log.getEffectiveLevel() <= logging.DEBUG:
log.debug("Very expensive calculation only for debugging: %s", get_my_diagnostics())
log.error()
是另一個記錄層級,外觀上有所區別,但在其他所有方面都與 warning
的功能相同,因此很少使用。如果您的外掛程式遇到實際錯誤,最好透過引發 mkdocs.exceptions.PluginError
(也會記錄錯誤訊息) 來中斷構建。
1.5 版本新功能
MkDocs 現在提供 get_plugin_logger()
便利函式,傳回如上所述的記錄器,還會加上外掛程式的名稱作為字首。
mkdocs.plugins.get_plugin_logger(name: str) -> PrefixedLogger
傳回外掛程式的記錄器。
參數
-
name
(str
) –在
logging.getLogger
中使用的名稱。
傳回值
-
PrefixedLogger
–設定為在 MkDocs 中順利運作的記錄器,每個訊息的前面都會加上外掛程式套件的名稱。
範例
from mkdocs.plugins import get_plugin_logger
log = get_plugin_logger(__name__)
log.info("My plugin message")
進入點
外掛需要以 Python 函式庫封裝(在 PyPI 上獨立於 MkDocs 散布),並且每個都必須透過 setuptools entry_points
作為外掛進行註冊。將下列內容加入你的 setup.py
指令碼
entry_points={
'mkdocs.plugins': [
'pluginname = path.to.some_plugin:SomePluginClass',
]
}
pluginname
會是使用者(在組態檔中)使用的名稱,而 path.to.some_plugin:SomePluginClass
會是可匯入的外掛本身(from path.to.some_plugin import SomePluginClass
),其中 SomePluginClass
是 BasePlugin 的子類別,它定義了外掛行為。當然,同一個模組中可能存在多個外掛類別。只要將每個都定義為一個獨立的進入點即可。
entry_points={
'mkdocs.plugins': [
'featureA = path.to.my_plugins:PluginA',
'featureB = path.to.my_plugins:PluginB'
]
}
請注意,註冊外掛並不會啟動它。使用者仍然需要透過組態告訴 MkDocs 使用它。
發佈一個外掛
你應該在 PyPI 上發佈一個套件,然後將它加入 目錄 以便發現。根據該目錄的建議,外掛強烈建議使用獨特的外掛名稱(進入點名稱)。