知识补充:什么是EJS? EJS 是一个用 JavaScript 语言生成 HTML 页面的模板库,所以对前端开发者非常友好,几乎没有额外的学习成本。常在 Node.js 服务端使用。
问题背景
目前我们的网盘系统使用了类似淘宝中途岛架构的方式,服务端用Node.js 来渲染HTML模板,其中服务端使用的模板引擎就是 EJS。
由于不同页面需要引用的CDN资源不一样,所以编写成了不同的渲染模板,比如登录页面。而模板中的一些变量的需要经常地改动,比如CDN资源的版本信息。由于模板之间都某些CDN资源是共享的,比如国际化的资源文件、第三方SDK,所以希望设置一个全局变量实现统一修改,而不是到每个模板配置项中进行复制粘贴。
我们进行模板编辑的运维平台,目前并没有提供跨模板共享变量的功能,但是为了方便渲染逻辑的复用,提供了模板引用的功能,也就是说一些公共模板可以被页面模板所引用。
解决思路
官方文档
EJS 功能比较简单,文档也非常简单(估计一千字左右),不到一页。
翻遍文档也没找到全局变量的使用说明。
三方示例
既然官方找不到正解,看看“民间”有没有解决方案。
网上搜索发现,比较接近的一种实现方式是在 express.js 中保存全局变量,然后在渲染模板的时候传入。
基本上就是借助Node.js服务端来实现,这种方案需要对代码进行改动,不能通过配置实现,方式并不优雅。
深入底层
回到问题本身,目的在于复用一些配置,能够在版本更新的时候做到一处修改每个模板都生效,而不是不同模板重复修改(版本号)。
在浏览器和Node.js 环境中,我们可以通过 window 或 Global 默认全局变量来传递参数。但其实在 ESM 和 CommonJS 的模块机制中还有另一种实现方式,那就是用一个模块(或配置文件)专门来保存全局变量,然后其它模块按需引用。在EJS模板上实现会遇到一个问题:模板不支持导出变量,只支持变量引入。
有没有办法把模板的变量导出来了呢?
答案当然是有的,熟悉 JavaScript 语言的同学都知道,函数调用的入参如果为对象数据类型的时候使用的是浅拷贝,也就是说函数内部可以对入参进行修改,然后函数调用方就可以得到最新的值。只是为了避免产生副作用,这种修改入参的方式在开发的时候并不推荐,很少用到。
最后的实现方式如下:
// Variable 模板
<%
// Config once, run anywhere!
var font = config.font || "font_1664786_pvgug973rb8";
config.fontURL = `//at.alicdn.com/t/${font}.js`;
......
%>
<% var config = {} %>
<%- include('Variable', {config}) %>
<script src="<%=config.fontURL%>"></script>
总结
遇到技术问题如果官方没有提供解决方案的话,如果在官方文档上找不到实现方式的话,可以在两个思路方向上进行突破:
- 横向借助第三方模。
- 纵向深入底层原理。