نحوه استفاده از React Compiler – راهنمای کامل
در این آموزش، خواهید آموخت که چگونه کامپایلر React می تواند به شما در نوشتن برنامه های React بهینه تر کمک کند.
React یک کتابخانه رابط کاربری است که بیش از یک دهه است که کار خود را به خوبی انجام می دهد. معماری مؤلفه، جریان داده های یک طرفه و ماهیت اعلامی در کمک به توسعه دهندگان در ساخت برنامه های نرم افزاری آماده برای تولید و مقیاس پذیر برجسته است.
در طول نسخهها (حتی تا آخرین نسخه پایدار v18.x)، React تکنیکها و متدولوژیهای مختلفی را برای بهبود عملکرد برنامه ارائه کرده است.
به عنوان مثال، کل پارادایم یادداشت با استفاده از مؤلفه مرتبه بالاتر React.memo()
یا با قلاب هایی مانند useMemo()
و useCallback()
پشتیبانی شده است.
در برنامه نویسی، memoization
یک تکنیک بهینه سازی است که باعث می شود برنامه های شما با ذخیره کردن نتایج محاسبات گران قیمت، سریعتر اجرا شوند.
اگرچه تکنیکهای memoization
React برای اعمال بهینهسازی عالی هستند، همانطور که عمو بن (یادتان هست عموی مرد عنکبوتی؟) یک بار گفت: "با قدرت زیاد مسئولیت بزرگی به همراه دارد". پس ما به عنوان توسعه دهندگان باید کمی مسئولیت پذیرتر در اعمال آنها باشیم. بهینه سازی عالی است، اما بهینه سازی بیش از حد می تواند برای عملکرد برنامه قاتل باشد.
با React 19، جامعه توسعهدهندگان فهرست ی از پیشرفتها و ویژگیها را دریافت کردهاند که میتوانند به آن افتخار کنند:
یک کامپایلر منبع باز تجربی. ما در این مقاله عمدتاً بر روی آن تمرکز خواهیم کرد.
اجزای سرور React.
اقدامات سرور
روش سادهتر و ارگانیکتر برای مدیریت فراداده سند.
قلاب ها و API های پیشرفته.
ref
می توان به عنوان props ارسال کرد.
بهبود در بارگذاری دارایی برای سبک ها، تصاویر و فونت ها.
یکپارچگی بسیار روانتر با اجزای وب.
اگر اینها برای شما هیجان انگیز هستند، توصیه می کنم این ویدیو را تماشا کنید که توضیح می دهد چگونه هر ویژگی روی شما به عنوان یک توسعه دهنده React تأثیر می گذارد. امیدوارم خوشتون بیاد😊.
معرفی یک compiler
با React 19
قرار است بازی را تغییر دهد. از این به بعد، میتوانیم به کامپایلر اجازه دهیم تا سردرد بهینهسازی را کنترل کند نه اینکه آن را روی ما نگه دارد.
آیا این بدان معناست که دیگر مجبور نیستیم از memo
، useMemo()
، useCallback
و غیره استفاده کنیم؟ نه - ما بیشتر این کار را نمی کنیم. اگر قوانین React را برای کامپوننت ها و هوک ها درک کرده و از آنها پیروی کنید، کامپایلر می تواند به طور خودکار از این موارد مراقبت کند.
چگونه این کار را انجام خواهد داد؟ خب بهش میرسیم اما قبل از آن، بیایید بفهمیم که compiler
چیست و آیا می توان این بهینه ساز جدید برای کد React را React Compiler
نامید یا خیر.
اگر دوست دارید از آموزش های ویدئویی نیز بیاموزید، این مقاله به عنوان یک آموزش تصویری نیز در اینجا موجود است:
فهرست مطالب
رفع مشکل: با استفاده از کامپایلر React
برنامه React بهینه شده با React Compiler
React Compiler در React DevTools
غواصی عمیق - کامپایلر React چگونه کار می کند؟
چگونه می توان از کامپایلر React شرکت کرد و از آن خارج شد؟
آیا می توانیم از کامپایلر React با React 18.x استفاده کنیم؟
کامپایلر به طور سنتی چیست؟
به بیان ساده، کامپایلر یک برنامه/ابزار نرم افزاری است که کد زبان برنامه نویسی سطح بالا (کد منبع) را به کد ماشین ترجمه می کند. چندین مرحله برای کامپایل کد منبع و تولید کد ماشین وجود دارد:
lexical analyzer
کد منبع را نشانه گذاری می کند و توکن ها را تولید می کند.
Syntax Analyzer
یک درخت نحو انتزاعی (AST) ایجاد می کند تا رمزهای کد منبع را به صورت منطقی ساختار دهد.
Semantic Analyzer
صحت معنایی (یا نحوی) کد را تأیید می کند.
پس از هر سه نوع تجزیه و تحلیل توسط تحلیلگرهای مربوطه، مقداری intermediate code
تولید می شود. به کد IR نیز معروف است.
سپس optimization
روی کد IR انجام می شود.
در نهایت، machine code
توسط کامپایلر از کد IR بهینه سازی شده تولید می شود.
که در بالا توضیح داده شد" class="image--center mx-auto" width="1200" height="630" loading="lazy">
اکنون که اصول کار یک کامپایلر را فهمیدید، بیایید با React Compiler
آشنا شویم و نحوه عملکرد آن را درک کنیم.
معماری کامپایلر React
کامپایلر React ابزاری در زمان ساخت است که شما باید آن را با پروژه React 19 خود با استفاده از گزینه های پیکربندی ارائه شده توسط اکوسیستم ابزار React پیکربندی کنید.
به عنوان مثال، اگر Vite
برای ایجاد برنامه React خود استفاده می کنید، پیکربندی کامپایلر در فایل vite.config.js
انجام می شود.
کامپایلر React دارای سه جزء اصلی است:
Babel Plugin
: به تغییر کد در طول فرآیند کامپایل کمک می کند .
ESLint Plugin
: به شناسایی و گزارش هرگونه نقض قوانین React کمک می کند.
Compiler Core
: منطق کامپایلر هسته ای که تجزیه و تحلیل کد و بهینه سازی را انجام می دهد. هر دو افزونه Babel و ESLint از منطق کامپایلر اصلی استفاده می کنند.
جریان کامپایل به این صورت است:
Babel Plugin
مشخص می کند که کدام توابع (کامپوننت ها یا قلاب ها) باید کامپایل شوند. ما بعداً برخی از پیکربندیها را خواهیم دید تا نحوه انتخاب و خروج از فرآیند کامپایل را بیاموزیم. این افزونه منطق کامپایلر اصلی را برای هر یک از توابع فراخوانی می کند و در نهایت درخت دستور Abstract را ایجاد می کند.
سپس هسته کامپایلر Babel AST را به کد IR تبدیل میکند، آن را تجزیه و تحلیل میکند و اعتبارسنجیهای مختلفی را اجرا میکند تا اطمینان حاصل شود که هیچ یک از قوانین شکسته نشده است.
در مرحله بعد، سعی می کند با انجام پاس های مختلف، مقدار کدهای بهینه سازی شده را کاهش دهد تا کدهای مرده حذف شوند. کد با استفاده از حافظهسازی بهینهسازی میشود.
در نهایت، در مرحله تولید کد، AST تبدیل شده دوباره به کد جاوا اسکریپت بهینه شده تبدیل می شود.
React Compiler در عمل
اکنون که میدانید React Compiler چگونه کار میکند، بیایید اکنون به پیکربندی آن با یک پروژه React 19 بپردازیم تا بتوانید در مورد بهینهسازیهای مختلف یاد بگیرید.
درک مشکل: بدون کامپایلر React
بیایید یک صفحه محصول ساده با React ایجاد کنیم. صفحه محصول عنوانی را با تعداد محصولات موجود در صفحه، فهرست ی از محصولات و محصولات ویژه نشان می دهد.
سلسله مراتب کامپوننت ها و داده هایی که بین کامپوننت ها ارسال می شود به شکل زیر است:
همانطور که در تصویر بالا می بینید،
مؤلفه ProductPage
دارای سه مؤلفه فرزند، Heading
، ProductList
و FeaturedProducts
است.
جزء ProductPage
دو پروپوزال، products
و heading
دریافت می کند.
جزء ProductPage
تعداد کل محصولات را محاسبه می کند و مقدار را همراه با مقدار متن عنوان به جزء Heading
ارسال می کند.
مؤلفه ProductPage
پایه products
به مؤلفه فرزند ProductList
منتقل می کند.
به طور مشابه، محصولات برجسته را محاسبه می کند و سرپ featuredProducts
را به مؤلفه فرزند FeaturedProducts
ارسال می کند.
در اینجا نحوه ظاهر کد منبع مؤلفه ProductPage
آمده است:
import React from 'react' import Heading from './Heading' ; import FeaturedProducts from './FeaturedProducts' ; import ProductList from './ProductList' ; const ProductPage = ( {products, heading} ) => { const featuredProducts = products.filter( product => product.featured); const totalProducts = products.length; return ( < div className = "m-2" > < Heading heading = {heading} totalProducts = {totalProducts} /> < ProductList products = {products} /> < FeaturedProducts featuredProducts = {featuredProducts} /> </ div > ) } export default ProductPage
همچنین، فرض کنید از کامپوننت ProductPage
در فایل App.js
به صورت زیر استفاده می کنیم:
import ProductPage from "./components/compiler/ProductPage" ; function App ( ) { // A list of food products const foodProducts = [ { "id" : "001" , "name" : "Hamburger" , "image" : "🍔" , "featured" : true }, { "id" : "002" , "name" : "French Fries" , "image" : "🍟" , "featured" : false }, { "id" : "003" , "name" : "Taco" , "image" : "🌮" , "featured" : false }, { "id" : "004" , "name" : "Hot Dog" , "image" : "🌭" , "featured" : true } ]; return ( < ProductPage products = {foodProducts} heading = "The Food Product" /> ); } export default App;
همه چیز خوب است - پس مشکل کجاست؟ مشکل این است که React به طور فعال مولفه فرزند را زمانی که مولفه والد دوباره رندر میشود، دوباره رندر میدهد. یک رندر غیر ضروری نیاز به بهینه سازی دارد. بیایید ابتدا مشکل را به طور کامل درک کنیم.
ما مهر زمانی فعلی را در هر یک از مؤلفههای فرزند اضافه میکنیم. حال رابط کاربری رندر شده به شکل زیر خواهد بود:
عدد بزرگی که در کنار سرفصل ها می بینید، مهر زمانی است (با استفاده از تابع ساده Date.now()
از JavaScript Date API) که به کد مؤلفه اضافه کرده ایم. حال اگر مقدار heading prop مولفه ProductPage
را تغییر دهیم چه اتفاقی می افتد؟
قبل از:
< ProductPage products = {foodProducts} heading = "The Food Product" />
و بعد (توجه کنید که با اضافه کردن s
در انتهای مقدار heading
، آن را برای محصولات جمع کرده ایم):
< ProductPage products = {foodProducts} heading = "The Food Products" />
اکنون متوجه تغییر فوری در رابط کاربری خواهید شد. هر سه مُهر زمانی بهروزرسانی شدند. این به این دلیل است که هر سه مؤلفه زمانی که مؤلفه والد مجدداً رندر می شد به دلیل تغییر props دوباره رندر شدند.
اگر متوجه شده باشید، heading
prop فقط به کامپوننت Heading
منتقل شد، و حتی پس از آن دو جزء فرزند دیگر مجددا رندر شدند. اینجاست که ما به بهینه سازی نیاز داریم.
رفع مشکل: بدون کامپایلر React
همانطور که قبلاً بحث شد، React قلابها و APIهای مختلفی را برای memoization
در اختیار ما قرار میدهد. ما میتوانیم از React.memo()
یا useMemo()
برای محافظت از مؤلفههایی که بهطور غیرضروری دوباره رندر میشوند، استفاده کنیم.
به عنوان مثال، ما میتوانیم از React.memo()
برای به خاطر سپردن مولفه ProductList استفاده کنیم تا اطمینان حاصل کنیم که تا زمانی که پایه products
تغییر نکند، مولفه ProductList
دوباره رندر نمیشود.
ما می توانیم از قلاب useMemo()
برای به خاطر سپردن محاسبات محصولات برجسته استفاده کنیم. هر دو پیاده سازی در تصویر زیر نشان داده شده است.
اما باز هم، با یادآوری سخنان حکیمانه عمو بن بزرگ، در چند سال گذشته ما شروع به استفاده بیش از حد از این تکنیک های بهینه سازی کرده ایم. این بهینه سازی های بیش از حد می تواند بر عملکرد برنامه های شما تأثیر منفی بگذارد. پس ، در دسترس بودن کامپایلر برای توسعه دهندگان React یک مزیت است زیرا به آنها اجازه می دهد بسیاری از بهینه سازی ها را به کامپایلر واگذار کنند.
بیایید اکنون با استفاده از کامپایلر React مشکل را برطرف کنیم.
رفع مشکل: با استفاده از کامپایلر React
باز هم، کامپایلر React یک ابزار انتخاب زمان ساخت است. همراه با React 19 RC ارائه نمی شود. شما باید وابستگی های مورد نیاز را نصب کنید و کامپایلر را با پروژه React 19 خود پیکربندی کنید.
قبل از پیکربندی کامپایلر، می توانید با اجرای این دستور در فهرست پروژه خود تحلیل کنید که آیا پایگاه کد شما سازگار است یا خیر:
npx react-compiler-healthcheck@experimental
چه تعداد مؤلفه می تواند توسط کامپایلر بهینه شود
اگر قوانین React رعایت شود.
اگر کتابخانه های ناسازگاری وجود دارد.
اگر متوجه شدید که چیزها با هم سازگار هستند، وقت آن رسیده است که پلاگین ESLint را که توسط کامپایلر React طراحی شده است نصب کنید. این افزونه به شما کمک می کند تا هر گونه نقض قوانین React را در کد خود مشاهده کنید. کدهای نقض شده توسط کامپایلر React نادیده گرفته می شود و هیچ بهینه سازی روی آن انجام نمی شود.
npm install eslint-plugin-react-compiler@experimental
سپس فایل پیکربندی ESLint را باز کنید (به عنوان مثال، .eslintrc.cjs
برای Vite) و این تنظیمات را اضافه کنید:
module .exports = { plugins : [ 'eslint-plugin-react-compiler' , ], rules : { 'react-compiler/react-compiler' : "error" , }, }
در مرحله بعد، از افزونه Babel برای کامپایلر React برای فعال کردن کامپایلر برای کل پروژه خود استفاده خواهید کرد. اگر پروژه جدیدی را با React 19 شروع می کنید، توصیه می کنم کامپایلر React را برای کل پروژه فعال کنید. بیایید افزونه Babel را برای کامپایلر React نصب کنیم:
npm install babel-plugin-react-compiler@experimental
پس از نصب، باید با گفت ن گزینههای موجود در فایل پیکربندی Babel، پیکربندی را تکمیل کنید. همانطور که از Vite استفاده می کنیم، فایل vite.config.js
را باز کنید و محتوا را با قطعه کد زیر جایگزین کنید:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' const ReactCompilerConfig = { /* ... */ }; // https://vitejs.dev/config/ export default defineConfig({ plugins : [react({ babel : { plugins : [ [ "babel-plugin-react-compiler" , ReactCompilerConfig ] ], }, })], })
در اینجا، شما babel-plugin-react-compiler
به پیکربندی اضافه کرده اید. ReactCompilerConfig
برای ارائه هر گونه پیکربندی پیشرفته لازم است، مانند زمانی که می خواهید ماژول زمان اجرا سفارشی یا هر پیکربندی دیگر را ارائه دهید. در این مورد، یک شی خالی بدون هیچ گونه تنظیمات پیشرفته است.
همین است. پیکربندی کامپایلر React با پایه کد خود برای استفاده از قدرت آن تمام شده است. از این به بعد، کامپایلر React به هر کامپوننت و قلاب پروژه شما نگاه میکند تا سعی کند بهینهسازیها را روی آن اعمال کند.
اگر میخواهید کامپایلر React را با Next.js، Remix، Webpack و غیره پیکربندی کنید، میتوانید این راهنما را دنبال کنید .
برنامه React بهینه شده با React Compiler
اکنون باید یک برنامه React بهینه شده با گنجاندن کامپایلر React داشته باشید. پس ، بیایید همان تست هایی را که قبلا انجام دادید اجرا کنیم. دوباره، مقدار heading
مولفه ProductPage
را تغییر دهید.
این بار دیگر رندر شدن مجدد اجزای فرزند را نخواهید دید. پس مهر زمانی نیز به روز نمی شود. اما بخشی از مؤلفه را خواهید دید که در آن داده ها تغییر کرده است، زیرا به تنهایی تغییرات را منعکس می کند. همچنین، دیگر نیازی به استفاده از memo
، useMemo()
یا useCallback()
در کد خود نخواهید داشت.
از اینجا می توانید به صورت بصری کارکرد آن را ببینید.
React Compiler در React DevTools
React DevTools نسخه 5.0+ دارای پشتیبانی داخلی از کامپایلر React است. یک نشان با متن Memo ✨
در کنار اجزای بهینهسازی شده توسط کامپایلر React خواهید دید. این فوق العاده است!
Diving Deep – کامپایلر React چگونه کار می کند؟
اکنون که نحوه عملکرد کامپایلر React روی کد React 19 را دیدید، بیایید عمیقاً درک کنیم که در پسزمینه چه اتفاقی میافتد. ما از React Compiler Playground برای تحلیل کدهای ترجمه شده و مراحل بهینه سازی استفاده خواهیم کرد.
ما از مولفه Heading
به عنوان مثال استفاده می کنیم. کد زیر را در سمت چپ ترین قسمت زمین بازی کپی و پیست کنید:
const Heading = ( { heading, totalProducts } ) => { return ( < nav > < h1 className = "text-2xl" > {heading}({totalProducts}) - {Date.now()} </ h1 > </ nav > ) }
خواهید دید که مقداری کد جاوا اسکریپت بلافاصله در زبانه _JS
زمین بازی تولید می شود. کامپایلر React این کد جاوا اسکریپت را به عنوان بخشی از فرآیند کامپایل تولید می کند. بیایید قدم به قدم آن را تحلیل کنیم:
function anonymous_0 ( t0 ) { const $ = _c( 4 ); const { heading, totalProducts } = t0; let t1; if ($[ 0 ] === Symbol .for( "react.memo_cache_sentinel" )) { t1 = Date .now(); $[ 0 ] = t1; } else { t1 = $[ 0 ]; } let t2; if ($[ 1 ] !== heading || $[ 2 ] !== totalProducts) { t2 = ( < nav > < h1 className = "text-2xl" > {heading}({totalProducts}) - {t1} </ h1 > </ nav > ); $[ 1 ] = heading; $[ 2 ] = totalProducts; $[ 3 ] = t2; } else { t2 = $[ 3 ]; } return t2; }
کامپایلر از یک قلاب به نام _c()
برای ایجاد آرایه ای از آیتم ها برای کش استفاده می کند. در کد بالا، آرایه ای از چهار عنصر برای کش کردن چهار آیتم ایجاد شده است.
const $ = _c( 4 );
اما، چه چیزهایی برای ذخیره کردن وجود دارد؟
این کامپوننت دارای دو پایه است، heading
و totalProducts
. کامپایلر باید آنها را کش کند. پس ، به دو عنصر در آرایه اقلام قابل ذخیره سازی نیاز دارد.
قسمت Date.now()
در هدر باید کش شود.
خود JSX باید کش باشد. محاسبه JSX هیچ فایده ای ندارد مگر اینکه یکی از موارد فوق تغییر کند.
پس در مجموع چهار آیتم برای کش وجود دارد.
کامپایلر بلوک های حافظه را با استفاده از if-block
ایجاد می کند. مقدار برگشتی نهایی از کامپایلر JSX است که به سه وابستگی بستگی دارد:
مقدار Date.now()
.
دو غرفه، یک heading
و totalProducts
خروجی JSX زمانی که هر یک از موارد فوق تغییر می کند نیاز به محاسبه مجدد دارد. این بدان معناست که کامپایلر باید برای هر یک از موارد فوق دو بلوک حافظه ایجاد کند.
اولین بلوک ذخیره سازی به صورت زیر است:
if ($[ 0 ] === Symbol .for( "react.memo_cache_sentinel" )) { t1 = Date .now(); $[ 0 ] = t1; } else { t1 = $[ 0 ]; }
بلوک if مقدار Date.now() را در اولین فهرست آرایه کش ذخیره می کند. هر بار از همان استفاده مجدد می کند مگر اینکه تغییر کند.
به طور مشابه، در بلوک دوم حفظ کردن:
if ($[ 1 ] !== heading || $[ 2 ] !== totalProducts) { t2 = ( < nav > < h1 className = "text-2xl" > {heading}({totalProducts}) - {t1} </ h1 > </ nav > ); $[ 1 ] = heading; $[ 2 ] = totalProducts; $[ 3 ] = t2; } else { t2 = $[ 3 ]; }
در اینجا، تحلیل تغییرات ارزش برای سرفصلهای heading
یا totalProducts
است. اگر یکی از این تغییرات تغییر کند، JSX باید دوباره محاسبه شود. سپس تمام مقادیر در آرایه کش ذخیره می شوند. اگر تغییری در مقدار وجود نداشته باشد، JSX محاسبهشده قبلی از حافظه پنهان بازگردانده میشود.
اکنون میتوانید هر کد منبع مؤلفه دیگری را در سمت چپ جایگذاری کنید و به کد جاوا اسکریپت تولید شده نگاه کنید تا به شما کمک کند همانطور که در بالا انجام دادیم بفهمید چه خبر است. این به شما کمک می کند تا درک بهتری از نحوه اجرای کامپایلر تکنیک های حفظ کردن در فرآیند کامپایل داشته باشید.
چگونه می توان از کامپایلر React شرکت کرد و از آن خارج شد؟
هنگامی که کامپایلر React را به روشی که با پروژه Vite خود در اینجا انجام دادیم پیکربندی کردید، برای همه کامپایلرها و هوک های پروژه فعال می شود.
اما در برخی موارد، ممکن است بخواهید به طور انتخابی کامپایلر React را انتخاب کنید. در این صورت، می توانید کامپایلر را در حالت "opt-in" با استفاده از گزینه compilationMode: "annotation"
اجرا کنید.
// Specify the option in the ReactCompilerConfig const ReactCompilerConfig = { compilationMode : "annotation" , };
سپس اجزا و قلابهایی را که میخواهید برای کامپایل انتخاب کنید، با دستورالعمل "use memo"
حاشیهنویسی کنید.
// src/ProductPage.jsx export default function ProductPage ( ) { "use memo" ; // ... }
توجه داشته باشید که دستورالعمل "use no memo"
نیز وجود دارد. ممکن است موارد نادری وجود داشته باشد که مؤلفه شما پس از کامپایل آنطور که پیش بینی می شود کار نکند، و بخواهید تا زمانی که مشکل شناسایی و برطرف شود، به طور موقت از کامپایل انصراف دهید. در این صورت می توانید از این دستورالعمل استفاده کنید:
function AComponent ( ) { "use no memo" ; // ... }
آیا می توانیم از کامپایلر React با React 18.x استفاده کنیم؟
توصیه می شود از کامپایلر React با React 19 استفاده کنید زیرا سازگاری های مورد نیاز وجود دارد. اگر نمی توانید برنامه خود را به React 19 ارتقا دهید، باید یک پیاده سازی سفارشی از تابع کش داشته باشید. می توانید به این موضوع بروید و راه حل را توضیح دهید.
مخازن برای بررسی
تمام کد منبع استفاده شده در این مقاله در این مخزن است.
اگر میخواهید با React 19 و آپشن های آن کدنویسی کنید، در اینجا یک مخزن قالب با React 19 RC، Vite و TailwindCSS پیکربندی شده است . ممکن است بخواهید آن را امتحان کنید.
بعد چه می شود؟
برای یادگیری بیشتر،
مستندات رسمی React Compiler را از اینجا تحلیل کنید.
بحث های کارگروه را تحلیل کنید.
در مرحله بعد، اگر مایلید React
و Next.js
شبیه اکوسیستم آن را با مفاهیم اساسی و پروژه ها یاد بگیرید، یک خبر عالی برای شما دارم: می توانید این فهرست پخش را در کانال یوتیوب من با بیش از 22 آموزش ویدیویی و 12+ مشاهده کنید. ساعت ها محتوای جذاب تا کنون، به صورت رایگان. امیدوارم شما هم خوشتون بیاد.
فعلاً همین است. آیا از خواندن این مقاله لذت بردید و آیا چیز جدیدی یاد گرفتید؟ اگر چنین است، من دوست دارم بدانم که آیا مطالب مفید بوده است یا خیر.
در کانال یوتیوب من مشترک شوید.
اگر نمی خواهید مقدار روزانه نکات مهارتی را از دست بدهید ، من را در X (تویتر ) یا لینکدین دنبال کنید.
کار منبع باز من را در GitHub تحلیل کرده و دنبال کنید.
من مرتباً پستهای معنیداری را در وبلاگ GreenRoots خود منتشر میکنم، ممکن است برای شما نیز مفید باشد.
به زودی با مقاله بعدی من شما را می بینم. تا آن زمان، لطفا مراقب خود باشید و به یادگیری ادامه دهید.
ارسال نظر