首页 热门资讯文章正文

2025 年 Nginx 官宣放弃 njs ,全面拥抱 QuickJS !

热门资讯 2025年07月28日 00:14 1 admin

家好,很高兴又见面了,我是"高级前端‬进阶‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。

2025 年 Nginx 官宣放弃 njs ,全面拥抱 QuickJS !

1.njs 宣布退出历史舞台

2025 年 7 月 10 日,njs 宣布自 v0.9.1 版本起引入了 QuickJS 引擎支持,其不仅兼容 ES2023,还为 NGINX 环境中的 JavaScript 脚本编写开辟了新的可能性。

按照官方的说法,njs 花费了大量时间维护和扩展为 Nginx 定制的 JavaScript 引擎,而没有更多精力专注在 JavaScript 和 NGINX 之间实现无缝集成的重要事项上。随着 Web 的发展以及开发者对现代 JavaScript 特性的依赖,局限性也愈发凸显:

  • 语言本身的限制:ES5 基础架构以及有限的 ES6 扩展,开发者无法利用现代 JavaScript 模式或采用新语言标准的当代库生态
  • 开发重点:维护定制的 JavaScript 引擎需要大量的资源,只能将有限的资源用来提升 NGINX 集成能力、优化性能和新功能
  • 生态兼容性:许多现有的 JavaScript 库和工具都期望获得更全面的 ES6+ 支持,从而给希望在其 NGINX 配置中重用成熟解决方案的开发者带来了障碍

给开发者代码的弊端就是:njs 最初的设计目标与 JavaScript 开发社区不断变化的需求之间存在矛盾。

2. 为什么 Nginx 团队选择 QuickJS

njs 团队做了最新的战略决策,宣布集成 QuickJS 作为 Nginx 替代的 JavaScript 引擎,同时保留现有的 njs 引擎以实现向后兼容。

引入轻量级、可嵌入的 QuickJS 引擎具有以下几个显著优势:

  • 完全兼容 ES2023 :支持完整的 ES2023 规范,包括 模块、异步生成器、Proxy 代理和 BigInt 等现代 JavaScript 开发的标准功能
import divide, {add, multiply} from "./mathUtils.js";import {user, greet} from "./user.js";// 模块化以前不支持async function* myAsyncGenerator() {  yield value;}// 异步生成器以前不支持const proxy = new Proxy(target, handler);// Proxy 代理以前不支持const a = 123n;const bigNum = 9007199254740991n;const b = BigInt(123);const c = BigInt("9007199254740991");const negative = -456n;// BigInt 以前也不支持
  • 体积优势 : 尽管 QuickJS 功能齐全,但体积非常小巧且易于嵌入,只需几个 C 文件,且无需任何外部依赖项。对于一个简单的程序来说,完整的 x86 代码占用 367 KB。
  • 社区活跃 : 作为一个拥有更广泛社区参与的开源项目,QuickJS 受益于各种用例的持续开发和测试,从而减轻了 njs 团队的维护负担。同时,njs 团队还实现了 QuickJS 插入式替代,即现有 njs 脚本只需进行很少的修改或无需修改即可运行。

目前 QuickJS 在 Github 通过 MIT 协议开源,有超过 10k 的 star、1k 的 fork、妥妥的前端顶级开源项目。

3. 如何在 Nginx 中使用 QuickJS

3.1 如何自定义 QuickJS 构建

大多数 Linux 发行版都需要安装一些依赖项才能构建 NGINX 和 NGINX JavaScript。以下说明针对 apt 包管理器,该管理器在大多数 Ubuntu/Debian 发行版及其衍生版本中均可广泛使用。

sudo apt install gcc make// 安装编译器和 make 实用程序sudo apt install libpcre3-dev zlib1g-dev libssl-dev libxml2-dev libxslt-dev// 安装依赖

如果要使用 QuickJS 进行构建,开发者还需要构建 QuickJS 库:

git clone https://github.com/bellard/quickjscd quickjsCFLAGS='-fPIC' make libquickjs.a

下面使用 --with-cc-opt= 和 --with-ld-opt= 选项提供库路径:

auto/configure --add-dynamic-module=<NJS_SRC_ROOT_DIR>/nginx \    --with-cc-opt="-I<QUICKJS_SRC_ROOT_DIR>" \    --with-ld-opt="-L<QUICKJS_SRC_ROOT_DIR>"

3.2 如何在 Nginx 中使用 QuickJS

切换到 QuickJS 引擎非常简单,开发者只需一个配置指令即可。js_engine 指令适用于 HTTP 和流上下文,可让开发者指定要使用的 JavaScript 引擎。

下面是基础的 HTTP 配置:

// nginx.conf 配置load_module modules/ngx_http_js_module.so;events {}http {    js_import main from js/main.js;    // 引入指定的文件    server {        listen 8000;        location /njs {            js_content main.handler;        }        location /qjs {            js_engine qjs;            js_content main.handler;        }    }} // js/main.js 文件function handler(r) {    r.return(200, `Hello from ${njs.engine}`);}export default {handler};

下面是一个更复杂的示例,展示了 QuickJS 提供的现代 JavaScript 功能:

// nginx.conf 配置信息http {    js_engine qjs;    js_import analytics from js/analytics.js;    // 引入指定的文件    server {        listen 8000;        location /analytics {            js_content analytics.processRequest;        }    }}

下面是 js/analytics.js 文件的内容:

class RequestAnalytics {  // 使用生成器函数处理 HTTP 头部信息  *getHeaderMetrics(headers) {    for (const [key, value] of Object.entries(headers)) {      // 详细的头部信息      yield {        header: key.toLowerCase(),        size: key.length + value.length,        type: key.startsWith("x-") ? "custom" : "standard",      };    }  }  processRequest(r) {    // 默认解构    const {method = "GET", uri = "/", httpVersion = "1.0"} = r;    const headerStats = [];    for (const metric of this.getHeaderMetrics(r.headersIn)) {      headerStats.push(metric);    }    const timestamp = BigInt(Date.now());    // BigInt 保持详细时间    const headerCount = headerStats.length;    const customHeaders = headerStats.filter(      ({type}) => type === "custom"    ).length;    // 返回数据给客户端    r.return(      200,      JSON.stringify(        {          message: `Request processed at ${timestamp}`,          stats: {headerCount, customHeaders},          serverInfo: `${method} ${uri} HTTP/${httpVersion}`,        },        null,        2      )    );  }}const analytics = new RequestAnalytics();export default {processRequest: (r) => analytics.processRequest(r) };

3.3 在 Nginx 中使用 QuickJS 的权衡

在 Nginx 中引入 QuickJS 后,在实例创建、长时间运行的脚本、内存管理、上下文重用优化等方方面面都需要综合考量,例如:性能和内存占用之间的权衡:

  • 更高的上下文重用率(默认值:128):由于上下文创建开销减少,性能更佳,但内存消耗更高
  • 更低的上下文重用率(或使用 js_context_reuse 0 禁用):内存占用更低,但由于频繁创建上下文,延迟会增加

参考资料

https://github.com/nginx/njs

https://blog.nginx.org/blog/quickjs-engine-support-for-njs

https://github.com/bellard/quickjs

https://javascript.plainenglish.io/how-javascript-became-the-super-glue-inside-nginx-2ce57cb09686

发表评论

泰日号Copyright Your WebSite.Some Rights Reserved. 网站地图 备案号:川ICP备66666666号 Z-BlogPHP强力驱动