Jade 模板引擎实战指南:从语法、API 到 Wekan 中的 Blaze 模板编译链路

Jade 模板引擎实战指南:从语法、API 到 Wekan 中的 Blaze 模板编译链路 Jade 模板引擎实战指南从语法、API 到 Wekan 中的 Blaze 模板编译链路【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekanJade 是一款受 Haml 深刻影响、用 JavaScript 实现并面向 Node.js 的高性能模板引擎以空白符敏感的极简语法编写 HTML是 Wekan 看板前端Meteor Blaze页面模板的技术基石。本文以仓库内 meteor-jade-loader 所捆绑的 Jade 1.3.0 官方文档 为主体完整讲解其安装、语法、编译 API、浏览器端预编译与命令行用法并结合 Wekan 的meteor-jade-loader与rspack.config.js源码剖析.jade模板从语法树到 Blaze 运行时模板注册的完整编译链路读完你既能独立使用 Jade 编写模板也能理解 Wekan 前端构建系统中模板的接入方式。一、Jade 是什么Jade 是一个高性能模板引擎语法深受 Haml 影响使用 JavaScript 实现并运行于 Node.js。它的核心设计目标是用更少、更干净的代码写出结构清晰的 HTML。通过缩进表达嵌套关系、通过极简标记表达标签/属性/类名/id模板可读性大幅提升同时官方提供了在线试玩原 README 中的 jade-syntax-docs 在线测试地址与完整文档站jade-lang.com。在 Wekan 仓库中Jade 并非直接以 npm 依赖方式使用而是以vendored 源码形式被捆绑在自定义构建插件 npm-packages/meteor-jade-loader 内。其 package.json 显示捆绑的是 jade1.3.0来源是 mquandalle 的 jade forktarball 地址f3f956fa1031e05f85be7bc7b67f12e9ec80ba37并自带jade.md、jade-language.md、Readme_zh-cn.md等多份说明文档以及完整的examples/、test/、support/目录。二、安装通过 npm 安装最新版 Jade$ npm install jade若需要在命令行中使用jade命令则全局安装$ npm install jade -g注意在 Wekan 仓库中由于 Jade 已作为meteor-jade-loader的内部 vendor 依赖存在npm-packages/meteor-jade-loader/package.json并未把 jade 声明为独立依赖而是通过require(./lib/vendor/jade)直接加载捆绑副本见 jade-compiler.js。三、语法入门一个完整的示例Jade 的语法是空白符敏感的whitespace sensitive缩进决定元素的嵌套层级。官方 README 给出了如下经典示例doctype html html(langen) head title pageTitle script(typetext/javascript). if (foo) bar(1 5) body h1 Jade - node template engine #container.col if youAreUsingJade p You are amazing else p Get on it! p. Jade is a terse and simple templating language with a strong focus on performance and powerful features.编译后输出为!DOCTYPE html html langen head titleJade/title script typetext/javascript if (foo) bar(1 5) /script /head body h1Jade - node template engine/h1 div idcontainer classcol pYou are amazing/p pJade is a terse and simple templating language with a strong focus on performance and powerful features./p /div /body /html这个示例集中体现了 Jade 的核心语法要素逐条拆解如下语法写法含义编译结果doctype html声明 HTML5 doctype!DOCTYPE htmlhtml(langen)标签 属性html langentitle pageTitle表示输出变量/表达式titleJade/title运行时取pageTitlescript(...).标签名后加.表示后续缩进行是纯文本不做解析script.../script#container.col#id与.class快捷写法div idcontainer classcolif youAreUsingJade/else内联条件逻辑无需写{{}}按条件输出对应分支p.段落后加.多行纯文本块p.../p保留内部换行兼容性提示来自官方 README AnnouncementsJade0.31.0起废弃了 script/style 的隐式纯文本支持——即script与style标签后必须显式追加一个.才能让内容按纯文本处理。若存在大量历史文件需要批量修复官方曾提供fix-jade工具辅助自动化处理由于该变更在捆绑的 1.3.0 中依然生效编写新模板时务必遵守。3.1 控制流写法Jade 原生支持if / else if / else、each迭代等控制流关键字它们同样以缩进组织。在 Wekan 的实际模板中随处可见例如 client/components/activities/activities.jadetemplate(nameactivities) if showActivities .activities.js-sidebar-activities if $eq mode board boardActivities else cardActivities template(nameboardActivities) each activityData in boardActivitiesList activity(activityactivityData cardcard modemode)这里的if/else、each ... in ...正是由 jade-compiler.js 中自定义 Lexer 的builtInComponents规则捕获的——它通过正则/^(if|unless|else if|else|with|each)\b(.*)/将关键字识别为内部组件 token进而转换成 Blaze 的 Spacebars 区块标签。3.2 组件调用语法componentWekan 模板中大量使用componentName(...)形式调用 Blaze 组件如上例的boardActivities、activity(...)。这是 Jade 语法向 Meteor 生态的自然延伸在 jade-compiler.js 的userComponents规则中以开头的标识符会被词法分析器捕获为组件调用 token随后在 visitMixin 中被翻译为{{#componentName args}}...{{/componentName}}有内容块或{{componentName args}}无内容块形式的 Spacebars 标签。四、Node.js API在 Node 环境中通过require(jade)使用官方 API 包含编译、渲染、渲染文件三种基本姿势var jade require(jade); // compile编译模板字符串返回一个渲染函数 var fn jade.compile(string of jade, options); var html fn(locals); // render一步完成编译 渲染options 与 locals 合并 var html jade.render(string of jade, merge(options, locals)); // renderFile从文件读取模板并渲染 var html jade.renderFile(filename.jade, merge(options, locals));其中render与renderFile内部会先执行 compile 流程再把locals合并进options后执行渲染函数。4.1 核心选项官方 README 明确列出的选项如下选项作用默认值filename用于异常报错信息中定位源文件使用 include 时必填无compileDebug设为false时编译产物中不注入调试插桩代码适合生产环境truepretty为输出 HTML 添加美化缩进的空白字符false在 Wekan 的编译链路中filename语义被完整保留jade-compiler.js 在创建 Parser 时传入options.filename而 index.js 会把this.resourcePath即被处理的.jade文件绝对路径作为 filename 传入从而保证任何语法错误都能精确定位到具体模板文件。五、浏览器端支持与客户端预编译Jade 可以编译为浏览器端使用的独立脚本但官方明确指出独立版只支持最新浏览器且文件体积较大因此推荐的做法是——在构建期把模板预编译为 JavaScript客户端仅加载轻量的 runtime.js 运行库。命令行预编译方式$ jade --client --no-debug filename.jade该命令会生成filename.js内含编译后的模板函数。其中--client表示生成客户端可用代码--no-debug等价于关闭 debug 插桩即compileDebug: false。这一理念正是 Wekan 构建体系的写照客户端不加载 Jade 运行时所有.jade文件在构建期就被meteor-jade-loader编译为注册 Blaze 模板的 JavaScript详见下一节。仓库同时保留了 vendor/jade/jade.js 与 vendor/jade/runtime.js 两份 browserify 产物其构建脚本见 vendor/jade/package.json 的compile-full/compile-runtime。六、命令行用法全局安装后先查看帮助$ jade --help命令行主要能力包括编译单个/多个.jade文件为 HTML、配合--client输出客户端模板 JS、通过--no-debug关闭调试插桩等。注意命令行选项变更自v0.31.0起输出目录参数从-O改为-o即--out。捆绑版本为 1.3.0因此请使用新写法$ jade -o dist/ -P src/*.jade七、Wekan 中的落地meteor-jade-loader 编译链路7.1 构建配置接入Wekan 使用 Rspack/webpack 构建客户端其 rspack.config.js 中通过一条规则接管所有.jade文件module: { rules: [ { test: /\.jade$/, use: [path.resolve(__dirname, npm-packages/meteor-jade-loader)], }, ... ], },即所有.jade源文件都会交给 meteor-jade-loader 处理。该 loader 的职责正如其 package.json 所述把 Meteor 的.jade模板文件编译成注册 Blaze 模板的 JavaScript。7.2 两种编译模式loader 依据文件名后缀区分两种模式index.js文件模式file mode以.jade结尾的普通文件。编译结果是一个包含{ head, body, bodyAttrs, templates }的对象head内容以注释形式保留实际注入由 Meteor boilerplate 处理body内容通过Template.body.addContent(...)注册并随Meteor.startup渲染到文档文件内每个template(name...)块分别注册为独立模板见 FileCompiler。模板模式template mode以.tpl.jade结尾的文件整份文件对应一个模板模板名取文件名如 client/components/main/popup.tpl.jade 编译后注册为popup模板。当文件名为head或body时走特殊分支分别输出 head 内容或 body 渲染注册代码index.js。7.3 模板注册与运行时依赖loader 为每个模板生成的注册代码index.js如下Template.__checkName(activities); Template[activities] new Template(Template.activities, renderFuncCode);其执行前置条件是运行时环境中存在 Meteor 包的全局对象。因此 loader 在输出开头先注入一段取全局的 preambleindex.jsvar Template Package[templating-runtime].Template; var HTML Package.htmljs.HTML; var Blaze Package.blaze.Blaze; var Spacebars Package.spacebars.Spacebars; var Meteor Package.meteor.Meteor;7.4 从 Jade AST 到 Spacebars AST 的转换真正的语法处理在 jade-compiler.js 中完成整体分四层自定义 Lexer继承捆绑 jade 的JadeLexer新增builtInComponentsif/unless/else if/else/with/each与userComponentscomponent两类 token自定义 Parser继承JadeParser对markdown组件做特殊处理——启用 pipeless 模式读取后续文本块将其封装为Mixin(markdown, ...)节点parseMixin这正是 Wekan 模板内 Markdown 内容的入口转译器FileCompiler/TemplateCompiler遍历 Jade AST把标签、属性、文本、组件调用翻译为htmljs的 HTML 节点与 Spacebars 的模板标签如visitTag调用HTML.getTag(tagName)visitMixin生成{{#if ...}}等JadeCompiler API对外暴露parse(source, { filename, fileMode })与compile(source)两个入口jade-compiler.js。需要特别指出的是编译期的两条限制visitFilter会抛出 Jade filters are not supported in meteor-jade不支持 Jade 过滤器visitWhen会抛出 Case statements are not supported in meteor-jade不支持case语句——这是 meteor-jade 方言与原生 Jade 的语法差异编写模板时应避免使用这两类特性。7.5 Meteor 包的无沙箱引导由于 jade 编译器依赖htmljs、html-tools、blaze-tools、spacebars-compiler四个 Meteor 包而构建插件运行在 Meteor 构建体系之外meteor-packages.js 用 Node 的vm模块构造了一个含Package全局对象的沙箱按依赖顺序htmljs → html-tools → blaze-tools → spacebars-compiler逐个执行 vendor 目录下的包源码并用原生 JS 补齐_each、map、indexOf、extend与Tracker等最小化依赖最终导出HTML、HTMLTools、BlazeTools、SpacebarsCompiler供编译器使用且整个加载过程按进程缓存_cached保证重复构建不重复执行。八、实践要点速查模板入口Wekan 的.jade视图主要位于 client/components131 个.jade文件单个文件内可通过多个template(name...)块定义多个模板再配合component组件调用、if/else与each控制流组织 UI 逻辑样式类与 id使用.class与#id快捷写法多个类可连续书写如#container.col纯文本块script、style以及任意标签后跟.时进入纯文本模式内容中的{{...}}不会被当作模板标签解析文本插值#{}与!{}会被转换为 Spacebars 的{{ }}与{{{ }}}见 jade-compiler.js 的parseText正则替换这是 meteor-jade 方言对原生 Jade 插值语法的兼容映射调试语法或编译错误会通过 loader 的this.emitError上报给构建工具并以注释形式返回空模块避免构建崩溃index.js错误信息中带有具体文件路径与行号。九、许可协议Jade 采用 MIT 许可证见 vendor/jade/LICENSEmeteor-jade-loader本身同样以 MIT 发布见 npm-packages/meteor-jade-loader/package.json。对于想要深入了解语法的读者仓库内还保留了更完整的旧版语法文档 jade-language.md 与 jade.md以及中文版 Readme_zh-cn.md可作为扩展阅读。【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考