قادم من جيثب؟ يمكن الحصول على تجربة عرض أفضل لهذا البرنامج التعليمي في الموقع أدناه: https://pokedpeter.dev
سيوضح لك هذا البرنامج التعليمي كيفية إنشاء مشروع Barebones Node (JavaScript) من الصفر مع الأشياء الجيدة التالية:
المتطلبات المسبقة:
دعنا ننشئ مشروع عقدة Barebones
إنشاء مشروع العقدة لدينا. يمكن أن تتخطى جميع الخيارات المطالبة.
mkdir project
cd project
npm init سيتم إعداد ملف يسمى package.json مع الخيارات التي اخترتها. يمكنك تخطي خيارات الواجهة والذهاب مع الإعدادات الافتراضية عن طريق تشغيل npm init -y
{
"name" : " project " ,
"version" : " 1.0.0 " ,
"description" : " " ,
"main" : " index.js " ,
"scripts" : {
"test" : " echo " Error: no test specified " && exit 1 "
},
"author" : " " ,
"license" : " ISC "
}لا يتم إنشاء البرنامج النصي الرئيسي القابل للتنفيذ تلقائيًا. قم بإنشائها.
touch index.js ضع شيئًا أساسيًا في index.js لأغراض الاختبار.
console . log ( 'Hello World' ) ;اختبره من CLI:
node index.js
الذي يمنحك بعض إخراج وحدة التحكم:
Hello World
لا يأتي JavaScript مع أي مكتبات قياسية مدمجة. النهج الموصى به هو تثبيت حزم NPM. لنجرب مثالًا. سنقوم بتثبيت Lodash ، مكتبة شهيرة من المرافق المفيدة.
npm install lodash
ها هو الإخراج:
added 1 package, and audited 4 packages in 987ms
found 0 vulnerabilities
الآن بعد أن قمنا بتشويه Lodash يمكننا الآن استخدامه في تطبيقنا. افتح Up index.js مرة أخرى وتحديثه للمطابقة:
const _ = require('lodash);
console.log(_.snakeCase('Hello World'));
قم بتشغيله وسترى الإخراج التالي:
hello_world
عرض ملف package.json مرة أخرى وألاحظ قسم dependencies الجديد مع إدخال Lodash:
"dependencies" : {
"lodash" : " ^4.17.21 "
}نصيحة
لعرض محتويات الملف بسرعة من CLI ، اكتب: cat package.json
عرض ملفات المشروع الخاصة بك ولاحظ تم إنشاء مجلد node_modules :
$ ls -l
index.js
node_modules
package-lock.json
package.jsonهذا المجلد هو المكان الذي يتم فيه تخزين تبعياتك. دعنا نتحقق منها:
$ ls node_modules
@types lodash typescriptدعنا نضيف TypeScript إلى مشروع Node Barebones.
تثبيت تبعية TypeScript ، كدخل DEV. جميع تبعيات TypeScript مطلوبة فقط أثناء التطوير ، لذلك نحن نفعل --save-dev
npm install --save-dev typescriptتثبيت تعريفات نوع typscript للعقدة:
npm install --save-dev @types/nodeنصيحة
قم بتثبيت حزم متعددة في واحدة من خلال الجمع بينها على سطر واحد: npm install --save-dev typescript @types/node
إلقاء نظرة على التبعيات في package.json . هذا هو الجزء ذي الصلة:
{
"devDependencies" : {
"@types/node" : " ^20.4.9 " ,
"typescript" : " ^5.1.6 "
}
}قم بتهيئة TypeScript عن طريق تشغيل الأمر التالي في أي مكان داخل مشروعك.
npx tsc --init سيؤدي ذلك إلى إنشاء ملف tsconfig.json مع إعدادات افتراضية:
Created a new tsconfig.json with:
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
نستخدم npx التي تنفذ ثنائيات مثبتة محليًا تم تثبيتها عبر package.json .
تحذير
سوف يوصي بعض أدلة التثبيت بتثبيت TypeScript على مستوى عالمي sudo npm install -g typescript . أوصي بتثبيت إصدار محلي (أي داخل مجلد المشروع)
قد يختلف الإصدار العالمي عن الإصدار المحلي المثبت لمشروعك. يستخدم تشغيل tsc مباشرة الإصدار العالمي. عندما يتم تشغيل tsc كجزء من NPM في مشروعك ، فإنه يستخدم الإصدار المحلي.
هناك العديد من الخيارات التي تم تعيينها افتراضيًا في tsconfig.json . هناك الكثير من الخيارات التي تم التعليق عليها - لا تظهر أدناه.
{
"compilerOptions" : {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
"target" : " es5 " , /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module" : " commonjs " , /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
/* Strict Type-Checking Options */
"strict" : true , /* Enable all strict type-checking options. */
/* Module Resolution Options */
"esModuleInterop" : true , /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
/* Advanced Options */
"skipLibCheck" : true , /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames" : true /* Disallow inconsistently-cased references to the same file. */
}
}بعض التعديلات الموصى بها إلى الإعدادات الافتراضية:
"target" : " es2015 " , // I'd recommend es2015 at a minimum. es5 is ancient.
"outDir" : " build " , // Keep our compiled javascript in the build directory
"rootDir" : " src " , // Keep our source code in a separate directory
"noImplicitAny" : true , // We're using Typescript yeah? And not adding Typescript to an existing project. Enforce good habits from the start.
"lib" : [ " es2020 " ], // Setting this excludes DOM typings as we are using Node. Otherwise you'll run into errors declaring variables like 'name' فيما يتعلق target . عادة ما تدعم إصدارات الأحدث من العقدة ميزات ECMA الأحدث. موقع الويب أدناه هو مورد رائع لمعرفة ميزات ECMA المتاحة لكل إصدار من العقدة:
https://node.green/
لا حاجة إلى index.js بعد الآن:
rm index.jsقم بإعداد رمز مصدر المشروع الخاص بنا:
mkdir src
cd src
touch index.ts أضف شيئًا أساسيًا إلى index.ts لاختباره:
console . log ( 'Hello typescript!' ) ;تجميع مشروع Barebones لدينا.
npx tsc يمكن العثور على الإخراج المترجم ، كما JavaScript ، في دليل /build . سوف يحتوي على index.js عكس src/index.ts
محتويات index.js:
"use strict" ;
console . log ( 'Hello World!' ) ;أنت الآن مستعد لبناء مشاريع JavaScript مع TypeScript!
حتى وقت قريب ، كان Tslint هو Lo-to TypeScript Code Linter ولكن تم إهماله الآن حيث تم دمج المشروع في ESLINT. ها هي الصفحة الرئيسية الرسمية:
موقع إلكتروني:
https://eslint.org
موقع github:
https://github.com/typescript-eslint/typescript-eslint
تثبيت ESLINT (كاعتماد DEV بالطبع)
npm install --save-dev eslintدعنا ننشئ تكوين الوبر الخاص بنا باستخدام أمر eBr الخاص بـ ESLINT:
npx eslint --initاتبع المطالبات. نحن نستخدم العقدة ، لذلك لا يلزم دعم المتصفح. سوف يسألك ما إذا كنت تريد تثبيت المكونات الإضافية TypeScript التابعة. المضي قدما وافعل ذلك.
✔ How would you like to use ESLint ? · problems
✔ What type of modules does your project use ? · esm
✔ Which framework does your project use ? · none
✔ Does your project use TypeScript ? · No / Yes
✔ Where does your code run ? · node
✔ What format do you want your config file to be in ? · JSON
The config that you ' ve selected requires the following dependencies:
@typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
✔ Would you like to install them now with npm? · No / Yes
Successfully created .eslintrc.json file in /your/projectمزيد من المعلومات حول تكوين الوبر أدناه:
https://eslint.org/docs/user-guide/configuring
باستخدام الخيارات المحددة أعلاه ، يبدو ملف .eslintrc.json الخاص بنا:
{
"env" : {
"es2020" : true ,
"node" : true
},
"extends" : [
" eslint:recommended " ,
" plugin:@typescript-eslint/recommended "
],
"parser" : " @typescript-eslint/parser " ,
"parserOptions" : {
"ecmaVersion" : 11 ,
"sourceType" : " module "
},
"plugins" : [
" @typescript-eslint "
],
"rules" : {
}
}ربما لاحظت أن أحد الأسئلة أثناء عملية eSlint init هو:
? How would you like to use ESLint ? …
To check syntax only
▸ To check syntax and find problems
To check syntax, find problems, and enforce code styleالخيار الأخير يفرض أيضًا نمط الرمز. إذا قمت بتحديد هذا الخيار ، فسيكون سؤال متابعة:
? How would you like to define a style for your project ? …
▸ Use a popular style guide
Answer questions about your style
Inspect your JavaScript file(s)إذا اخترت استخدام دليل النمط الشهير ، فستكون لديك خيار من ما يلي:
? Which style guide do you want to follow ? …
▸ Airbnb: https://github.com/airbnb/javascript
Standard: https://github.com/standard/standard
Google: https://github.com/google/eslint-config-google
XO: https://github.com/xojs/eslint-config-xoأوصي بالبحث في أدلة النمط أعلاه والذهاب مع واحدة تتماشى مع تفضيلاتك.
بعد ذلك ، سنقوم بإنشاء ملف تكوين آخر في نص الشكوى للسماح لنا باستبعاد الملفات والأدلة من Linting:
touch .eslintignoreوأضف المحتويات التالية إلى الملف:
node_modules
build
لا نريد أن ننزلق على رمز JavaScript المترجم.
بشكل افتراضي ، يتم تمكين القواعد القياسية. انظر العناصر المميزة في القائمة على:
https://eslint.org/docs/rules/
على سبيل المثال ، دعنا نحاول كسر قاعدة no-extra-semi .
حاول إضافة شبه كولون إلى نهاية الخط في الفهرس.
console . log ( 'Hello typescript' ) ; ;وثم:
npx eslint srcالذي ينتج عنه:
1:34 error Unnecessary semicolon @typescript-eslint/no-extra-semi
✖ 1 problem (1 error, 0 warnings)
1 error and 0 warnings potentially fixable with the `--fix` option.
تحذير
عند تثبيت خيار Airbnb ، لاحظت أن ESLINT تحتاج إلى تمرير ملحق ملف .TS:
npx eslint src --ext .ts قم بإنشاء برنامج نصي لهذا في package.json .
"scripts" : {
...
"lint" : " eslint src --ext .ts "
},ينطبق فقط عند وجود NPM <V7 ولكن لاحظ أنه إذا قمت بتشغيل البرنامج النصي NPM وإيجاد المشكلات ، فسترى رسالة خطأ NPM التالية الملحقة أسفل إخراج ESLINT:
> eslint src --ext .ts
/home/user/dev/test/src/index.ts
1:1 warning Unexpected console statement no-console
1:21 error Missing whitespace after semicolon semi-spacing
1:22 error Unnecessary semicolon no-extra-semi
✖ 3 problems (2 errors, 1 warning)
2 errors and 0 warnings potentially fixable with the ` --fix ` option.
npm ERR ! code ELIFECYCLE
npm ERR ! errno 1
npm ERR ! [email protected] lint: ` eslint src --ext .ts `
npm ERR ! Exit status 1
npm ERR !
npm ERR ! Failed at the [email protected] lint script.
npm ERR ! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR ! A complete log of this run can be found in:
npm ERR ! /home/user/.npm/_logs/2021-08-18T15_27_55_318Z-debug.logلا أرى خطأ NPM عندما على NPM V7 (على سبيل المثال ، عند استخدام العقدة 16.6.2)
يمكن أن تكون كل قاعدة واحدة من الدول الثلاث:
| وضع القاعدة | وصف |
|---|---|
| 0 أو "OFF" | يعطل القاعدة |
| 1 أو "تحذير" | تحذير ، لن يفشل لينتر |
| 2 أو "خطأ" | خطأ ، سيفشل لينتر |
يمكن إضافة القواعد كمفاتيح إلى كائن قواعد في ملف config lint .eslintrc.json:
{
"root" : true ,
"parser" : " @typescript-eslint/parser " ,
"plugins" : [ ... ],
"extends" : [ ... ],
"rules" : {
..your rules go here..
}
}ابحث عن القواعد في eslint.org:
https://eslint.org/docs/rules/
دعنا نختبر القاعدة الأسلوبية المسماة "زجاجة الفاصلة". نريد تحذير المستخدم إذا كانت مجموعة من خطوط متعددة تفتقد فاصلة على العنصر الأخير.
أضف القاعدة:
"rules" : {
"comma-dangle" : [
" warn " , {
"arrays" : " always-multiline "
}
]
}اقرأ تفاصيل القاعدة على الموقع. هناك قدر كبير من التخصيص المسموح به للعديد من القواعد. نريد أن نفرض فواصل متدلية في جميع السيناريوهات في هذا المثال.
تغيير index.ts مع الكود التالي:
const movies = [
'Lord of the Flies' ,
'Battle Royale'
] ;
movies . pop ( ) ;قم بتشغيل Linter:
npx eslint srcالآن يجب أن نرى التحذير التالي:
3:18 warning Missing trailing comma comma-dangle
✖ 1 problem (0 errors, 1 warning)
0 errors and 1 warning potentially fixable with the ` --fix ` option. ملاحظة في الإخراج ، هناك خيار لإصلاح المشكلة. حاول تشغيل Linter مع خيار --fix :
npx eslint --fix src لا يوجد إخراج من Linter هذه المرة ، وإذا تحققنا من index.ts سنرى أنه تمت إضافة فاصلة متدلية تلقائيًا:
const movies = [
'Lord of the Flies' ,
'Battle Royale' , // <-- dangling comma added
] ;
movies . pop ( ) ; سنستخدم أجمل لتنسيق الكود. إنه رمز رأي يدعم العديد من اللغات بما في ذلك TypeScript و JavaScript وغيرها من التنسيقات التي قد تستخدمها في التكوينات مثل JSON و YAML.
https://prettier.io
بدلاً من ذلك ، يمكنك الالتزام بـ ESLINT لتنسيق الكود الخاص بك. يختلف أجمل من حيث أنه لا يعدل التعليمات البرمجية الخاصة بك ، إلا إذا قمت بتعيين أحد الخيارات الصغيرة.
تثبيت الوحدة:
npm install --save-dev prettierإنشاء ملف التكوين. هذا يتيح للمحررين والأدوات الأخرى معرفة أنك تستخدم أجمل:
echo {} > .prettierrc.jsonربما لن تحتاج إلى إضافة أي خيارات إلى ملف التكوين حيث سيتضمن معظمهم تحويل التعليمات البرمجية الخاصة بك. من الأفضل ترك ذلك إلى ESLINT واتركي أجمل التعامل مع التنسيق.
إنشاء ملف تجاهل. هذا يتيح للجملاء CLI والمحررين معرفة الملفات التي يمكن استبعادها من التنسيق.
touch .prettierignore أضف الأسطر التالية إلى .prettierignore :
node_modules
buildاختبار أجمل مع الأمر التالي. لن يتجاوز أي شيء فقط إخراج الكود المنسق:
npx prettier srcبناءً على تغييرنا الأخير إلى الفهرس ، سيكون الإخراج:
const movies = [ "Lord of the Flies" , "Battle Royale" ] ;
movies . pop ( ) ;يمكننا أن نرى أن الصفيف متعدد الخطوط قد تم تنسيقه في سطر واحد.
اكتب التغييرات في الملف بتكرار الأمر مع الخيار --write :
npx prettier --write srcسيدرج هذا الملفات التي تم تنسيقها:
src/index.ts 279msبالنظر إلى كل من ESLINT و ARTTIER يمكن تنسيق الكود ، يمكنك أن تتوقع حدوث بعض النزاعات. لقد أنشأت أجمل قواعد خصيصًا لـ ESLINT التي تعطل بشكل أساسي أي قواعد غير ضرورية أو متضاربة عند الجمع بين أجمل.
الأول هو eslint-config-prettier :
https://github.com/prettier/eslint-config-prettier
يقوم هذا التكوين بإيقاف تشغيل جميع القواعد غير الضرورية أو الصراع مع أجمل. تثبيته مع الأمر التالي:
npm install --save-dev eslint-config-prettier ثم ، أضفه إلى السطر الأخير من قسم extends في تكوين ESLINT ، .eslintrc.json :
{
"extends" : [
"eslint:recommended" ,
"plugin:@typescript-eslint/recommended" ,
"plugin:@typescript-eslint/eslint-recommended" ,
"prettier" // <-- Add this
] ,
}يمكنك تشغيل الأمر التالي على أي ملف للتحقق من عدم وجود تعارض بين Eslint و أجمل:
npx eslint-config-prettier src/index.tsإذا سارت الأمور على ما يرام ، فيجب أن تحصل على الاستجابة التالية:
No rules that are unnecessary or conflict with Prettier were found. التالي للتثبيت هو eslint-plugin-prettier :
https://github.com/prettier/eslint-plugin-prettier
يدير أجمل كقاعدة ESLINT ويبلغ الاختلافات مثل قضايا ESLINT الفردية. تثبيته مع الأمر التالي:
npm install --save-dev eslint-plugin-prettier ثم قم بتحديث ملف .eslintrc.json على النحو التالي:
{
"plugins" : [ " prettier " ],
"rules" : {
"prettier/prettier" : " error "
}
}ابحث عن البرنامج المساعد أدناه:
ESLint - بقلم ديرك بايمر
ابحث عن البرنامج المساعد أدناه:
Prettier - Code formatter - بواسطة أجمل
اضغط على Ctrl + Shift + I لتنسيق الكود. ستتم مطالبتك بتحديد التنسيق الافتراضي. حدد أجمل كما هو الافتراضي الخاص بك.
ابحث عن البرنامج المساعد أدناه:
Prettier ESLint - بواسطة Rebecca Vest
تم تصميم هذه البرامج النصية لمشروع TypeScript الخاص بنا. نحن نتحقق فقط من ملفات .TS.
أضف الأوامر أدناه إلى قسم scripts في package.json .
"start:dev" : " nodemon " "lint" : " eslint --ext .ts src "
"lint-fix" : " eslint --fix --ext .ts src " "pretty" : " prettier --write 'src/**/*.ts' " Curveball هو إطار عمل صغير لبناء واجهات برمجة التطبيقات في العقدة. إنه مبني من الألف إلى الياء بدعم لـ TypeScript بدلاً من سلفه الأكثر شعبية KOA.
https://curveballjs.org/
تثبيته:
npm install @curveball/core انسخ المثال من الموقع إلى index.ts . الشيء الوحيد الذي سنغيره هو رقم المنفذ. لسببين. واحد ، يمكن حظر المنفذ 80. اثنين. يتيح لنا التشغيل على منافذ مختلفة إجراء مشاريع عقدة متعددة في وقت واحد.
import { Application } from '@curveball/core' ;
const app = new Application ( ) ;
app . use ( async ctx => {
ctx . response . type = 'text/plain' ;
ctx . response . body = 'hello world' ;
} ) ;
app . listen ( 9000 ) ;بدء تشغيل الخادم في وضع dev مع البرنامج النصي الذي أنشأناه مسبقًا:
npm run start:devستحصل على الإخراج التالي مع استمع Nodemon لتغييرات الملف:
> [email protected] start:dev /home/your_name/project
> nodemon
[nodemon] 2.0.4
[nodemon] to restart at any time, enter ` rs `
[nodemon] watching path(s): src/ ** / *
[nodemon] watching extensions: ts,jsبعد إجراء تغيير رمز ، شاهد إخراج وحدة التحكم في الخادم ليكون Nodemon في العمل. قم أيضًا بتحديث صفحة الويب لمشاهدة التحديثات.
قم بإعداد إعادة التحميل التلقائي بعد تغييرات التعليمات البرمجية للتطوير. قم بتثبيت nodemon لمراقبة تغييرات الملفات و ts-node لتشغيل رمز TypeScript مباشرة بدلاً من الاضطرار إلى التجميع ثم النقل إلى node .
npm install --save-dev ts-node nodemon إضافة تكوين nodemon.json . سيؤدي ذلك إلى تكوين Nodemon لمشاهدة التغييرات على ملفات .ts و .js داخل دليل رمز المصدر الخاص بك ، ثم قم بتشغيل الأمر exec بعد التغييرات.
{
"watch" : [ " src " ],
"ext" : " .ts,.js " ,
"ignore" : [],
"exec" : " ts-node ./src/index.ts "
} إضافة نص NPM داخل package.json لبدء nodemon للتنمية:
"start:dev" : " nodemon " تشغيل npm run start:dev لبدء عملية إعادة التحميل.
قم بتثبيت إرشادات Docker و Lookup حول كيفية تشغيل Docker بدون Sudo - تعليمات تم حذفها هنا لأنها OS / Distro محددة.
قم بإنشاء ملف docker-compose.yml مع حاوية عقدة واحدة كخدمة:
اسم مشروعنا هو "مشروع" كما هو اسم الخدمة والحاوية. لدينا رسم تخطيطي دليل المشروع الخاص بنا إلى /مشروع داخل حاوية العقدة. تأكد أخيرًا من مطابقة المنافذ المنافذ المكشوفة في طلبك.
مزيد من التفاصيل أدناه:
https://docs.docker.com/compose/compose-file/
version : ' 3 '
services :
project :
build : .
container_name : project
volumes :
- .:/project
ports :
- " 9000 " بعد ذلك ، قم بإنشاء Dockerfile مع المحتويات التالية.
FROM node:12
WORKDIR /project
COPY package.json .
RUN npm install
COPY . .
CMD [ "npm" , "run" , "start:dev" ]يقوم هذا بإعداد دليل المشروع الخاص بنا داخل الحاوية ، ويقوم بتثبيت حزم العقدة الخاصة بنا ، ونسخ على المحتوى من نظام الملفات الأصلي لدينا ويبدأ خادم CurveBall الخاص بنا في وضع DEV.
قم الآن بإحضار الحاوية:
docker-compose upسترى الإخراج التالي:
Creating network "project_default" with the default driver
Building project
Step 1/7 : FROM node:12
---> dfbb88cfffc8
Step 2/7 : WORKDIR /project
---> Running in 86fff3a3c90b
Removing intermediate container 86fff3a3c90b
---> 5912fd119492
Step 3/7 : COPY package.json .
---> 4fa4df04cc6b
Step 4/7 : RUN npm install
---> Running in 8b814e4d75d2
...
(Node package installation happens here)
...
Removing intermediate container 8b814e4d75d2
---> 3bfd2b1a83e4
Step 5/7 : COPY . .
---> f6971fdf7fb5
Step 6/7 : EXPOSE 9000
---> Running in 2ab0a152b0a6
Removing intermediate container 2ab0a152b0a6
---> 0e883b79c1b3
Step 7/7 : CMD ["npm", "run", "start:dev"]
---> Running in f64884ae2643
Removing intermediate container f64884ae2643
---> 1abb8edf6373
Successfully built 1abb8edf6373
Successfully tagged project_project:latest
WARNING: Image for service project was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating project ...
Creating project ... done
Attaching to project
project |
project | > [email protected] start:dev /project
project | > nodemon
project |
project | [nodemon] 2.0.4
project | [nodemon] to restart at any time, enter `rs`
project | [nodemon] watching path(s): src/**/*
project | [nodemon] watching extensions: ts,js
project | [nodemon] starting `ts-node ./src/index.ts`
يمكنك استخدام CTRL-C لإيقاف الحاوية.
استخدم docker-compose up -d لإبراز الحاوية في الوضع المنفصل -يتم طرحه في Brackground وأنت حر في متابعة سطر الأوامر.
نقوم بإنشاء حاوية تعتمد على العقدة V12. يتم تعريف دليل العمل الخاص بنا داخل الحاوية على أنه /project (حيث سيتم تعيين رمز المشروع الخاص بنا)
يعتمد إصدار العقدة المثبتة على نظام التشغيل المثبت وكيفية تحديث حزمها.
إذا كنت تستخدم العقدة خارج حاويات Docker والعمل على مشاريع عقدة متعددة ، تتطلب كل منها إصدارات مختلفة من العقدة ، ثم قم بتثبيت NVM:
https://github.com/nvm-sh/nvm
شكر كبير لما يلي لمساعدتي في إنشاء هذا البرنامج التعليمي.