# Hugo Modules

本文專門介紹 Hugo Modules 以及對應的 `hugo mod` 指令。

## 什麼是 Module

Module 是 Hugo 組織內容的基本單位。一個 module 可以是完整的 Hugo 專案，也可以只是提供某一種元件（content、layouts、assets、data、i18n、static、archetypes）的小型可重用套件。你安裝的主題，本質上就是一個 module。

Module 可以任意組合、巢狀引用，也可以掛載外部目錄，甚至是非 Hugo 專案的目錄，全部併入同一個 [UFS](project-structure.md#ufs)。

## 初始化與引用

專案本身要先變成一個 module 才能引用其他 module：

```bash
hugo mod init github.com/user/theme
```

這會產生 `go.mod`。如果你不打算讓其他人導入你的模組，那麼具體的名稱並不重要，取個合理的名稱即可。

在 `hugo.yaml` 宣告要引用的 module：

```yaml
module:
  imports:
    - path: github.com/user/theme
```

執行 `hugo` 構建時，會自動下載 module、寫入快取，並產生 `go.sum` 記錄版本與校驗碼。

同時引用多個 module 時，同名檔案的合併規則按照 [UFS](project-structure.md) 規則合併。

## 常用指令

以下整理常用的 `hugo mod` 指令：

- 更新單一 module：

    ```bash
    hugo mod get -u github.com/user/theme
    ```

- 指定版本：

    ```bash
    hugo mod get -u github.com/user/theme@v0.42.0
    ```

- 更新全部 module：

    ```bash
    hugo mod get -u
    ```

- 遞迴更新 module：

    ```bash
    hugo mod get -u ./...
    ```

- 清理 `go.mod`/`go.sum` 中未使用的項目：

    ```bash
    hugo mod tidy
    ```

- 清除 module 快取：

    ```bash
    hugo mod clean
    ```

## Vendor

`hugo mod vendor` 用於本地檢視與臨時修改除錯。

此指令會將所有引用的 module 複製到優先權更高的 `_vendor` 目錄，可以直接在 `_vendor` 目錄中對 module 修改測試。直接修改 `_vendor` 內的檔案僅用於快速除錯，再次 vendor 就會被覆蓋，正式的客製化方式仍然是透過 UFS 在專案根目錄用相同路徑覆蓋。

## Replace

Replace 功能用於永久替換依賴，比如改為自己的 fork：

```text {title="go.mod"}
require example.com/othermodule v0.1.0

replace example.com/othermodule => example.com/myfork/othermodule v0.1.0
```

或是指向本地目錄：

```text {title="go.mod"}
replace github.com/user/theme => /home/user/projects/theme
```

`replace` 寫在 `go.mod` 裡並隨專案一起發布，因此對所有建置這個專案的人都會生效，包含 CI。

## Workspace{#workspace}

Workspace 用於設定本地開發時的 module 配置，可以將他理解為暫時版的 replace 功能。舉例來說，開發本地 module 時直接套用本機檔案：

```text {title="hugo.work"}
go 1.20

use .
use ../theme
```

以環境變數暫時啟用：

```sh
HUGO_MODULE_WORKSPACE=hugo.work hugo server
```

或是在 `hugo.yaml` 設定長期啟用 workspace 模式：

```yaml {title="hugo.yaml"}
workspace: 'hugo.work'
```

Workspace 和 replace 最大的差異是允許暫時啟用且不會寫進 `go.mod`，當模組被外部依賴，不會有 replace 設定影響外部用戶的問題。

## 實際應用範例

### 多語言網站

如同[多語言網站](multilingual.md#獨立目錄)說的一樣，可以將指定目錄 mount 到指定位置的指定 site 上，以完成多語言設定。

### 共用元件庫

最基礎的應用，多個網站共用同一組 shortcode、partial 或 CSS，抽成獨立 module 讓所有網站引用：

```yaml
module:
  imports:
    - path: github.com/your-org/shared-components
```

### exampleSite

開發主題時常見的做法是在主題 repo 裡放一個 `exampleSite/` 目錄，作為主題的範例網站使用，但 `exampleSite/` 這個網站依賴的主題是專案根目錄的主題本身。

Workspace 可以輕鬆解決這個問題，設定方式為

```text {title="hugo.work"}
go 1.20

use .
use ../
```

```yaml {title="hugo.yaml"}
workspace = 'hugo.work'
```

### node_modules

Mounts 功能也可用於 node_modules，讓你直接將 node_modules 內容 mount 到指定目錄，不需手動 vendor 套件。設定方式為：

```yaml
module:
  mounts:
    - source: assets
      target: assets
    - source: node_modules/@awmottaz/prettier-plugin-void-html/
      target: assets/prettier-plugin-void-html
```

在 JS 和模板中就能直接使用該目錄的內容。

### 內容與源碼分離

把 `content/` `assets/` 獨立成一個 module（獨立的 git repo），讓寫手完全不需要碰觸主題原始碼：

```yaml
module:
  imports:
    - path: github.com/your-org/site-content
```

寫手只需要對 `site-content` 這個獨立 repo 有存取權限，不會誤動到 layouts 等程式碼部分。工程師只需要設定 CI 構建時下載這個 module 即可簡單達成權責分離。

本地開發需要即時看到內容變更效果時，可以搭配前面提到的 `replace` 指向本地路徑或用 workspace 掛載。

### 多環境設定分離

把正式站與預覽站需要的不同 `data/` 或 `params` 依環境切換引用：

```yaml {title="config/staging/hugo.yaml"}
module:
  imports:
    - path: config-staging
```

```yaml {title="config/production/hugo.yaml"}
module:
  imports:
    - path: config-production
```

其中 `config/staging` 和 `config/production` 目錄會根據 environment variable [自動切換](https://gohugo.io/configuration/introduction/#example)，或是以 `hugo -e staging` 手動指定，也可搭配 CI/CD 依部署環境切換要引用的設定 module。




## Ancestors of This Page (Auto Generated)



- https://hugo-community-docs.github.io/zh-tw/docs/concept/index.md

- https://hugo-community-docs.github.io/zh-tw/docs/index.md
