نظرات مطالب
بدست آوردن برگهای یک درخت توسط Recursive CTE
من دقیقا متوجه نشدم نتیجه مورد نظر شما چیست.
آیا نتیجه مورد نظر شما به صورت الحاق یافته (concatenated)  هست یا نه؟
در هر صورت باید یکی از دو query زیر نتیجه مورد نظر شما را تولید کند.
declare @t table
(id char(1) primary key,
parent char(1));
 
insert @t values
('A',null),                                   --Level 1
('B', 'A'), ('C', 'A'),                       --Level 2
('D', 'B'), ('E', 'B'),('R','B'), ('F', 'C'), --Level 3
('G', 'D'),                                   --Level 4
('H', 'G'), ('I', 'G');                       --Level 5

;with cte as
(
select id, rnk=0, 
       concats = cast(id as varchar(10))
from @t
where parent is null
 
union all
 
select t.id, rnk+1,
       cast(cte.concats + t.id as varchar(10))
from cte join @t t
on cte.id = t.parent
)
select * from cte
/*
id   rnk         concats
---- ----------- ----------
A    0           A
B    1           AB
C    1           AC
F    2           ACF
D    2           ABD
E    2           ABE
R    2           ABR
G    3           ABDG
H    4           ABDGH
I    4           ABDGI
*/
;with cte as
(
select id, rnk=0, 
       concats = cast(id as varchar(10))
from @t
where parent is null
 
union all
 
select t.id, rnk+1,
       cast(cte.concats + t.id as varchar(10))
from cte join @t t
on cte.id = t.parent
)
select stuff(d.list,1,1,'') as concats
from (select ','+concats
      from cte
  for xml path(''))d(list)
/*
concats
----------------------------------------
A,AB,AC,ACF,ABD,ABE,ABR,ABDG,ABDGH,ABDGI
*/

موفق باشید
مطالب
سری بررسی SQL Smell در EF Core - استفاده از مدل Entity Attribute Value - بخش دوم
در مطلب قبلی، مدل EAV را معرفی کردیم و گفتیم که این نوع پیاده‌سازی در واقع یک SQL Smell است؛ زیرا کوئری نویسی را سخت میکند و همچنین به دلیل عدم امکان تعریف constraints، کنترلی بر روی صحت دیتاهای وارده شد نخواهیم داشت. در نهایت با برنامه‌ای روبرو خواهیم شد که درک صحیحی از ماهیت دیتا ندارد. اما اگر در شرایطی مجبور به استفاده‌ی از این مدل هستید، بهتر است از فرمت JSON برای ذخیره‌سازی دیتای داینامیک استفاده کنید. بیشتر دیتابیس‌های رابطه‌ایی به صورت native از نوع داده‌ایی JSON پشتیبانی میکنند:  
CREATE TABLE EmployeeJsonAttributes (
  Id int NOT NULL AUTO_INCREMENT,
  EmployeeId int NOT NULL,
  Attributes json DEFAULT NULL,
  PRIMARY KEY (Id),
  FOREIGN KEY (EmployeeId) REFERENCES EmployeeEav (Id) ON DELETE CASCADE
)
همانطور که مشاهده می‌کنید در اینجا تایپ ستون Attributes، به JSON تنظیم شده است. بنابراین می‌توانیم از قابلیت‌های توکار دیتابیس (MySQL در مطلب جاری) برای ذخیره و بازیابی داده‌های JSON استفاده کنیم. در ادامه دو روش ذخیره JSON  را مشاهده میکنید: 
INSERT INTO EmployeeJsonAttributes VALUES (
101, 
  '{
  "name": "Jon",
    "lastName": "Doe",
    "dateOfBirth": "1989-01-01 10:10:10+05:30",
    "skills": [ "C#", "JS" ],
    "address":  {
  "country": "UK",
      "city": "London",
      "email": "jon.doe@example.com"
    }
  }'
)

INSERT INTO efcoresample.EmployeeJsonAttributes VALUES (
101, 
  JSON_OBJECT(
"name", "Jon", 
"lastName", "Doe",
"dateOfBirth", "1989-01-01 10:10:10+05:30",
"skills", JSON_ARRAY("C#", "JS"),
    "address", JSON_OBJECT(
  "country", "UK",
      "city", "London",
  "email", "jon.doe@example.com"
    )
  )
)

به عنوان مثال در ادامه میخواهیم کشور محل تولد یک کاربر خاص را نمایش دهیم. برای اینکار می‌توانیم از JSON_EXTRACT استفاده کنیم:
SELECT JSON_EXTRACT(Attributes, '$.address.country') as Country 
FROM EmployeeJsonAttributes
WHERE EmployeeId = 101;

-- Conutry
-- "UK"

همچنین می‌توانیم از عملگر column-path نیز به جای JSON_EXTRACT استفاده کنیم:
SELECT Attributes -> '$.address.country' as Country 
FROM EmployeeJsonAttributes
WHERE EmployeeId = 101;

-- Conutry
-- "UK"

بنابراین به راحتی می‌توانیم کوئری مطلب قبل را اینگونه بازنویسی کنیم:
SELECT EmployeeId, Attributes ->> '$.DateOfBirth' AS BirthDate FROM EmployeeJsonAttributes
WHERE Attributes ->> '$.DateOfBirth' > DATE_SUB(CURRENT_DATE(), INTERVAL 25 YEAR)
همانطور که مشاهده می‌کنید در کوئری فوق یک عملگر < دیگر نیز اضافه کرده‌ایم. هدف از آن حذف “” از خروجی نهایی می‌باشد. 

استفاده از JSON در EF Core 
متاسفانه در EF Core به صورت مستقیم نمی‌توانیم از JSON درون کلاس‌های سی‌شارپ استفاده کنیم (+ )، در نتیجه در سمت کلاس‌های سی‌شارپ باید از string استفاده کنیم و به نوعی به EF Core اطلاع دهیم که تایپ ستون موردنظرمان JSON است. در نتیجه خروجی نهایی درون دیتابیس، یک فیلد با تایپ JSON خواهد بود. برای اینکار به دو شیوه می‌توانیم تایپ ستون موردنظر را تعیین کنیم: 
// Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Employee>(entity =>
    {
        entity.Property(e => e.Attributes).HasColumnType("json");
    });
}

// Data Annotations
[Column(TypeName = "json")]
public string Attributes { get; set; }

در نهایت برای تشکیل بانک اطلاعاتی، به مدلی با ساختار زیر نیاز خواهیم داشت:
public class EmployeeJsonAttribute
{
    public int Id { get; set; }
    public virtual EmployeeEav Employee { get; set; }
    public int EmployeeId { get; set; }
    [Column(TypeName = "json")]
    public string Attributes { get; set; }
}
در اینجا به جای تعریف ستون‌ها و مقادیر داینامیک‌شان از یک فیلد از نوع رشته‌ایی با نام Attributes استفاده شده است. از آنجائیکه نوع ستون در سمت دیتابیس به JSON تنظیم خواهد شد، در نتیجه هر نوع ساختار JSON معتبری را می‌توانیم درون آن ذخیره کنیم:
dbContext.EmployeeJsonAttributes.Add(new EmployeeJsonAttribute
{
    EmployeeId =  101,
    Attributes = JsonSerializer.Serialize(new
    {
        FirstName = "Sirwan",
        LastName = "Afifi",
        DateOfBirth = DateTime.Now.AddYears(-31)
    })
});

dbContext.SaveChanges();
همانطور که اشاره شده به دلیل عدم پشتیبانی از JSON در حال حاضر در EF Core امکان کوئری نویسی بر روی ستون JSON را نداریم. در همین حد که براساس فیلدهای دیگر جستجو را انجام داده و خروجی را Deserialize کنیم:
var employee = dbContext.EmployeeJsonAttributes.Find(201);
Console.WriteLine(JsonSerializer.Deserialize<Employee>(employee.Attributes).DateOfBirth);

برای نوشتن کوئری روی ستون JSON می‌توانید از Query Types  نیز استفاده کنید. 
بازخوردهای دوره
پیاده سازی امتیاز دهی ستاره‌ای به مطالب به کمک jQuery در ASP.NET MVC
سلام، وقتی میخوام این پروژه را به پروژه خودم اضافه کنم در هنگام ایجاد migration دچار خطا شده و میگه برای کلاس Rating باید primary Key تعریف شود آیا نیاز است که پراپرتی id به آن اضافه کرد یا راه حل دیگری دارد؟
خطا:
The entity type 'Rating' requires a primary key to be defined. 
اشتراک‌ها
اضافه شدن امکان تعریف منبع دریافت بسته‌های نیوگت بر اساس الگوهای مشخص
<!-- Microsoft.* packages will only come from nuget.org. -->
<!-- All other packages come from contoso.com by default. -->
<packageSourceMapping>
  <packageSource key="nuget.org">
    <package pattern="Microsoft.*" />
  </packageSource>
  <packageSource key="contoso.com">
    <package pattern="*" />
  </packageSource>
</packageSoureMapping>
اضافه شدن امکان تعریف منبع دریافت بسته‌های نیوگت بر اساس الگوهای مشخص
نظرات مطالب
الگویی برای مدیریت دسترسی همزمان به ConcurrentDictionary
با وجود lazy بودن هم چندین بار امتحان کردم قسمت آپدیت آن فر اخوانی نمی‌شود و همچنان مثل قبل کلیدهای مشابه و تکراری را تولید می‌کند.
 var result = _properties.AddOrUpdate(key
                  k =>
                  {
                      Console.WriteLine("AddValueFactory called for " + k);
                      return new Lazy<int>(() => 1);
                  },
                  (x, y) =>
                  {
                      Console.WriteLine("updateValueFactory called for " + key);
                      return new Lazy<int>(() => y.Value + 1);
                  }).Value;

مطالب
آموزش فایرباگ - #2 - تب Console
در قسمت قبلی با تب‌های فایرباگ آشنا شدیم . در این قسمت و قسمت‌های بعدی ، با هر تب به صورت کامل آشنا خواهیم شد .

در این قسمت با تب Console  آشنا خواهیم شد .
در قسمت قبل در مورد این تب گفتیم :

در این تب دو بخش وجود دارد :
در بخش Log هشدار‌ها ، پیغام‌ها ، درخواست‌های XHR و ... نمایش داده می‌شوند .
بخش دیگر هم که در سمت راست قرار دارد ، مخصوص اجرای کدهای جاوا اسکریپت می‌باشد .

 

پس یک قسمت داریم برای نوشتن کدهای جاوا اسکریپت و یک قسمت هم برای مشاهده‌ی رویداد‌ها .

اکنون 2 سوال مطرح می‌شود :
  1. برای اجرای یک کد در حالت معمول چگونه عمل می‌کنیم ؟
    پاسخ : کدهای مورد نظر را بین تگ باز و بسته‌ی script قرار می‌دهیم و صفحه مورد نظر را در مرورگر باز می‌کنیم و مرورگر کد را اجرا می‌کند .
  2. در صورتی که کدهای ما خطا داشته باشند ، چگونه خطایابی می‌کنیم ؟
    پاسخ : در بین کدهای نوشته شده چند alert قرار می‌دهیم و سعی می‌کنیم مشکل را پیدا کنیم .

همین 2 سوال اهمیت و قدرت فایرباگ و قسمت Console آن را برای ما آشکار می‌کند ، زیرا ما می‌توانیم بدون Reload کردن صفحه ، کدهایمان را اجرا و نتیجه را مشاهده کنیم یا بوسیله توابع موجود خیلی ساده کدهایمان را خطایابی کنیم .



چگونه کدهای نوشته شده را سریع اجرا کنم ؟ کلید میانبر ( HotKey ) اجرای کد‌ها چیست ؟
پاسخ : فشردن کلید CTRL + Enter

امتحان کنید :

کد زیر را در بخش کدنویسی تایپ کنید و بوسیله کلید میانبر گفته شده ، آن را اجرا کنید .
document.getElementsByTagName("div");
 
تصویر ذیل نتیجه اجرای کدی هست که اجرا کردیم .



چند نکته :
  • قسمت هایی که با رنگ قرمز و یک دات ( . ) بعد از نام تگ قرار گرفته اند ، کلاس‌های CSS ای هستند که المنت دارد .
  • قسمت هایی که با رنگ آبی تیره و یک شارپ ( # ) بعد از نام تگ قرار گرفته اند ، ID تگ‌ها هستند .
  • قسمت هایی که کمرنگ هستند ، المنت هایی هستند که در صفحه قابل نمایش نیستند .
  • اگر یک تگ چند کلاس داشته باشد ، فقط اولین کلاس نمایش داده می‌شود .


دکمه‌ها و حالت‌های نمایش بخش کد نویسی

4 دکمه در قسمت کدنویسی وجود دارد :
  1. Run : اجرای کد
  2. Clear : خالی کردن بخش کد نویسی
  3. Copy : کپی کردن کد موجود در بخش کد نویسی در حافظه
  4. History : کدهای نوشته شده در نشست ( Session ) فعلی مرورگر

بخش کد نویسی می‌تواند به 2 شکل نمایش داده شود :
  1. بصورت جعبه چند خطی ( Command Editor )
  2. بصورت تک خطی ( Command Line )
با دکمه‌ی قرمز رنگ موجود در پایین - چپ می‌توانید بین این دو حالت سوئیچ کنید .


9 دکمه هم در بالای بخش log وجود دارد ( به ترتیب از چپ به راست ) :


  • دکمه ای با عنوان “Break On All Errors” . زمانی فعال شود ، در اولین اجرای یک کد از داخل صفحه ، به تب Script منتقل می‌شود و در خطی که کد در حال اجرا است توقف می‌کند .
  • Clear : بخش log را خالی می‌کند .
  • Persist : فعال بودن این دکمه باعث می‌شود که محتویات بخش Console در بارگزاری مجدد صفحه حفظ شود .
  • Profile : بوسیله این گزینه می‌توانید کدهای اجرایی خود در مدت زمان فعال بودن این دکمه ، تحت نظر بگیرید .
    به این صورت که پس از غیر فعال کردن این دکمه ( کلیک مجدد بروی آن ) می‌توانید تابع‌های اجرا شده ، تعداد فراخوانی آنها ، مدت زمان اجرای هر یک ، میانگین زمان اجرای هر بار یک تابع و ... را مشاهده کنید .
  • 5 دکمه‌ی بعدی هم برای فیلتر کردن Log هستند .


نمایش تعداد خطاهای اتفاق افتاده ، در نوار وضعیت ( Status Bar ) :

اگر در زمان فعال بودن فایرباگ ، در صفحه خطایی رخ دهد ، در نوار وضعیت عدد 1 را نمایش می‌دهد و به ازای هر خطای جدید ، یکی به تعداد خطاها اضافه می‌کند .
البته اگر از ورژن‌های جدید فایرفاکس استفاده می‌کنید ، نوار وضعیت را نخواهید داشت و تعداد خطاها را در کنار آیکون فایرباگ خواهید داشت .


در کنار همه این امکانات ، فایرباگ یک مجموعه کامل از توابع کاربردی برای توسعه جاوا اسکریپت و خطایابی جاوا اسکریپت در اختیار ما می‌گذارد .

چند متد کمکی برای نوشتن Log‌های مختلف در Console :
console.debug('This is a Debug message'); 
console.info('This is an Information'); 
console.warn('This is a Warning message'); 
console.error('This is an Error message');


در قسمت بعدی توابع مربوط به توسعه جاوا اسکریپت ( Command Line API & Console API ) در فایرباگ را بررسی خواهیم کرد .
مطالب
مروری بر چند تجربه‌ی کاری با SQLite




SQLite بانک اطلاعاتی سریع، کم حجم و سورس بازی است که استفاده از آن در دات نت فریم ورک بسیار ساده است. فقط کافی است پروایدر مربوط به آن را دریافت کنید و در کدهای قدیمی خود هر جایی مثلا sqlconnection داشتید آن‌را تبدیل به sqliteconnection کنید و امثال آن (به بیان دیگر، پروایدر تهیه شده از معماری ADO.NET پیروی می‌کند و عملا دانش قبلی شما به سادگی قابل استفاده و ارتقاء است). علاوه بر آن پروایدر ADO.NET‌ تهیه شده برای آن، پشتیبانی از Entity framework را هم ارائه می‌دهد.
این دیتابیس تحت سیستم عامل‌های مختلف مهیا است و مهم‌ترین مزیت آن عدم نیاز به نصب آن می‌باشد.

مزایا:
- سورس باز و رایگان
- مهیا بودن آن در سایر پلتفرم‌ها (ویندوز، لینوکس و ...)
- نیازی به نصب ندارد و فقط یک DLL بومی است. این مورد برای کاربرانی که در مدیریت بانک‌های اطلاعاتی پیچیده مشکل دارند، یک مزیت مهم است.
- امکان تشیکل دیتابیس در حافظه. این نکته و توانایی، در آزمون‌های واحد بسیار جالب توجه است. می‌توانید با سرعت بالا دیتابیسی واقعی را در حافظه تشکیل داده، کلیه آزمون‌های واحد خود را اجرا کرده و پس از پایان کار، اثری از دیتابیس و تغییر داده‌ها و مشکلات بازگردانی اطلاعات به حالت اول وجود نخواهد داشت.


ملاحظات:
الف) مرتب سازی SQLite حساس به حروف کوچک و بزرگ است.
برای برگشت به عادت متداولی که وجود دارد می‌شود به صورت زیر عمل کرد:
select f1 from tbl1 order by f1 COLLATE NOCASE
یک COLLATE NOCASE اضافه شده است.

ب) رعایت نکات مرتبط با سیستم‌های 64 بیتی
در مورد سیستم‌های 64 بیتی و دات نت قبلا مطلبی را نوشته بودم : {+}. این مطلب دقیقا اینجا کاربرد پیدا می‌کند، از این لحاظ که SQLite یک بانک اطلاعاتی Native است. اگر برنامه‌ی دات نت شما برای حالت Any CPU تهیه شده است، در سیستم‌های 32 بیتی نیاز است تا DLL مرتبط SQLite را توزیع کنید و در سیستم‌های 64 بیتی DLL مرتبط 64 بیتی آن نیاز خواهد بود. در غیراینصورت برنامه‌ی شما در بدو امر کرش کرده و اجرا نخواهد شد.

مشکلات:
الف) کلید خارجی بی خاصیت!
SQLite از کلید خارجی پشتیبانی می‌کند اما آن‌را اعمال نمی‌کند! برای اینکه کلید خارجی را اعمال کنید باید خودتان تریگر بنویسید تا این‌کار را انجام دهد.

ب) پشتیبانی در حد صفر از مباحث همزمانی و تردینگ.
اگر برنامه شما مالتی ترد است، در بد مخمصه‌ای گرفتار شده‌اید. مدام با پیغام database is locked مواجه خواهید شد. (چه انتظاری داشتید؟ یک dll کمتر از 2 مگابایت که قرار نیست کار غول‌های دیتابیسی را انجام دهد)
بنابراین اصلا تصورش را هم نکنید که از این دیتابیس به عنوان بانک اطلاعاتی یک سایت (و محیط‌های چند کاربره) بتوان استفاده کرد و کاربران دچار مشکل نشوند.

ج)حجم بالای دیتابیس و عدم کش
از مباحث caching که در دیتابیس‌های معظم دیگر به صورت توکار وجود دارد خبری نیست. برای مثال اگر یک کوئری قرار است تعدادی را شمارش نماید، حاصلی کش نشده و اگر صدبار هم به صورت متوالی آن‌را فراخوانی کنید باز هم از نو محاسبات آن انجام خواهد شد.
این مورد در حجم بالای دیتابیس واقعا مهم است و نمودش را با دیتابیسی با حجم بالای یک گیگ به وضوح مشاهده خواهید. افت کارآیی و همچنین قرچ و قرچ مداوم هارد دیسک سیستم! (چون به کش رجوع نمی‌شود)

د) امنیت
روی بانک‌های اطلاعاتی اکسس حداقل می‌توان یک کلمه‌ی عبور را قرار داد (که در کسری از ثانیه قابل شکستن است!). در SQLite استاندارد هیچ خبری از این مباحث نبوده و امنیت را باید خودتان تامین کنید. (البته یک نسخه‌ی تجاری هم از این بانک اطلاعاتی با پشتیبانی از رمزنگاری اطلاعات موجود است : +)

ه) مرتب سازی فارسی
هر چند SQLite هیچ مشکلی در ثبت اطلاعات یونیکد و خصوصا متون فارسی ندارد، اما با مرتب سازی کلمات یونیکد مشکل داشته و بر اساس کد اسکی آن‌ها عمل می‌کند. هر چند امکان تعریف Collation سفارشی در آن ممکن است : + (البته ممکن بودن با موجود بودن متفاوت است)


نتیجه گیری:
- SQLite برای دیتابیسی تا حدود یک گیگ که فقط یک نفر قرار باشد از آن استفاده کند انتخاب بسیار مناسبی است (برای مثال فایرفاکس از آن برای ذخیره سازی تنظیمات خودش استفاده می‌کند).

مطالب
شروع کار با webpack - قسمت دوم
در مطلب قبلی بیشتر از لحاظ تئوریک با وب‌پک آشنا شدیم و در آخر نیز یک تک اسکریپت را با استفاده از آن باندل کرده و در صفحه‌ی index.html اضافه کردیم.

توجه :
در مطلب قبلی برای استفاده و نصب وبپک دو راه پیشنهاد شد؛ یکی نصب وبپک به صورت سراسری و دیگری به صورت محلی در محیط کاری فعلی پروژه. استفاده‌ی نگارنده به صورت محلی می‌باشد و برای فراخوانی وبپک از دستور npm run webpack استفاده خواهد شد. در صورتی که از وبپک به صورت سراسری (گلوبال ) استفاده می‌کنید، به جای این دستور فقط کافی است در خط فرمان دستور webpack را نوشته و آن را اجرا کنید.

اضافه کردن فایل تنظیمات وبپک

وبپک دارای تنظیمات و حالت‌های مختلفی برای تولید خروجی نهایی می‌باشد که می‌توان این تنظیمات را به صورت پارامترهای ورودی، در هنگام فراخوانی برای آن مشخص کرد. ولی برای ساده کردن و همچنین عدم الزام به تکرار برای تنظیمات مورد نیاز می‌توانیم یک فایل پیکربندی را ایجاد کنیم و موارد مورد نیاز را در آن تعریف کرده و تنها با فراخوانی نام webpack در خط فرمان، به صورت خودکار این تنظیمات خوانده شده و دستورات ما اجرا شوند. TaskRunner‌های گالپ و گرانت نیز دارای یک فایل پیکربندی، برای مشخص کردن تنظیمات مورد نیاز کاربر می‌باشند.

ساخت فایل پیکربندی وبپک

در محیط کاری پروژه یک فایل جدید را با نام webpack.config.js ایجاد می‌کنیم، تا پیکر بندی مورد نظرمان را برای وبپک در آن مشخص کنیم (نام این فایل قراردادی است و امکان مشخص کردن فایلی با نام دیگر نیز وجود دارد که در آینده با آن برخورد خواهیم کرد).
این فایل به صورت یک ماژول در فرمت commonjs می‌باشد (در صورتی که با ماژول‌های مختلف آشنا نیستید، مطالعه‌ی این مقاله پیشنهاد می‌شود ماژول‌ها در es6).
پس از ایجاد فایل پیکربندی در محیط کاری پروژه، محتوای زیر را به آن اضافه خواهیم کرد. این حالت را می‌توان ساده‌ترین پیکربندی وبپک دانست و با دستور webpack ./main.js bundle.js که در پایان مطلب قبلی در خط فرمان اجرا کردیم، تفاوتی ندارد.
// webpack.config.js file
module.exports = {
    entry:'./main.js'
    ,output:{
        filename:'bundle.js'
    }
}
پروپرتی entry مشخص کننده‌ی فایل ورودی است که قصد پردازش آن را داریم و پروپرتی output نیز خود یک آبجکت می‌باشد که در ساده‌ترین حالت، احتیاج به تعریف یک پروپرتی با نام filename را در آن داریم که مشخص کننده‌ی نام فایل باندل شونده توسط وبپک می‌باشد.
حال با اجرای دستور npm run webpack، وبپک به صورت خودکار محتوای فایل پیکربندی را خوانده و تنظیمات تعریف شده را در فایل باندل نهایی ترتیب اثر می‌دهد.

حالت نظاره گر یا watch mode

اضافه کردن فایل پیکربندی می‌تواند مفید باشد و ما را از الزام به تکرار برای مشخص کردن پارامترهای مورد نیاز در هر بار اجرای وبپک بی‌نیاز می‌کند. ولی فرض کنید در حال توسعه‌ی پروژه‌ای هستید و مدام در حال تغییر فایل‌های پروژه می‌باشید. فایلی اضافه، حذف و یا دچار تغییر می‌شود و برای هر بار انجام شدن پروسه‌ی باندلینگ باید وبپک را فراخوانی کنیم. برای جلوگیری از این پروسه‌ی تکراری، وبپک دارای حالت نظاره‌گر یا watch mode می‌باشد. معنای این حالت این است که وبپک تغییرات محیط کاری شما را در نظر می‌گیرد و با انجام هر تغییری، دوباره باندل مربوطه را از نو می‌سازد.
برای وارد شدن به این حالت یک راه کار این می‌باشد که در هنگام فراخوانی وبپک در خط فرمان، پرچم زیر را به آن اضافه کنیم:
//for when webpack is installed globally 
webpack --watch
//for when webpack is installed locally in project 
npm run webpack -- --watch
(در فراخوانی بالا دو حالت نصب سراسری و محلی وبپک در نظر گرفته شده‌است. حالت اول نکته‌ای را ندارد. ولی در حالت دوم برای اینکه پارامترهای خط فرمان توسط npm به دست وبپک برسد، احتیاج به اضافه کردن -- می‌باشد. جهت عدم آشنایی با این مورد می‌توانید به اینجا مراجعه کنید: فرستادن پارامتر به اسکریپت‌های npm)
راه کار دوم جهت تنظیم کردن وبپک در حالت نظاره گر، اضافه کردن پروپرتی watch به فایل پیکربندی وبپک است. پس از انجام این تغییر، محتوای فایل پیکربندی به این صورت خواهد بود:
//webpack.config.js file
module.exports = {
    entry:'./main.js'
    ,output:{
        filename:'bundle.js'
    }
    ,watch :true
}
اینبار برای ورود وپ بک به حالت نظاره‌گر کافی است وبپک را یک بار از طریق خط فرمان با دستور npm run webpack، فراخوانی کنیم.
در صورتی که مشکلی وجود نداشته باشد، با اجرای این دستور، کنترل خط فرمان به شما برنخواهد گشت و وبپک در حالت اجرا باقی می‌ماند که در تصویر زیر قابل مشاهده‌است.

حال اگر در اسکریپت main.js تغییری ایجاد کنید، خواهید دید که وبپک به صورت خودکار باندل را از اول خواهد ساخت.

وب سرور وبپک

تا اینجا از وبپک به عنوان یک باندل کننده بهره برده‌ایم و جهت میزبانی فایل‌های پروژه از فایل سیستم و سیستم عامل بهره بردیم. ولی می‌دانیم که در حین توسعه دادن برنامه‌های وب، استفاده از فایل سیستم و سیستم عامل مفید نیست و دچار مشکلات عدیده‌ای هم از سمت مرورگرها و هم از سمت کتابخانه‌های معروف جاوا اسکریپتی خواهیم شد( مانند مباحث cors و ...). جهت حذف این مشکلات می‌توانیم وب سرور مورد علاقه‌ی خود را اجرا کنیم یا از وب سرور فراهم شده توسط وبپک بهره ببریم.
جهت نصب وب سرور وبپک دستور زیر را در خط فرمان  اجرا خواهیم کرد ( به صورت سراسری یا محلی به انتخاب شما خواهد بود و قبلا توضیح داده شده است).
// to install globally :
npm install -g webpack-dev-server

//to install locally in project :
npm install -D webpack-dev-server
در حالتی که وبپک به صورت سراسری نصب شده باشد، با اجرای دستور webpack-dev-server در خط فرمان، وب سرور وبپک شروع به کار خواهد کرد و تنظیمات را نیز از فایل پیکربندی اعمال می‌کند.
در صورتی که وبپک به صورت محلی نصب شده باشد، بایستی یک مدخل به قسمت اسکریپت‌های package.json برای راهنمایی npm اضافه کنیم. محتویات این فایل پس از تغییرات، از این قرار است:
//package.json file
{
  "name": "dntwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "webpack": "webpack",
    "webpackserver": "webpack-dev-server"
  },
  "author": "mehdi",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^1.13.1",
    "webpack-dev-server": "^1.14.1"
  }
}
در اینجا پروپرتی جدیدی به قسمت scripts، با نام webpackserver اضافه شده‌است. حال با فراخوانی این اسکریپت با دستور زیر، وب سرور وبپک شروع به کار خواهد کرد:
npm run webpackserver
(دقت کنید که نام‌های قرار داده شده‌ی در قسمت scripts می‌توانند به صورت دلخواه باشند و شما می‌توانید نامی را که دلخواه خودتان است، برگزینید؛ به طور مثال به جای webpackserver نام دیگری را در فایل package.json برای آن مشخص کنید و در هنگام فراخوانی از آن استفاده کنید).
در صورتی که همه چیز بدون مشکل باشد، خروجی شبیه به تصویر زیر را مشاهده خواهید کرد که آدرسی که به صورت محلی، سرور بر روی آن میزبان شده است نیز قابل مشاهده است:


باندل کردن اسکریپت‌های گوناگون توسط وبپک

تا اینجای کار تنها از یک تک اسکریپت، با نام main.js استفاده کردیم. قطعا پروژه‌های واقعی از یک تک اسکریپت تشکیل نخواهند شد و اسکریپت‌های گوناگونی خواهیم داشت. جهت استفاده از چندین اسکریپت توسط وبپک، دو سناریوی مختلف رخ خواهند داد که هر دو را برسی خواهیم کرد:
اضافه کردن اسکریپت‌ها به صورت داینامیک یا پویا توسط وبپک 

در محیط کاری پروژه، یک فایل جدید user.js را اضافه می‌کنیم که از این فایل در فایل main.js استفاده خواهد شد.
محتوای فایل user.js یک تابع ساده‌ی جاوا اسکریپتی خواهد بود:
// user.js file 

function userLog() {
    console.log("ahooy from user module file");
}

module.exports={
    userLog:userLog
}  
حال جهت استفاده از این ماژول در فایل main.js تغییرات زیر را اعمال خواهیم کرد:
//main.js file

var user = require("./user");

user.userLog();

console.log(`i'm bundled by webpack`);
پس از ذخیره‌ی تغییرات خواهید دید که وب سرور وبپک از این تغییرات آگاه شده و باندل جدید را خواهد ساخت که در اینجا خروجی مانند تصویر زیر را خواهید دید:
در تصویر قابل مشاهده است که ماژول user.js نیز وارد باندل شده است.


در صورتی که به مسیری که وبپک در حال میزبانی بر روی آن است در مرورگر خود مراجعه کنید، پیغام‌های چاپ شده را در کنسول مشاهده خواهید کرد.

اضافه کردن اسکریپت‌ها به باندل به صورت استاتیک توسط وبپک

قطعا در پروژه‌های خود از کتابخانه‌هایی که توسط برنامه نویسان دیگر تولید شده‌اند مانند جی کوئری و ... استفاده خواهیم کرد. استفاده از این اسکریپت‌ها به صورت داینامیک و ایمپورت کردن آنها در هر ماژول جالب نخواهد بود و یا ممکن است ماژولی که خود شما نوشته اید به صورت اشتراکی بین تمام برنامه اجرا شود. در این گونه از موارد می‌توانیم این اسکریپت‌ها را در فایل پیکربندی به وبپک معرفی کنیم تا در هنگام باندلینگ، به باندل وارد شوند.
اسکریپت جدیدی را در پروژه اضافه می‌کنیم و نامش را shared.js می‌گذاریم که دارای محتوای زیر است :
// shared.js file
console.log('log message from shared module !');
حال برای اینکه این اسکریپت را به وبپک معرفی کنیم، فایل پیکربندی وبپک را باز کرده و تغییرات زیر را در آن اعمال می‌کنیم :
//webpack.config.js file
module.exports = {
    entry:['./shared.js','./main.js']
    ,output:{
        filename:'bundle.js'
    }
    ,watch :true
}
قابل مشاهده است که قسمت entry، به جای این که یک تک فایل را معرفی کند، تبدیل به یک آرایه شده‌است که هم فایل shared.js را در بر می‌گیرد و هم فایل main.js را دارد.
در مواقعی که فایل پیکربندی دچار تغییر می‌شود، بایستی وبپک را متوقف و دوباره اجرا کنید تا تنظیمات جدید، اعمال شوند. پس از راه اندازی دوباره وبپک، در صورت موفقیت آمیز بودن تغییراتتان، خروجی را شبیه تصویر رو به رو خواهید گرفت و مشخص است که فایل shared.js نیز در باندل وارد شده است.


استفاده از Loader‌ها در وبپک

به صورت پیش فرض وبپک قابلیت باندل کردن ماژول‌های جاوا اسکریپت را دارد و همچنین می‌تواند این فایل‌ها را Minify  کند (در مطالب بعدی خواهیم دید). ولی به طور مثال استفاده از تایپ اسکریپت از توانایی‌های وبپک به صورت توکار خارج است. اینجاست که Loader‌ها وارد کار می‌شوند.
اگر بخواهیم به زبان ساده Loader‌‌ها را تعریف کنیم می‌توان  آنها را کامپوننت هایی دانست که به وبپک فوت و فن کار جدیدی را یاد می‌دهند.
در ادامه Loader تایپ اسکریپت را نصب خواهیم کرد و به کمک آن فایل‌های پروژه را تبدیل به تایپ اسکریپت کرده و در هنگام باندل کردن از وبپک می‌خواهیم که این فایل‌ها را ترنسپایل کند و سپس باندل را از روی آنها بسازد ( برای مطالعه‌ی ادامه‌ی این مطلب احتیاجی به آشنایی به تایپ اسکریپت نیست و هدف استفاده از یک loader است. ولی در صورت علاقه می‌توانید به اینجا مراجعه کنید سری آموزش تایپ اسکریپت)

نصب Loader تایپ اسکریپت 

به خط فرمان برگشته و با استفاده از npm، لودر تایپ اسکریپت مورد نیاز وبپک را نصب می‌کنیم. دستور مورد نیاز این قرار است :
npm install -D ts-loader

( توجه :
در ادامه این مطلب از پیکربندی ساده‌ی یک پروژه‌ی تایپ اسکریپتی استفاده شده است که اعم از ایجاد فایل tsconfig.json و اضافه کردن پوشه‌ی typings به پروژه می‌باشد.)
فایل main.ts را که یک فایل تایپ اسکریپتی می‌باشد، به پروژه اضافه می‌کنیم. محتوای آن به صورت زیر خواهد بود. قابل مشاهده است که از ویژگی‌های ES6 در این فایل استفاده شده و این انتظار را از لودر تایپ اسکریپت داریم که این فایل را در هنگام باندلینگ برای ما ترنسپایل کند.
// main.ts file
let user = require("./user");

user.userLog();
let mainlogger = () => {
    console.log(`i'm bundled by webpack in an arrow function`);
}

mainlogger();
برای اینکه به وبپک خبر دهیم که در پروژه در حال استفاده از تایپ اسکریپت هستیم، فایل پیکربندی وبپک را باز کرده و پروپرتی جدیدی را با نام module به آن معرفی می‌کنیم که خود یک آبجکت می‌باشد. حال در آبجکت module یک پروپرتی جدید را با نام loaders که جنس آرایه‌ای دارد، اضافه می‌کنیم. آرایه‌ی loaders شامل همه‌ی loader هایی خواهد بود که شما قصد استفاده‌ی آنها را به همراه وبپک دارید. هر عضو از این آرایه خود نیز یک آبجکت می‌باشد که دارای سه پروپرتی زیر می‌باشد:
test : یک رجکس می‌باشد که به loader می‌گوید به دنبال چه فایل‌هایی بگردد.
exclude : از جنس رجکس و مشخص کننده‌ی مسیرهایی است که از پروژه باید جدا شوند و توسط loader پردازش نشوند (مانند فایل‌های از قبل کامپایل شده‌ی کتابخانه‌ها).
loader : مشخص کننده‌ی نام loader مورد نظر .
محتوای فایل پیکربندی وبپک، پس از معرفی loader تایپ اسکریپت، به این صورت خواهد بود:
//webpack.config.js
module.exports = {
    entry:['./shared.js','./main.js']
    ,output:{
        filename:'bundle.js'
    }
    ,watch :true
    ,module:{
        loaders:[
            {
                test:/\.ts$/
                ,exclude:/node_modules/
                ,loader:'ts-loader'
            }
        ]
    }
}
حال با اجرای دوباره‌ی وبپک، loader تایپ اسکریپت ابتدا اجرا شده، سپس وبپک وارد کار می‌شود و فایل‌ها را باندل خواهد کرد. در صورتی که بدون مشکل همه چیز اجرا شود، خروجی مانند تصویر زیر را خواهید داشت:

در این مطلب تنظیمات مختلف وبپک، فایل پیکربندی، استفاده از چندین فایل به همراه وبپک، وب سرور وبپک و همچنین با loader‌های وبپک آشنا شدیم.
دریافت فایل‌ها dntwebpack-part2.zip  
اشتراک‌ها
معرفی RabbitMQ: بخش دوم، آشنایی با Exchange ها، Routing Key ها و Binding ها

در این بخش یاد میگیریم که Exchange و Binding و Routing Key چیست؟ اینکه Exchange‌ها و Queue‌ها چطور با هم ارتباط برقرار می‌کنند؟ تفاوت انواع Exchange‌ها و سناریو‌های استفاده از آن‌ها را در RabbitMQ یادمیگیریم

معرفی RabbitMQ: بخش دوم، آشنایی با Exchange ها، Routing Key ها و Binding ها
اشتراک‌ها
قوانین UX

Laws of UX is a collection of the key maxims that designers must consider when building user interfaces

قوانین UX