前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2024 年必会的 10 个 Node.js 新特性,你还不知道就太落伍了!

2024 年必会的 10 个 Node.js 新特性,你还不知道就太落伍了!

作者头像
童欧巴
发布2024-06-17 17:40:34
1470
发布2024-06-17 17:40:34
举报
文章被收录于专栏:前端食堂前端食堂

服务器端 JavaScript 运行时的领域充满了创新,如 Bun 在兼容 Node.js API 方面的进展,以及 Node.js 运行时提供的丰富标准库和运行时功能。

进入 2024 年,这篇文章提供了解 Node.js 运行时最新功能的好机会。保持更新不仅是“跟上潮流”,更是利用现代 API 的力量编写更高效、更高性能和更安全的代码。

本文将探讨 2024 年每位开发者应开始使用的 10 个现代 Node.js 运行时特性。从最新发布的 API 到 Bun 和 Deno 等新兴技术提供的亮点功能,我们将全面覆盖。

前提条件:Node.js LTS 版本

在开始探索这些现代功能之前,确保你使用的是 Node.js LTS(长期支持)版本。截至本文撰写时,最新的 Node.js LTS 版本是 v21.6.1。

检查 Node.js 版本的方法:

代码语言:javascript
复制
node --version

如果你未使用 LTS 版本,可以考虑使用 fnm 或 nvm 等版本管理器轻松切换 Node.js 版本。

Node.js 20 的新功能

接下来我们将介绍 Node.js 最近版本的新特性。有些已稳定,有些仍在实验阶段,还有些早已有支持,但你可能还未听说过。

我们将讨论以下主题:

  • Node.js 测试运行器
  • Node.js 原生 Mock
  • Node.js 原生测试覆盖率
  • Node.js 监视模式
  • Node.js corepack
  • Node.js .env 加载器
  • 用于 __dirname 和 __file 的 Node.js import.meta.file
  • Node.js 原生定时器 Promise
  • Node.js 权限模块
  • Node.js 策略模块

Node.js 原生测试运行器

在 Node.js 引入原生测试运行器之前,我们通常使用 node-tap、jest、mocha 或 vitest 等流行选项。

现在,我们来学习如何在开发流程中使用 Node.js 原生测试运行器。首先,需要在测试文件中导入 Node.js 的测试模块,如下所示:

代码语言:javascript
复制
import { test } from 'node:test';

接下来,我们将逐步介绍如何使用 Node.js 测试运行器。

使用 node:test 运行单个测试

要创建一个测试,可以使用 test 函数,传入测试名称和回调函数。在回调函数中定义你的测试逻辑。

代码语言:javascript
复制
import { test } from "node:test";
import assert from "node:assert";
import { add } from "../src/math.js";

test("should add two numbers", () => {
  const result = add(1, 2);
  assert.strictEqual(result, 3);
});

test("should fail to add strings", () => {
  assert.throws(() => {
    add("1", "2");
  });
});

运行该测试,使用 node --test 命令并跟上测试文件名:

代码语言:javascript
复制
node --test tests/math.test.js

Node.js 测试运行器可以自动检测并运行项目中的测试文件。按惯例,这些文件应以 .test.js 结尾,但不严格限定。

如果省略测试文件参数,Node.js 测试运行器会使用一些启发式方法和 glob 模式匹配查找测试文件,例如 test/ 或 tests/ 文件夹中的所有文件或以 test- 前缀或 .test 后缀的文件。

例如,glob 匹配测试文件:

代码语言:javascript
复制
node --test '**/*.test.js'

使用 node:assert 进行测试断言

Node.js 测试运行器支持通过内置的 assert 模块进行断言。可以使用 assert.strictEqual 等方法来验证测试结果。

代码语言:javascript
复制
import assert from 'node:assert';

test('Test 1', () => {
  assert.strictEqual(1 + 1, 2);
});

测试套件和测试钩子与原生 Node.js 测试运行器

describe 函数用于将相关测试分组为测试套件,使测试更有条理、易于管理。

代码语言:javascript
复制
import { test, describe } from "node:test";

describe('My Test Suite', () => {
  test('Test 1', () => {
    // Test 1 logic
  });

  test('Test 2', () => {
    // Test 2 logic
  });
});

测试钩子是在测试前或测试后运行的特殊函数,适用于设置或清理测试环境。

代码语言:javascript
复制
test.beforeEach(() => {
  // Runs before each test
});

test.afterEach(() => {
  // Runs after each test
});

你还可以使用 test.skip 函数跳过某个测试,这在暂时忽略特定测试时很有用。

代码语言:javascript
复制
test.skip('My skipped test', () => {
  // Test logic
});

此外,Node.js 测试运行器提供不同的报告器,能够以各种方式显示测试结果。可以使用 --reporter 选项指定报告器。

代码语言:javascript
复制
node --test --test-reporter=tap

你应该放弃 Jest 吗?

尽管 Jest 在 Node.js 社区中很受欢迎,但它的某些缺点使得原生 Node.js 测试运行器更具吸引力。

安装 Jest 即使只是开发依赖,也会引入 277 个不同许可证的间接依赖,包括 MIT、Apache-2.0、CC-BY-4.0 和一个未知许可证。你知道吗?

  • Jest 修改全局对象,可能导致测试出现意外行为。
  • instanceof 操作符在 Jest 中不总是按预期工作。
  • Jest 增加了项目的依赖负担,使得维护第三方依赖和管理安全问题更加困难。
  • 由于额外开销,Jest 可能比原生 Node.js 测试运行器更慢。

Node.js 测试运行器的其他优秀功能包括子测试和并发测试。子测试允许通过 context.test 创建嵌套测试,并发测试则可通过在 describe() 测试套件中传入 concurrency: true 实现,适合熟练使用并避免竞争条件的情况。

什么是测试运行器?

测试运行器是一种软件工具,帮助开发人员管理和执行自动化测试。Node.js 测试运行器是专为 Node.js 设计的框架,提供了丰富的环境,用于编写和运行 Node.js 应用程序的测试。

Node.js 原生 Mock

Mock 是一种开发人员用来隔离代码进行测试的策略。Node.js 运行时引入了原生 Mock 功能,开发人员需要理解并有效使用。

你可能使用过其他测试框架的 Mock 功能,如 Jest 的 jest.spyOn 或 mockResolvedValueOnce。在需要避免在测试中运行实际代码(如 HTTP 请求或文件系统 API)时,它们非常有用,可以用存根和模拟来替代这些操作,并在稍后进行检查。

与 watch 和 coverage 功能不同,mock 并未被声明为实验性功能,但由于它是 Node.js 18 中引入的新功能,可能会有更多变化。

使用 import { mock } from 'node:test' 进行 Node.js 原生 Mock

我们来看一个实际例子,如何使用 Node.js 原生 Mock 功能。Node.js 20 LTS 中测试运行器和模块模拟功能已经作为稳定功能提供。

我们将使用一个名为 dotenv.js 的实用模块,该模块从 .env 文件加载环境变量。还将用一个测试文件 dotenv.test.js 来测试 dotenv.js 模块。

以下是我们自己的 dotenv 模块:

代码语言:javascript
复制
// dotenv.js
import fs from "node:fs/promises";

export async function loadEnv(path = ".env") {
  const rawDataEnv = await fs.readFile(path, "utf8");
  const env = {};
  rawDataEnv.split("\n").forEach((line) => {
    const [key, value] = line.split("=");
    env[key] = value;
  });

  return env;
}

在 dotenv.js 文件中,我们有一个异步函数 loadEnv,它使用 fs.readFile 方法读取文件并将内容拆分为键值对。这个函数使用了 Node.js 原生文件系统 API fs。

现在,我们看看如何使用 Node.js 的原生模拟功能来测试这个函数。

代码语言:javascript
复制
// dotenv.test.js
import { describe, test, mock } from "node:test";
import assert from "node:assert";
import fs from "node:fs/promises";

import { loadEnv } from "../src/dotenv.js";

describe("dotenv test suite", () => {
  test("should load env file", async () => {
    const mockImplementation = async (path) => {
      return "PORT=3000\n";
    };
    const mockedReadFile = mock.method(fs, "readFile", mockImplementation);

    const env = await loadEnv(".env");

    assert.strictEqual(env.PORT, "3000");
    assert.strictEqual(mockedReadFile.mock.calls.length, 1);
  });
});

在测试文件中,我们从 node:test 导入 mock 方法,用它创建 fs.readFile 的模拟实现。无论传入的文件路径是什么,模拟实现都返回字符串 "PORT=3000\n"。

然后调用 loadEnv 函数,并使用 assert 模块检查两点:

  1. 返回的对象包含值为 "3000" 的 PORT 属性。
  2. fs.readFile 方法被调用了一次。

通过 Node.js 的原生模拟功能,我们可以有效地将 loadEnv 函数与文件系统隔离,进行独立测试。Node.js 20 的模拟功能还支持模拟定时器。

什么是 Mock?

在软件测试中,Mock 是用人工功能替代特定模块的实际功能。其主要目的是将测试单元与外部依赖隔离,确保测试只验证单元功能,而非依赖。Mock 还允许模拟各种场景,如依赖错误,这些错误在真实环境中可能难以一致重现。

Node.js 原生测试覆盖率

什么是测试覆盖率?

测试覆盖率是软件测试中的度量标准,帮助开发人员了解应用程序源代码的测试程度。它揭示了未测试的代码区域,使开发人员能够识别潜在弱点。

为什么测试覆盖率很重要?因为它通过减少错误和防止回归确保软件质量,并提供对测试有效性的见解,帮助开发更强大、可靠和安全的应用程序。

利用原生 Node.js 测试覆盖率

从版本 20 开始,Node.js 运行时包括原生测试覆盖率功能。但需要注意的是,原生 Node.js 测试覆盖率目前标记为实验性功能,未来可能会有所变化。

要使用原生 Node.js 测试覆盖率,需要使用 --experimental-coverage 命令行标志。以下是如何在 package.json 的 scripts 字段中添加 test:coverage 条目的示例:

代码语言:javascript
复制
{
  "scripts": {
    "test": "node --test ./tests",
    "test:coverage": "node --experimental-coverage --test ./tests"
  }
}

在上例中,test:coverage 脚本使用 --experimental-coverage 标志在测试执行期间生成覆盖率数据。

运行 npm run test:coverage 后,您应会看到类似的输出:

代码语言:javascript
复制
ℹ tests 7
ℹ suites 4
ℹ pass 5
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 1
ℹ duration_ms 84.018917
ℹ start of coverage report
ℹ ---------------------------------------------------------------------
ℹ file                 | line % | branch % | funcs % | uncovered lines
ℹ ---------------------------------------------------------------------
ℹ src/dotenv.js        | 100.00 |   100.00 |  100.00 | 
ℹ src/math.js          | 100.00 |   100.00 |  100.00 | 
ℹ tests/dotenv.test.js | 100.00 |   100.00 |  100.00 | 
ℹ tests/math.test.js   |  94.64 |   100.00 |   91.67 | 24-26
ℹ ---------------------------------------------------------------------
ℹ all files            |  96.74 |   100.00 |   94.44 |
ℹ ---------------------------------------------------------------------
ℹ end of coverage report

报告显示测试覆盖的语句、分支、函数和行的百分比。

Node.js 原生测试覆盖率是提高应用质量的强大工具。尽管目前为实验性功能,但它能提供测试覆盖率的宝贵见解并指导测试。理解并利用此功能可确保代码的健壮、可靠和安全。

Node.js 监视模式

Node.js 监视模式是一项强大的开发者功能,能实时监控文件更改并自动重新执行脚本。

在深入了解 Node.js 的原生监视功能前,值得提到的是 nodemon[1],这是早期版本中常用的工具。Nodemon 是一个命令行工具,当检测到文件变化时会重启 Node.js 应用程序。

代码语言:javascript
复制
npm install -g nodemon
nodemon

此功能对开发过程非常有用,能节省时间并提高效率,无需每次文件修改后手动重启。

Node.js 现已内置实现此功能,无需额外安装第三方依赖。但需注意,Node.js 的原生监视模式仍是实验性功能,未来可能有所变化。确保使用支持此功能的 Node.js 版本。

使用 Node.js 20 原生监视功能

Node.js 20 引入了使用 --watch 命令行标志的原生文件监视功能。这一功能简单易用,还支持 glob 模式以满足复杂的文件监视需求。

在命令行中添加 --watch 标志即可使用:

代码语言:javascript
复制
node --watch app.js

使用 glob 模式时,可以通过 --watch 标志和特定模式监视多个文件或目录:

代码语言:javascript
复制
node --watch 'lib/**/*.js' app.js

--watch 标志还可与 --test 结合使用,在测试文件更改时自动重新运行测试:

代码语言:javascript
复制
node --watch --test '**/*.test.js'

这种组合能显著加快测试驱动开发 (TDD) 过程。

需要注意,Node.js 20 的监视模式仍为实验性功能,可能存在不稳定或未优化的情况。

实践中,使用 --watch 标志时可能会遇到一些问题。

Node.js Corepack

Node.js Corepack 是一个有趣的功能,值得一探。它在 Node.js 16 中引入,仍是实验性功能。让我们看看它提供了什么以及如何在 JavaScript 项目中利用它。

什么是 Corepack?

Corepack 是一个零运行时依赖项目,连接 Node.js 项目与其使用的包管理器。安装后,它提供了一个 corepack 程序,帮助开发者确保项目使用正确的包管理器,无需全局安装。

为什么使用 Corepack?

JavaScript 开发中,多个项目常有不同的包管理器偏好,如 pnpm 和 yarn,这会导致冲突和不一致。Corepack 解决了这个问题,使每个项目无缝使用其首选的包管理器。

此外,Corepack 提供项目与全局系统的隔离,确保项目在全局包升级或移除时依然可运行,提高项目一致性和可靠性。

安装和使用 Corepack

安装 Corepack 非常简单。自 Node.js 16 起捆绑,您只需安装或升级至该版本或更高版本的 Node.js。

安装后,可以在 package.json 文件中定义项目的包管理器:

代码语言:javascript
复制
{
  "packageManager": "yarn@2.4.1"
}

然后,您可以在项目中这样使用 Corepack:

代码语言:javascript
复制
corepack enable

在项目目录中输入 yarn,如果未安装 Yarn,Corepack 将自动检测并安装正确版本。

这确保项目依赖项使用 Yarn 版本 2.4.1 安装,而不管系统上全局 Yarn 版本。

如果要全局安装 Yarn 或使用特定版本,可以运行:

代码语言:javascript
复制
corepack install --global yarn@stable

Corepack:仍是实验性功能

尽管在 Node.js 16 中引入,但 Corepack 仍为实验性功能。这意味着它预计能正常工作,但仍在积极开发中,未来可能有变化。

尽管如此,Corepack 易于安装,使用简单,为项目提供了额外的可靠性。它是一个值得探索并整合到开发流程中的功能。

Node.js .env 加载器

应用配置非常重要,作为 Node.js 开发者,您可能需要管理 API 凭证、服务器端口号或数据库配置。

开发人员需要在不更改源码的情况下,为不同环境提供不同设置。在 Node.js 应用中,常用的方法是使用 .env 文件存储环境变量。

dotenv npm 包

在 Node.js 引入原生 .env 文件加载支持之前,开发者主要使用 dotenv npm 包。dotenv 将 .env 文件中的环境变量加载到 process.env 中,使其在整个应用中可用。

下面是 dotenv 包的典型用法:

代码语言:javascript
复制
require('dotenv').config();

console.log(process.env.MY_VARIABLE);

这很好用,但需要为项目添加额外依赖。随着原生 .env 加载器的引入,现在无需外部包即可加载环境变量。

Node.js 引入加载 .env 文件的原生支持

从 Node.js 20 开始,运行时包括一个内置功能,可从 .env 文件加载环境变量。尽管该功能仍在开发中,但已成为开发者的福音。

要加载 .env 文件,可以在启动 Node.js 应用时使用 --env-file CLI 标志。该标志指定要加载的 .env 文件路径。

代码语言:javascript
复制
node --env-file=./.env index.js

这会将指定 .env 文件中的环境变量加载到 process.env 中,变量将像之前一样在您的应用中可用。

加载多个 .env 文件

Node.js .env 加载器还支持加载多个 .env 文件。当您有不同环境(如开发、测试、生产)的环境变量时,这非常有用。

可以通过多个 --env-file 标志加载多个文件。文件按指定顺序加载,后面的文件变量会覆盖前面的。

示例如下:

代码语言:javascript
复制
node --env-file=./.env.default --env-file=./.env.development index.js

在此示例中,./.env.default 包含默认变量,./.env.development 包含开发环境的变量。./.env.development 中的变量若也存在于 ./.env.default 中,将覆盖 ./.env.default 中的值。

Node.js 中加载 .env 文件的原生支持是对开发者的重大改进。它简化了配置管理,无需额外包。开始在 Node.js 应用中使用 --env-file CLI 标志,体验其便利性。

Node.js 对 __dirname 和 __file 的 import.meta 支持

如果您习惯于 Node.js 的 CommonJS 模块,使用 __filename__dirname 获取文件目录名和路径。然而,直到最近,这些在 ESM 中并不容易获得,需要以下代码来提取 __dirname

代码语言:javascript
复制
import url from 'url'
import path from 'path'
const dirname = path.dirname(url.fileURLToPath(import.meta.url))

如果你是 Matteo Collina 的粉丝,你可能使用过他的 desm[2]npm 包。

Node.js 不断发展,为开发者提供更高效的文件和路径操作方法。在 Node.js v20.11.0 和 Node.js v21.2.0 中引入了 import.meta.dirname 和 import.meta.filename 的内置支持,这对开发者来说是个重大利好。

使用 Node.js import.meta.filename 和 import.meta.dirname

幸运的是,随着 import.meta.filename 和 import.meta.dirname 的引入,这个过程变得简单多了。让我们看个例子,如何使用这些新特性加载配置文件。

假设有一个 YAML 配置文件与您的 JavaScript 文件在同一目录下,您需要加载它。操作如下:

代码语言:javascript
复制
import fs from 'fs';

const { dirname: __dirname, filename: __filename } = import.meta;
const projectSetup = fs.readFileSync(`${__dirname}/setup.yml`, "utf8");

console.log(projectSetup);

在这个示例中,我们使用 import.meta.dirname 获取当前文件的目录名,并将其赋值给 __dirname 变量,以便于遵循 CommonJS 的编码约定。

Node.js 原生定时器 Promise

Node.js 是一个基于 Chrome V8 JavaScript 引擎的流行 JavaScript 运行时,通过不断更新和新功能简化开发者的工作。

尽管 Node.js 早在 v15 就引入了 Promise 语法的原生定时器支持,但我承认并未经常使用。

JavaScript 的 setTimeout() 和 setInterval() 定时器:简要回顾

在深入了解原生定时器 Promise 之前,让我们简要回顾一下 JavaScript 的 setTimeout() 和 setInterval() 定时器。

setTimeout() 是一个 JavaScript 函数,在定时器到期后执行指定的函数或代码。

代码语言:javascript
复制
setTimeout(function(){ 
    console.log("Hello World!"); 
}, 3000);

上例中,“Hello World!” 将在 3 秒(3000 毫秒)后打印到控制台。

而 setInterval() 会反复执行指定函数,每次调用之间有延迟。

代码语言:javascript
复制
setInterval(function(){ 
    console.log("Hello again!"); 
}, 2000);

上例中,“Hello again!” 将每 2 秒(2000 毫秒)打印到控制台。

旧方法:使用 Promise 包装 setTimeout()

过去,开发者常需将 setTimeout() 函数包装为 Promise 以异步使用,从而在 async/await 中使用 setTimeout()。

以下是一个示例:

代码语言:javascript
复制
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later...');
}

demo();

这会打印“Taking a break...”,等待两秒钟后打印“两秒钟后...”。

虽然这能实现功能,但增加了不必要的复杂性。

Node.js 原生定时器 Promise:更简单的方法

使用 Node.js 原生定时器 Promise,不再需要将 setTimeout() 包装在 Promise 中。可以直接在 async/await 中使用 setTimeout(),使代码更简洁、更易读和维护。以下是使用 Node.js 原生定时器 Promise 的示例:

代码语言:javascript
复制
const {
  setTimeout,
} = require('node:timers/promises');

setTimeout(2000, 'Two seconds later...').then((res) => {
  console.log(res);  
});

console.log('Taking a break...');

在上面的代码中,我们从 node:timers/promises 导入 setTimeout(),然后直接在 async/await 中使用它。它会打印“Taking a break...”,等待两秒钟后打印“两秒钟后...”。

这大大简化了异步编程,使代码更易读、易写和维护。

Node.js 权限模型

Rafael Gonzaga 现在是 Node.js TSC 的成员,他重新启动了 Node.js 权限模块的工作。类似于 Deno,这个模块提供了一组可配置的进程级资源限制。

在供应链安全、恶意 npm 包和其他安全风险的背景下,管理和控制 Node.js 应用程序的资源访问变得越来越重要。

为此,Node.js 引入了一个实验性功能,称为权限模块,用于管理应用程序中的资源权限。此功能通过 --experimental-permission 命令行标志启用。

Node.js 资源权限模型

Node.js 的权限模型为管理文件系统、网络、环境变量、工作线程等资源的访问提供了抽象。当需要限制应用程序某部分的资源访问时,该功能尤为有用。

常见的资源限制包括:

  • 使用 --allow-fs-read=* 和 --allow-fs-write=* 进行文件系统读写,可指定目录和文件路径,且可重复标志提供多个资源
  • 使用 --allow-child-process 调用子进程
  • 使用 --allow-worker 调用工作线程

Node.js 权限模型还提供运行时 API process.permission.has(resource, value) 用于查询特定访问权限。

尝试访问不允许的资源时,如读取 .env 文件,会出现 ERR_ACCESS_DENIED 错误:

代码语言:javascript
复制
> start:protected
> node --env-file=.env --experimental-permission server.js

node:internal/modules/cjs/loader:197
  const result = internalModuleStat(filename);
                 ^

Error: Access to this API has been restricted
    at stat (node:internal/modules/cjs/loader:197:18)
    at Module._findPath (node:internal/modules/cjs/loader:682:16)
    at resolveMainPath (node:internal/modules/run_main:28:23)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:24)
    at node:internal/main/run_main_module:28:49 {
  code: 'ERR_ACCESS_DENIED',
  permission: 'FileSystemRead',
  resource: '/Users/lirantal/repos/modern-nodejs-runtime-features-2024/server.js'
}

Node.js v21.6.1

Node.js 权限模型示例

假设您有一个处理文件上传的 Node.js 应用程序,希望限制它只能访问存储上传文件的特定目录。

启动 Node.js 应用时使用 --experimental-permission 标志启用实验性权限功能。

代码语言:javascript
复制
node --experimental-permission ./app.js

还需特别允许应用读取 .env 和 setup.yml 两个受信任的文件,需更新为:

代码语言:javascript
复制
node --experimental-permission --allow-fs-write=/tmp/uploads --allow-fs-read=.env --allow-fs-read=setup.yml ./app.js

这样,若应用尝试在提供的上传路径外写文件,将会报错并停止。

请看以下代码示例,通过 try/catch 包装资源访问,以及使用 Node.js 权限运行时 API 确保访问不抛出错误:

代码语言:javascript
复制
const { dirname: __dirname, filename: __filename } = import.meta;
// @TODO to avoid the Node.js resource permission issue you should update
// the path to be `setup.yml` in the current directory and not `../setup.yml`.
// the outside path for setup.yml was only changed in the source code to
// show you how Node.js resource permission module will halt if trying to access
// something outside the current directory.
const filePath = `${__dirname}/../setup.yml`;
try {
  const projectSetup = fs.readFileSync(filePath, "utf8");
  // @TODO do something with projectSetup if you want to
} catch (error) {
  console.error(error.code);
}
// @TODO or consider using the permissions runtime API check:
if (!process.permission.has("read", filePath)) {
  console.error("no permissions to read file at", filePath);
}

注意,Node.js 的权限功能仍是实验性的,可能会有变化。

关于权限和生产级安全规范,更多信息请查阅 Snyk 的以下博客文章:

10 best practices to containerize Node.js web applications with Docker[3]

Choosing the best Node.js Docker image[4]

这些文章提供了构建 Node.js Web 应用安全容器镜像的综合指南,对开发安全的 Node.js 应用至关重要。

Node.js 策略模块

Node.js 策略模块是一项安全功能,旨在防止恶意代码在应用中加载和执行。虽然它不追踪加载代码的来源,但为潜在威胁提供了有效防御。

策略模块使用 --experimental-policy CLI 标志启用基于策略的代码加载。该标志以策略清单文件(JSON 格式)为参数。例如,--experimental-policy=policy.json。

策略清单文件包含 Node.js 加载模块时遵循的策略,提供了一种有效的方式控制应用加载的代码。

实现 Node.js 策略模块:分步指南

我们通过一个简单示例演示如何使用 Node.js 策略模块:

  1. 创建一个策略文件,该文件为 JSON 格式,指定应用的加载策略。命名为 policy.json。

例如:

代码语言:javascript
复制
{
  "resources": {
    "./moduleA.js": {
      "integrity": "sha384-xxxxx"
    },
    "./moduleB.js": {
      "integrity": "sha384-yyyyy"
    }
  }
}

该策略文件指定 moduleA.js 和 moduleB.js 需具有特定的完整性值才能被加载。

为所有直接和传递依赖生成策略文件并不简单。Bradley Meck 创建了 node-policy npm 包,提供了自动生成策略文件的 CLI。

  1. 使用 --experimental-policy 标志运行 Node.js 应用:
代码语言:javascript
复制
node --experimental-policy=policy.json app.js

该命令指示 Node.js 在加载 app.js 中的模块时遵循 policy.json 中的策略。

  1. 为防止策略文件被篡改,可使用 --policy-integrity 标志提供策略文件的完整性值:
代码语言:javascript
复制
node --experimental-policy=policy.json --policy-integrity="sha384-zzzzz" app.js

该命令确保策略文件在磁盘上被更改时保持完整性。

Node.js 完整性策略的注意事项

Node.js 运行时没有内置功能生成或管理策略文件,这可能会带来一些困难,如管理生产与开发环境的不同策略及动态模块导入。

另一个注意事项是,如果当前已有恶意 npm 包,生成模块完整性策略文件已经为时过晚。

建议关注该领域的更新,逐步尝试采用这一功能。

更多信息可查看关于 Node.js 完整性策略[5]的文章,提供更详细的分步教程。

总结

浏览了 2024 年应使用的现代 Node.js 运行时功能后,明显这些功能旨在简化开发流程、提升应用性能和增强安全性。这些功能不仅是趋势,还能重塑 Node.js 开发方式。

参考资料

[1]

nodemon: https://snyk.io/advisor/npm-package/nodemon

[2]

desm: https://snyk.io/advisor/npm-package/desm

[3]

10 best practices to containerize Node.js web applications with Docker: https://snyk.io/blog/10-best-practices-to-containerize-node-js-web-applications-with-docker/

[4]

Choosing the best Node.js Docker image: https://snyk.io/blog/choosing-the-best-node-js-docker-image/

[5]

Node.js 完整性策略: https://snyk.io/blog/introducing-experimental-integrity-policies-to-node-js/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端食堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前提条件:Node.js LTS 版本
  • Node.js 20 的新功能
  • Node.js 原生测试运行器
    • 使用 node:test 运行单个测试
      • 使用 node:assert 进行测试断言
        • 测试套件和测试钩子与原生 Node.js 测试运行器
          • 你应该放弃 Jest 吗?
            • 什么是测试运行器?
            • Node.js 原生 Mock
              • 使用 import { mock } from 'node:test' 进行 Node.js 原生 Mock
                • 什么是 Mock?
                • Node.js 原生测试覆盖率
                  • 什么是测试覆盖率?
                    • 利用原生 Node.js 测试覆盖率
                    • Node.js 监视模式
                    • 使用 Node.js 20 原生监视功能
                    • Node.js Corepack
                      • 什么是 Corepack?
                        • 为什么使用 Corepack?
                          • 安装和使用 Corepack
                            • Corepack:仍是实验性功能
                            • Node.js .env 加载器
                              • dotenv npm 包
                              • Node.js 引入加载 .env 文件的原生支持
                              • 加载多个 .env 文件
                                • Node.js 对 __dirname 和 __file 的 import.meta 支持
                                  • 使用 Node.js import.meta.filename 和 import.meta.dirname
                                  • Node.js 原生定时器 Promise
                                    • JavaScript 的 setTimeout() 和 setInterval() 定时器:简要回顾
                                      • 旧方法:使用 Promise 包装 setTimeout()
                                        • Node.js 原生定时器 Promise:更简单的方法
                                        • Node.js 权限模型
                                          • Node.js 资源权限模型
                                            • Node.js 权限模型示例
                                            • Node.js 策略模块
                                              • 实现 Node.js 策略模块:分步指南
                                                • Node.js 完整性策略的注意事项
                                                • 总结
                                                相关产品与服务
                                                腾讯云服务器利旧
                                                云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                                                领券
                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档