Liquid 模板引擎实战:让非技术用户改模板而不炸服务器

发布时间:2026/11/4 11:56:37
Liquid 模板引擎实战:让非技术用户改模板而不炸服务器 Liquid 模板引擎实战让非技术用户改模板而不炸服务器【免费下载链接】liquidLiquid markup language. Safe, customer facing template language for flexible web apps.项目地址: https://gitcode.com/gh_mirrors/li/liquid让商家自己改店铺模板最怕他在里面塞一行代码直接在服务器上执行。Liquid 模板引擎专门干这事模板随便写但只能在数据上跑碰不到服务器。理清 Liquid 替你挡掉的三类风险 用户写的模板进渲染器→ Liquid 是 non-evaling 引擎也就是说不执行模板里看起来像代码的东西。哪怕模板写{{ 11 | instance_eval }}输出也只是字符串11instance_eval根本不会被调用。这点和 ERB、Jinja 这类 eval 型引擎正好相反——那些引擎信任模板Liquid 把模板当不可信输入。这也是它敢直接渲染用户内容的原因。模板要存数据库、反复用→ Liquid 强制把 compile 和 render 拆开stateless。parse是一次性的高开销动作把模板编译成对象之后同一个对象可以带着不同的数据 hash 反复render。所以把模板直接存进数据库、每次请求再喂数据这套设计天然适配。数据太多不想全塞给模板→ 用Drop继承Liquid::Drop的类导出对象。模板里写{{ product.top_sales }}时才真的调top_sales方法没用到就不查库实现惰性加载避免把整棵对象图拍平进上下文。多个场景共用一套模板→ 用Environment隔离。用户模板、邮件模板各建一个环境各自只注册自己需要的标签和过滤器避免全局互相覆盖。小项目可以共用Liquid::Environment.default。把 Liquid 跑成最小可用版本 ▶️Liquid 是个 Ruby gemMIT 协议要求 Ruby 3.0不是 npm 包。如果你的前端是 React/Vue正确姿势是服务端用 Liquid 把模板渲染成 HTML再把 HTML 传给前端而不是在前端引liquidjs。下面以 Ruby 服务端为主线讲。装依赖git clone https://gitcode.com/gh_mirrors/li/liquid # 在你的项目 Gemfile 里加一行然后 bundle install gem liquid它几乎无运行时依赖装完即可require liquid。写最小可运行代码require liquid template Liquid::Template.parse(hi {{name}}) puts template.render(name tobi) # hi tobi两行就跑通了parse编译、render喂数据拿输出。想要过滤器就传一个模块进rendermodule ProductsFilter def price(cents) format($%.2f USD, cents / 100.0) end end template Liquid::Template.parse(~LIQUID) {% for product in products %} {{ product.name }}: {{ product.price | price }} {% endfor %} LIQUID products [{ name Arbor Draft, price 39900 }] puts template.render(products products, filters: [ProductsFilter]) # Arbor Draft: $399.00 USDprice是 Ruby 模块方法{{ product.price | price }}把价格值单位分喂给它做格式化。仓库里example/server/templates/products.liquid就是一套更完整的电商示例。调这几个参数默认解析是:lax几乎吞掉一切错误线上会很难排查。给新应用直接上严格模式并配好资源和文件系统env Liquid::Environment.build do |e| e.error_mode :strict2 # 语法非法直接抛 SyntaxError e.file_system Liquid::LocalFileSystem.new(path/to/templates) e.default_resource_limits { render_score_limit: 10_000, # 限制 for 循环等 CPU 工作量 render_length_limit: 1_000_000 # 限制最终输出长度 } end template Liquid::Template.parse(source, environment: env) template.render!(name tobi, strict_variables: true)render!遇到未定义变量会立即抛异常普通render则把所有错误攒进template.errors数组页面继续渲染。LocalFileSystem只允许字母数字和_的模板名从根目录防目录穿越细节见 file_system.rb。绕过三个最常见的坑 ⚠️现象模板里用{% include sidebar %}渲染时抛This liquid context does not allow includes.根因默认文件系统是BlankFileSystem就是为安全起见把 include 直接禁掉的。一行修复建环境时设e.file_system Liquid::LocalFileSystem.new(root)或改用隔离性更好的{% render %}标签。现象模板语法明显写错了却没有任何报错页面悄悄渲染成半吊子结果。根因默认error_mode是:lax静默忽略非法标签。一行修复建环境时e.error_mode :strict2或单次解析时Liquid::Template.parse(source, error_mode: :strict)。现象变量名拼错比如{{ product.nmae }}页面上该处直接空白没人知道哪里错了。根因未定义变量默认渲染成 nil不抛也不提示。一行修复渲染时加strict_variables: true并查template.errors或直接用render!让它当场炸出来。判断你的场景适不适合 Liquid 适合上你要把模板编辑权交给非技术用户商家、运营、模板要存数据库、渲染产物是 HTML 或邮件正文——这正是 Shopify 跑了几年的用法。别硬用模板里需要调后端 API、做复杂业务分支的Liquid 只能读数据加过滤器写不了业务逻辑纯前端 JS 场景别拿这个 Ruby gem 去凑以及需要极致性能的静态页面直接预生成更快。先把error_mode和resource_limits这两个开关接进你的渲染入口再决定要不要开放模板编辑器——这一步没做好就放用户进来等于把服务器交给陌生人。你现在的模板数据是放数据库还是文件系统这决定了file_system该怎么实现。【免费下载链接】liquidLiquid markup language. Safe, customer facing template language for flexible web apps.项目地址: https://gitcode.com/gh_mirrors/li/liquid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考