Pug 的 include 是编译时静态嵌入,实现真正组件复用需确保路径正确(相对于当前文件)、仅支持 .pug 文件、配合 mixin 隔离作用域传参,并在 Webpack 中配置 dependOn 或 watchOptions 以触发重编译。

如何用 include 实现真正的组件复用?
Pug 的 include 不是简单复制粘贴,而是编译时的静态嵌入。这意味着被包含文件(如 src/pug/includes/navbar.pug)一旦修改,所有引用它的页面都会同步更新——但前提是路径写对、且没被缓存干扰。
路径必须相对于当前 Pug 文件,不是相对于项目根目录:
include includes/navbar.pug✅(当前文件在src/pug/下)include src/pug/includes/navbar.pug❌(会报Failed to resolve include)include只支持 .pug 文件,不能直接 include HTML 或 JS;若需动态内容,得用block+extends配合 layout-
Webpack 场景下,
pug-loader默认不监听被 include 的文件变更,需手动配置dependOn或启用watchOptions,否则改了footer.pug但页面没刷新,容易误判为“没生效”立即学习“前端免费学习笔记(深入)”;
extends 和 include 该选哪个?
二者解决不同问题:include 是“拼接”,extends 是“继承”。选错会导致逻辑混乱或编译失败。
-
用
include:- 多个页面共用同一段结构(如导航栏、页脚)
- 组件无逻辑依赖,纯 UI 片段(
portfolio-modal-1.pug就属于这类) - 不需要传参或上下文隔离
-
用
extends:- 页面有统一骨架(比如
layout/main.pug定义head、body、footer区域) - 子模板通过
block content注入差异化内容 - 需要复用布局逻辑(如 SEO meta 标签、全局 script 加载顺序)
- 页面有统一骨架(比如
混用常见错误:在
extends的子模板里又include同一个 layout 文件,会造成重复渲染或编译报错Cannot overwrite block
为什么改了 Pug 组件,HTML 输出却没变?
这不是缓存错觉,而是三个典型原因叠加的结果:
pug-loader默认关闭pretty选项时,生成的 HTML 是单行压缩格式,diff 工具难识别变化,建议开发期始终开启:{ loader: 'pug-loader', options: { pretty: true } }Webpack 的持久化缓存(
cache: true)可能跳过未声明依赖的 included 文件,需显式告诉它:“这个文件变了,也要重编译主模板”:include语句本身不会触发父模板重编译,除非你用require('./includes/header.pug')这种方式(但会失去 Pug 原生语法优势)某些构建脚本(如
html-webpack-plugin)默认只监听template指定的入口文件,不递归 watch 所有include路径。解决方案是加files: ['src/pug/*<em>\/</em>.pug']到 webpack watch 配置中
如何安全地给 Pug 组件传参?
Pug 本身不支持函数式参数传递,所谓“传参”本质是作用域变量注入,容易踩坑:
include不带参数:所有变量来自父作用域,父子模板共享同一变量名空间 → 改title可能意外覆盖子组件里的title-
正确做法是用
mixin:mixin card(title, content) .card h3= title p= content
调用:+card('Hello', 'World') mixin是唯一能隔离作用域的方式,但注意:它不能跨文件复用,必须定义在同一个文件里,或通过include引入含 mixin 的文件若需跨文件传参(如从
index.pug向includes/post-list.pug传 posts 数组),只能靠父模板提前 assign 变量,再在被 include 文件里直接使用 —— 这要求双方约定好变量名,没有类型检查,出错时错误信息指向 include 行,而非实际赋值处
真正麻烦的从来不是怎么写,而是当 12 个页面都 include 同一个 header.pug,而某天它开始依赖一个新变量,你得翻遍所有调用处确认是否已赋值。



















