نسخه 20 Node.js در 18 آوریل 2023 منتشر شد. این نسخه به برخی از مسائل و انتقاداتی که قبلاً توسط Deno و Bun "حل" شده بودند، می پردازد، از جمله یک Permission Model و یک Native Test Runner پایدار. این مقاله به بررسی گزینههای جدید در دسترس توسعهدهندگان با استفاده از پرکاربردترین runtime جاوا اسکریپت میپردازد.
برنامه زمانبندی انتشار Node.js
Node.js یک برنامه شش ماهه انتشار دارد:
- نسخه های آوریل با شماره زوج (14، 16، 18، و غیره) پایدار هستند و به مدت سه سال بروز رسانی های پشتیبانی طولانی مدت (LTS) را دریافت می کنند.
- نسخه های اکتبر با شماره فرد (15، 17، 19، و غیره) بیشتر آزمایشی هستند و بروز رسانی آن ها گاها پس از یک سال به پایان می رسند.
Node.js 20 دارای ویژگی های جدید زیر می باشد که می خواهیم آن ها را تک به تک بررسی کنیم.
Permission Model جدید
اجرای node somescript.js بدون خطر نیست. یک اسکریپت میتواند هر کاری انجام دهد: حذف فایلهای ضروری، ارسال دادههای پرایوت به یک سرور، یا اجرای یک ماینر ارز دیجیتال در فرآیند child . تضمین اینکه کد شما چیزی را خراب نمی کند دشوار است: آیا می توانید مطمئن باشید که همه ماژول ها و وابستگی های آنها ایمن هستند؟
Permission Model در Node.js کاری را که اسکریپت می تواند انجام دهد را محدود می کند. برای استفاده از آن، دستور experimental-permission-- در cmd Node به دنبال آن اضافه کنید:
allow-fs-read--برای دادن دسترسی خواندن به فایل ها. می توانید دسترسی خواندن را به موارد زیر محدود کنید:
- دایرکتوری های خاص:
/allow-fs-read=/tmp-- - فایل های خاص:
allow-fs-read=/home/me/data.json-- - یا با یک الگوی فایل عام:
allow-fs-read=/home/me/*.json--
allow-fs-write--برای دادن دسترسی نوشتن به فایل هایی با دایرکتوری، فایل، یا الگوهای عام یکسان.allow-child-process--اجازه می دهد تا child processes مانند اجرای اسکریپت های دیگری که ممکن است به زبان های دیگر نوشته شده باشند.allow-worker--اجازه دهد تا worker threads، که کد Node.js را موازی با رشته پردازش اصلی اجرا می کنند.
در مثال زیر، somescript.js میتواند فایلهای موجود در دایرکتوری /home/me/data/ را بخواند:
node --experimental-permission --allow-fs-read=/home/me/data/ somescript.js
هر تلاشی برای نوشتن یک فایل، اجرای فرآیند دیگر یا راهاندازی یک web worker خطای ERR_ACCESS_DENIED را ایجاد میکند.
شما می توانید مجوزهای داخل برنامه خود را با استفاده از آبجکت new process.permission بررسی کنید. به عنوان مثال، در اینجا نحوه بررسی اینکه آیا اسکریپت می تواند فایل بنویسد، آمده است:
process.permission.has('fs.write');
در اینجا نحوه بررسی اینکه آیا اسکریپت می تواند در یک فایل خاص بنویسد یا نه، آمده است:
if ( !process.permission.has('fs.write', '/home/me/mydata.json') ) {
console.error('Cannot write to file');
}
مدیریت مجوز جاوا اسکریپت برای اولین بار توسط Deno معرفی شد که کنترل دقیقی بر دسترسی به فایل ها، متغیرهای environment، اطلاعات سیستم عامل، اندازه گیری زمان، شبکه، کتابخانه های بارگذاری شده پویا و فرآیندهای child ارائه می دهد. Node.js به طور پیش فرض ناامن است مگر اینکه دستور experimental-permission-- را اضافه کنید. این کمتر تاثیر دارد، اما تضمین می کند که اسکریپت های موجود بدون تغییر اجرا می شوند.
Native Test Runner
از لحاظ تاریخی، Node.js حداقل زمان اجرا داشته است، بنابراین توسعه دهندگان می توانند ابزارها و ماژول های مورد نیاز خود را انتخاب کنند. اجرای تست کد نیاز به یک ماژول شخص ثالث مانند Mocha، AVA یا Jest دارد. در حالی که این منجر به انتخابهای زیادی شد، گرفتن بهترین تصمیم ممکن است دشوار باشد، و عوض کردن ابزار ممکن است آسان نباشد.
سایر runtimeها یک دیدگاه جایگزین داشتند و ابزارهای داخلی را ارائه کردند که برای توسعه ضروری به نظر میرسید. Deno، Bun، Go و Rust همگی اجراکننده های تست داخلی را ارائه می دهند. توسعهدهندگان یک انتخاب پیشفرض دارند اما زمانی که پروژهشان نیازمندیهای خاصی داشت، میتوانند جای آن یک جایگزینی را انتخاب کنند.
Node.js 18 یک test runner معرفی کرد که اکنون در نسخه 20 پایدار است. نیازی به نصب ماژول شخص ثالث نیست و می توانید اسکریپت های تست ایجاد کنید:
- در پوشه
/test/پروژه شما - با نامگذاری فایل
test.js،test.mjsیاtest.cjs - با استفاده از
test-در ابتدای نام فایل - مانندtest-mycode.js - استفاده از کلمه تست در انتهای نام فایل با قبل نقطه (
.)، خط فاصله (-) یا آندرلاین (_) - مانندmycode-test.js،mycode_test.cjs، یاmycode.test.mjs
سپس می توانید توابع تست node:test و node:assert را وارد کنید و بنویسید:
// test.mjs
import { test, mock } from 'node:test';
import assert from 'node:assert';
import fs from 'node:fs';
test('my first test', (t) => {
assert.strictEqual(1, 1);
});
test('my second test', (t) => {
assert.strictEqual(1, 2);
});
// asynchronous test with mocking
mock.method(fs, 'readFile', async () => 'Node.js test');
test('my third test', async (t) => {
assert.strictEqual( await fs.readFile('anyfile'), 'Node.js test' );
});
تست ها را با node --test test.mjs اجرا کنید و خروجی را بررسی کنید:
✔ my first test (0.9792ms)
✖ my second test (1.2304ms)
AssertionError: Expected values to be strictly equal:
1 !== 2
at TestContext.<anonymous> (test.mjs:10:10)
at Test.runInAsyncScope (node:async_hooks:203:9)
at Test.run (node:internal/test_runner/test:547:25)
at Test.processPendingSubtests (node:internal/test_runner/test:300:27)
at Test.postRun (node:internal/test_runner/test:637:19)
at Test.run (node:internal/test_runner/test:575:10)
at async startSubtest (node:internal/test_runner/harness:190:3) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: 1,
expected: 2,
operator: 'strictEqual'
}
✔ my third test (0.1882ms)
ℹ tests 3
ℹ pass 2
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 72.6767
میتوانید یک دستور watch-- اضافه کنید تا بهطور خودکار تست ها را زمانی که فایل تغییر میکند، دوباره اجرا کند:
node --test --watch test.mjs
همچنین می توانید تمام تست های موجود در پروژه را اجرا کنید:
node --test
Native testing یک ویژگی بسیار عالی است که به زمان اجرا Node.js اضافه شد. نیاز کمتری به یادگیری API های شخص ثالث مختلف وجود دارد، و دیگر بهانه ای برای فراموش کردن اضافه کردن تست به پروژه های کوچکتر نداریم.
Compiling a Single Executable Application
پروژه های Node.js برای اجرا به runtime نیاز دارند. این می تواند مانعی در هنگام توزیع برنامه ها در پلتفرم ها یا کاربرانی باشد که به راحتی نمی توانند Node.js را نصب یا نگهداری کنند.
نسخه 20 یک ویژگی آزمایشی ارائه می دهد که به شما امکان می دهد یک برنامه اجرایی واحد (SEA) ایجاد کنید که بتوانید بدون وابستگی آن را مستقر کنید. راهنما این فرآیند را توضیح می دهد، اگرچه کمی پیچیده است:
- شما باید یک پروژه با یک اسکریپت ورودی داشته باشید. باید از CommonJS به جای ماژول های ES استفاده کند.
- یک فایل پیکربندی JSON ایجاد کنید که برای ساخت اسکریپت خود در یک blob استفاده می شود که در runtime اجرا می شود. برای مثال
sea-config.json:
{
"main": "myscript.js",
"output": "sea-prep.blob"
}
- blob را با
node --experimental-sea-config sea-config.jsonایجاد کنید. - با توجه به سیستم عامل خود، سپس باید
nodeاجرایی را کپی کنید، امضای باینری را حذف کنید، blob را به باینری تزریق کنید، آن را دوباره امضا کنید و برنامه به دست آمده را تست کنید.
در حالی که کار می کند، شما محدود به پروژه های قدیمی CommonJS هستید و فقط می توانید همان سیستم عامل مورد استفاده خود را هدف قرار دهید. با توجه به اینکه کامپایلر برتر Deno میتواند در یک دستور از فایلهای منبع جاوا اسکریپت یا TypeScript یک فایل اجرایی برای هر پلتفرمی ایجاد کند، مطمئناً بهبود خواهد یافت.
همچنین باید از اندازه فایل اجرایی بدست آمده آگاه باشید. یک console.log ('Hello World') یک فایل 85 مگابایتی تولید می کند، زیرا Node.js (و Deno) باید کل موتور جاوا اسکریپت V8 و کتابخانه های استاندارد را اضافه کنند. گزینه هایی برای کاهش اندازه فایل در نظر گرفته شده است، اما بعید است که کمتر از 25 مگابایت باشد.
کامپایل برای ابزارهای خط فرمان کوچک عملی نخواهد بود، اما برای پروژه های بزرگتر مانند یک برنامه وب سرور کامل، گزینه مناسب تری است.
موتور جاوا اسکریپت V8 به روز شد
Node.js 20 شامل آخرین نسخه موتور V8 است که شامل ویژگی های جاوا اسکریپت زیر است:
()String.prototype.isWellFormed: زمانی که یک رشته به خوبی شکل گرفته(well-formed) باشد و حاوی کاراکترهای جانشین تنها (جفت نشده) نباشد،trueرا برمی گرداند.()String.prototype.toWellFormed: رشته ای خوش فرم را برمی گرداند که مشکلات کاراکتر جانشین تنها را برطرف می کند.- یک عبارت منظم جدید
vکه به مشکلات مربوط به پوشش کاراکترهای یونیکد می پردازد.
بروز رسانی های متفرقه
به روز رسانی ها و بهبودهای زیر نیز در دسترس هستند:
- بهبود عملکرد URL ، نیتیو
()fetchو APIهای EventTarget - بهبودهای بارگیری ماژول ES، از جمله پشتیبانی تست برای
()import.meta.resolve، که می تواند مرجع مسیر فایل یک ماژول را به رشته URL محدود کند. - بهبود قابلیت همکاری Web Crypto API
- پیشرفت بیشتر در رابط سیستم WebAssembly (WASI) که به برنامه های کاربردی WASM sandboxed دسترسی به سیستم عامل اجازه می دهد.
- پشتیبانی رسمی از ARM64 در ویندوز
نتیجه
Node.js 20 یک گام بزرگ به جلو برداشته است. این ورژن قابل توجه تری می باشد و برخی از ویژگی های بهتر Deno را اجرا می کند.
با این حال، این سوال پیش می آید: آیا باید به جای آن از Deno استفاده کرد؟
دنو عالیه پایدار است، به طور نیتیو از TypeScript پشتیبانی می کند، زمان توسعه را کاهش می دهد، به ابزارهای کمتری نیاز دارد و بروز رسانی های منظم را دریافت می کند. نکته منفی این است که زمان کمتری سپری شده است، ماژول های کمتری دارد و اغلب تقلیدهای کم عمقی از کتابخانه های Node.js هستند.
Deno و Bun برای پروژه های جدید ارزش در نظر گرفتن دارند، اما هزاران برنامه کاربردی Node.js موجود است. Deno و Bun انتقال کد را آسانتر میکنند، اما همیشه یک مزیت واضح برای دور شدن از Node.js وجود نخواهد داشت.
نظر شما درباره این ویژگی ها و آینده نود جی اس چیست؟
