لینکهای هفته سوم دی
وبلاگها ، سایتها و مقالات ایرانی (داخل و خارج از ایران)
ASP. Net
- ویدیویی دربارهی ASP.Net 4 (بهبودهای حاصل شده در web forms از جهت کار با اسکریپتها خصوصا با تاکید بر jQuery و همچنین ذکر اینکه با آمدن ASP.Net MVC ، وب فرمها کهنه نشده و همچنان توسعه و بهبود داده خواهند شد)، یا مقالهای در این مورد
طراحی و توسعه وب
PHP
اسکیوال سرور
سی شارپ
عمومی دات نت
مسایل اجتماعی و انسانی برنامه نویسی
متفرقه
SQLite و EF6 و Code First
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت سوم - تکمیل مستندات یک API با کامنتها
استفاده از XML Comments برای بهبود کیفیت مستندات API
نوشتن توضیحات XML ای برای متدها و پارامترها در پروژههای داتنتی، روشی استاندارد و شناخته شدهاست. برای نمونه در AuthorsController، میخواهیم توضیحاتی را به اکشن متد GetAuthor آن اضافه کنیم:
/// <summary> /// Get an author by his/her id /// </summary> /// <param name="authorId">The id of the author you want to get</param> /// <returns>An ActionResult of type Author</returns> [HttpGet("{authorId}")] public async Task<ActionResult<Author>> GetAuthor(Guid authorId)
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup>
اکنون نیاز است وجود این فایل را به تنظیمات SwaggerDoc در کلاس Startup برنامه، اعلام کنیم:
namespace OpenAPISwaggerDoc.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc( // ... ); var xmlCommentsFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlCommentsFullPath = Path.Combine(AppContext.BaseDirectory, xmlCommentsFile); setupAction.IncludeXmlComments(xmlCommentsFullPath); }); }
پس از این تنظیمات اگر برنامه را اجرا کنیم، در Swagger-UI حاصل، این تغییرات قابل مشاهده هستند:
افزودن توضیحات به Response
تا اینجا توضیحات پارامترها و متدها را افزودیم؛ اما response از نوع 200 آن هنوز فاقد توضیحات است:
علت را نیز در تصویر فوق مشاهده میکنید. قسمت responses در OpenAPI specification، اطلاعات خودش را از اسکیمای مدلهای مرتبط دریافت میکند. بنابراین نیاز است کلاس DTO متناظر با Author را به نحو ذیل تکمیل کنیم:
using System; namespace OpenAPISwaggerDoc.Models { /// <summary> /// An author with Id, FirstName and LastName fields /// </summary> public class Author { /// <summary> /// The id of the author /// </summary> public Guid Id { get; set; } /// <summary> /// The first name of the author /// </summary> public string FirstName { get; set; } /// <summary> /// The last name of the author /// </summary> public string LastName { get; set; } } }
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup> </Project>
namespace OpenAPISwaggerDoc.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc( // ... ); var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml", SearchOption.TopDirectoryOnly).ToList(); xmlFiles.ForEach(xmlFile => setupAction.IncludeXmlComments(xmlFile)); }); }
در این حالت اگر مجددا برنامه را اجرا کنیم، خروجی ذیل را در قسمت schemas مشاهده خواهیم کرد:
بهبود مستندات به کمک Data Annotations
اگر به اکشن متد UpdateAuthor در کنترلر نویسندگان دقت کنیم، چنین امضایی را دارد:
[HttpPut("{authorId}")] public async Task<ActionResult<Author>> UpdateAuthor(Guid authorId, AuthorForUpdate authorForUpdate)
using System.ComponentModel.DataAnnotations; namespace OpenAPISwaggerDoc.Models { /// <summary> /// An author for update with FirstName and LastName fields /// </summary> public class AuthorForUpdate { /// <summary> /// The first name of the author /// </summary> [Required] [MaxLength(150)] public string FirstName { get; set; } /// <summary> /// The last name of the author /// </summary> [Required] [MaxLength(150)] public string LastName { get; set; } } }
بهبود مستندات متد HttpPatch با ارائهی یک مثال
دو نگارش از اکشن متد UpdateAuthor در این مثال موجود هستند:
یکی HttpPut است
[HttpPut("{authorId}")] public async Task<ActionResult<Author>> UpdateAuthor(Guid authorId, AuthorForUpdate authorForUpdate)
[HttpPatch("{authorId}")] public async Task<ActionResult<Author>> UpdateAuthor( Guid authorId, JsonPatchDocument<AuthorForUpdate> patchDocument)
بهتر است در این حالت مثالی را به استفاده کنندگان از آن ارائه دهیم تا در حین کار با آن، به مشکل برنخورند:
/// <summary> /// Partially update an author /// </summary> /// <param name="authorId">The id of the author you want to get</param> /// <param name="patchDocument">The set of operations to apply to the author</param> /// <returns>An ActionResult of type Author</returns> /// <remarks> /// Sample request (this request updates the author's first name) \ /// PATCH /authors/id \ /// [ \ /// { \ /// "op": "replace", \ /// "path": "/firstname", \ /// "value": "new first name" \ /// } \ /// ] \ /// </remarks> [HttpPatch("{authorId}")] public async Task<ActionResult<Author>> UpdateAuthor( Guid authorId, JsonPatchDocument<AuthorForUpdate> patchDocument)
روش کنترل warningهای کامنتهای تکمیل نشده
با فعالسازی GenerateDocumentationFile در فایل csproj برنامه، کامپایلر، بلافاصله برای تمام متدها و خواص عمومی که دارای کامنت نیستند، یک warning را صادر میکند. یک روش برطرف کردن این مشکل، افزودن کامنت به تمام قسمتهای برنامه است. روش دیگر آن، تکمیل خواص کامپایلر، جهت مواجه شدن با عدم وجود کامنتها در فایل csproj برنامه است:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors>false</TreatWarningsAsErrors> <WarningsAsErrors>NU1605;</WarningsAsErrors> <NoWarn>1701;1702;1591</NoWarn> </PropertyGroup>
- اگر میخواهید خودتان را مجبور به کامنت نویسی کنید، میتوانید نبود کامنتها را تبدیل به error کنید. برای این منظور خاصیت TreatWarningsAsErrors را به true تنظیم کنید. در این حالت هر کامنت نوشته نشده، به صورت یک error توسط کامپایلر گوشزد شده و برنامه کامپایل نخواهد شد.
- اگر TreatWarningsAsErrors را خاموش کردید، هنوز هم میتوانید یکسری از warningهای انتخابی را تبدیل به error کنید. برای مثال NU1605 ذکر شدهی در خاصیت WarningsAsErrors، مربوط به package downgrade detection warning است.
- اگر به warning نبود کامنتها دقت کنیم به صورت عبارات warning CS1591: Missing XML comment for publicly visible type or member شروع میشود. یعنی CS1591 مربوط به کامنتهای نوشته نشدهاست. میتوان برای صرفنظر کردن از آن، شمارهی این خطا را بدون CS، توسط خاصیت NoWarn ذکر کرد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: OpenAPISwaggerDoc-03.zip
در قسمت بعد، مشکل خروجی تولید response از نوع 200 را که در قسمت دوم به آن اشاره کردیم، بررسی خواهیم کرد.
Hello, you should definitely check this thing out http://www.newsl5.net/biz/?page=xyz
این ایمیلها هم جعلی نبودند. یعنی واقعا از اکانت یاهوی من ارسال شده بودند و در قسمت sent وجود خارجی داشتند! فقط IP ارسال کننده آن (115.78.224.246) متعلق به کشور ویتنام بود (IP ارسال کننده را در هدر ایمیل ارسالی میتوان مشاهده کرد).
این مساله باعث شد که من سیستم را چندین بار چک کنم؛ از لحاظ بحث ویروس تا اسپایور و غیره. «هیچ» مشکلی مشاهده نشد.
مرحله بعد کمی در مورد یاهو جستجو کردم و مشخص شد که یاهو با session hijacking به شدت مشکل دارد. همچنین ابزار دیگری که میتواند به این session hijacking کمک کند خود «فایرفاکس» است. فایرفاکس حاوی گزینهای است که سشنهای قبلی شما را ذخیره میکند. زمانیکه مرورگر را بسته و پس از مدتی آنرا باز میکنیم، یک راست و قشنگ همان سشن قبلی مثلا یاهو را بازیابی کرده و کار ادامه پیدا میکند.
کمی گشتم و این قابلیت رو به کل غیرفعال کردم. برای غیرفعال کردن آن «Disable Session Restore in Firefox» را در گوگل جستجو کنید.
و خلاصه آن به صورت زیر است:
در نوار آدرس فایرفاکس تایپ کنید about:config
در ادامه موارد زیر را یافته و غیرفعال کنید:
browser.sessionstore.resume_from_crash;false browser.sessionstore.resume_session_once;false browser.sessionstore.restore_pinned_tabs_on_demand;false browser.sessionstore.restore_hidden_tabs;false services.sync.prefs.sync.browser.sessionstore.restore_on_demand;false
راه سادهتر:
افزونه session manager را نصب کنید
در قسمت session manager options در برگه startup & shutdown آن کلا بحث ذخیره سازی سشن در حین بسته شدن مرورگر را غیرفعال کنید.
و به صورت خلاصه: تنظیمات پیش فرض فایرفاکس از لحاظ امنیتی مناسب نیستند.
ضمن اینکه ایمیل فوق رو من هفتهای یکی دو بار از تمام افرادی که میشناسم دریافت میکنم! به عبارتی خیلیها گرفتار این مساله شدهاند.
ذخیره سازی سشنها به نظر کارها رو ساده میکنه. مرورگر رو باز میکنی همه چیز مثل قبل از بسته شدن آن است و ... همین یعنی مشکل امنیتی. خصوصا مراجعه به سایتها و لینکهایی که از باگهای XSS سوء استفاده میکنند.
> ng generate <blueprint> <options>
ایجاد کامپوننتهای جدید توسط Angular CLI
دستور ایجاد یک کامپوننت جدید توسط Angular CLI به نحو زیر است:
> ng generate component customer
> ng g c customer
گزینههای ایجاد کدهای جدید در Angular CLI
اگر به اولین دستور بحث جاری دقت کنید، قسمت <options> نیز برای آن درنظر گرفته شدهاست. تعدادی از مهمترین گزینههایی را که در اینجا میتوان ذکر کرد به شرح زیر هستند:
گزینه | Alias (میانبر/نام مستعار) | توضیح |
flat-- | آیا باید برای آن پوشهای ایجاد نشود؟ (flat = بدون پوشه در اینجا) (پیش فرض آن ایجاد یک پوشهی جدید است). اگر میخواهیم ایجاد نشود، باید flat true-- را ذکر کرد. | |
inline-template-- | it- | آیا قالب کامپوننت، درون فایل ts. آن قرار گیرد؟ (پیش فرض آن، false است) |
inline-style-- | is- | آیا شیوه نامهی کامپوننت، داخل فایل ts. آن قرار گیرد؟ (پیش فرض آن، false است) |
spec-- | آیا فایل spec نیز تولید شود؟ (پیش فرض آن true است) اگر میخواهیم این فایل ایجاد نشود باید spec false-- را ذکر کرد. | |
view-encapsulation-- | ve- | تعیین نوع استراتژی view encapsulation مورد استفاده (مانند Emulated). |
change-detection-- | cd- | تعیین استراتژی change detection مورد استفاده (مانند OnPush). |
dry-run-- | d- | گزارش فایلهای تولیدی، بدون نوشتن و تولید آنها (پیش فرض آن false است) |
prefix-- | تعیین صریح prefix مورد استفادهی در حین مقدار دهی selectorها که در قسمت قبل در مورد آن بحث شد. |
برای مثال اگر خواستیم کامپوننتی را به همراه قالبها و شیوهنامههای inline (قرار گرفتهی داخل فایل ts. آن) تولید کنیم، میتوان از دستور ذیل کمک گرفت:
>ng generate component customer --inline-template --inline-style
>ng g c customer –it -is
اگر صرفا دستور ng generate component customer را اجرا کنیم (بدون هیچ گزینهی اضافهتری)، فایلهای ts (کلاس کامپوننت)، css (فایل شیوه نامه)، html (فایل قالب) و spec (فایل آزمون واحد کامپوننت) به صورت خودکار تولید خواهند شد.
همانطور که پیشتر نیز عنوان شد، اگر مطمئن نیستید که دستور درحال فراخوانی، چه فایلها و پوشههایی را ایجاد میکند، با ذکر پرچم dry-run-- و یا به صورت خلاصه d-، دستور مدنظر را شبیه سازی کنید تا صرفا گزارشی را از فایلهایی که قرار است تولید شوند، ارائه دهد.
نکتهی مهم دیگری که به همراه دستورات Angular CLI هستند، به روز رسانی خودکار فایل app.module.ts است:
>ng g c customer installing component create src\app\customer\customer.component.css create src\app\customer\customer.component.html create src\app\customer\customer.component.spec.ts create src\app\customer\customer.component.ts update src\app\app.module.ts
import { CustomerComponent } from './customer/customer.component'; @NgModule({ declarations: [ AppComponent, CustomerComponent ]})
مشاهدهی تغییرات انجام شدهی توسط Angular CLI به کمک سورس کنترل
همانطور که در قسمت قبل نیز عنوان شد، دستور ng new، کار آغاز یک مخزن Git را نیز به صورت خودکار انجام میدهد. در اینجا هر دستوری که توسط Angular CLI اجرا شود، به این مخزن کد commit خواهد شد.
برای مثال اگر کل پوشهی برنامه را توسط VSCode باز کنیم (کلیک راست در داخل ریشهی اصلی پروژه و انتخاب گزینهی Open With Code)، با مراجعهی به لیست تغییرات و بررسی diff آنها، به سادگی میتوان تشخیص داد که چه تغییراتی بر روی فایلها اعمال شدهاند.
ایجاد سایر اجزای جدید برنامه توسط Angular CLI
نام جزء | Alias | دستور |
service | s | ng g service customer-data |
pipe | p | ng g pipe init-caps |
class | cl | ng g class customer-model |
directive | d | ng g directive search |
interface | i | ng g interface orders |
enum | e | ng g enum gender |
module | m | ng generate module sales |
نکات تکمیلی
- در حین ایجاد یک directive جدید، پوشهای را برای آن ایجاد نمیکند. اگر میخواهید اینکار به صورت flat (بدون پوشه در اینجا) انجام نشود، گزینهی flat false-- را نیز قید کنید.
- در حین ایجاد یک سرویس جدید، اخطار «WARNING Service is generated but not provided, it must be provided to be used» را دریافت خواهید کرد. علت اینجا است که Angular CLI نمیداند که این سرویس را باید به کامپوننت خاصی اضافه کند یا به ماژول برنامه. به همین جهت یا باید به صورت دستی فایل src\app\app.module.ts را ویرایش و قسمت providers آنرا بر اساس نام این سرویس جدید تکمیل کرد و یا توسط سوئیچ m میتوان ماژول مدنظر را دقیقا ذکر کرد:
> ng g s sales -m app.module
این نکته در مورد تمام اجزایی که فایل app.module را به روز رسانی میکنند نیز صادق است. اگر برای مثال کامپوننتی قرار است ماژول جدید دیگری را به روز رسانی کند، میتوانید به صورت صریح نام ماژول آنرا قید کنید؛ در غیراینصورت از همان app.module پیش فرض استفاده خواهد شد.
- همانطور که مشاهده میکنید امکان تولید کلاس، اینترفیس و enum تایپاسکریپتی نیز در اینجا پیش بینی شدهاست. اگر خواستید کلاسی را درون پوشهی خاصی قرار دهید میتوانید محل پوشهی آنرا دقیقا ذکر کنید (در مورد اینترفیسها و enums و سایر اجزاء نیز به همین صورت):
> ng g cl models/customer
تغییر تنظیمات پیش فرض تولید کد پروژهی جاری
در قسمت قبل «تغییر پیش فرضهای عمومی Angular CLI» را بررسی کردیم. در اینجا نیز میتوان یکسری از خواص فایل angular-cli.json. را بازنویسی کرد؛ در قسمت defaults آن:
"defaults": { "styleExt": "css", "component": {} }
> ng set defaults.component.flat false > ng set defaults.directive.flat false > ng set defaults.styleExt sass
"defaults": { "styleExt": "sass", "component": { "flat": false }, "directive": { "flat": false } }
و اگر VSCode استفاده میکنید، به همراه intellisense کاملی در مورد اجزای مختلف این فایل json است (این intellisense را به صورت خودکار بر اساس اسکیمای این فایل و سرویس زبان Angular تهیه میکند).
که بعد از بررسی به راه حلهای زیر رسیدم:
راه حل اول
بعد از اجرای وب سرویس و باز کردن آدرس آن به صورت HTTPS در مرورگر، پیام مبنی بر عدم اعتبار گواهی HTTPS را در آدرس وارد شده، مشاهده میکنیم. (Untrusted certificate) (که نسبت به مرورگر استفاده شده، این پیام متفاوت است و من در اینجا از مرورگر IE استفاده میکنم)
- بر روی Certificate error در نوار آدرس، کلیک کرده و View certificates را انتخاب میکنیم.
- وقتی پنجره Certificate باز شد بر روی دکمه Install Certificate کلیک کرده و پنجره Certificate Import Wizard باز شده و Next را میزنیم و Place all certificates in the following store را انتخاب میکنیم و بر روی دکمه Browse کلیک میکنیم.
- از پنجره باز شده Trusted Root Certification Authorities را انتخاب میکنیم و بر روی دکمه OK، کلیک میکنیم.
- سپس Next را میزنیم و در پایان بر روی دکمه Finish کلیک میکنیم.
- پس از اتمام Wizard، پنجره Security Warning به شما نمایش داده میشود که باید بر روی Yes آن کلیک کنید، بعد از تایید، پیام .The import was successful به شما نمایش داده میشود.
راه حل دوم
ممکن است کامپیوتر شما با توسعه دهندگان دیگر که با حساب کاربری خود وارد میشوند، مشترک باشد و بخواهید اطلاعات مربوط به گواهی اعتبار، به صورت مشترک استفاده شود. جزئیات در این روش بیشتر از روش قبل است.
- بازکردن پنجره Run و وارد کردن دستور mmc و زدن دکمه OK.
- اضافه کردن Snap-in
- انتخاب Add/Remove Snap-in از منوی File
- انتخاب Certificates از لیست سمت چپ و انتخاب دکمه Add
- در پنجره Certificates Snap-ins انتخاب گزینه Computer account و انتخاب دکمه Next
- انتخاب Local computer و کلیک بر روی دکمه Finish
- انتخاب دکمه OK
- استخراج IIS Express certificate از computer’s personal store
- در قسمت Console Root ، بخش Certificates (Local Computer)، سپس قسمت Personal و انتخاب Certificates.
- انتخاب گواهی با مشخصات زیر:
- "Issued to = "localhost
- "Issued by = "localhost
- "Friendly Name = "IIS Express Development Certificate
- انتخاب گزینه Export از زیرمنوی All Tasks در منوی Action
- پنجره Certificate Export Wizard باز شده و انتخاب دکمه Next
- انتخاب No, do not export the private key و انتخاب دکمه Next
- انتخاب DER encoded binary X.509 (.CER) و انتخاب دکمه Next
- انتخاب مسیر ذخیره فایل گواهی تصدیق مجوز و انتخاب دکمه Next
- انتخاب دکمه Finish برای انجام عملیات Export و مشاهده پیام موفقیت
- وارد کردن IIS Express certificate به computer’s Trusted Root Certification Authorities store
- در قسمت Console Root ، بخش Certificates (Local Computer)، سپس قسمت Trusted Root Certification Authorities و انتخاب Certificates.
- انتخاب گزینه Import از زیرمنوی All Tasks در منوی Action
- پنجره Certificate Export Wizard باز شده و انتخاب دکمه Next
- انتخاب مسیر فایل ذخیره شده در مرحله قبل و انتخاب دکمه Next
- انتخاب Place all certificates in the following store و در قسمت Certificate store ، انتخاب بخش Trusted Root Certification Authorities و انتخاب دکمه Next
- انتخاب دکمه Finish برای انجام عملیات Import و مشاهده پیام موفقیت و مشاهده گواهی تصدیق مجوز با نام localhost در لیست Trusted Root Certification Authorities
راه حل سوم
با استفاده از Developer Command Prompt نیز میتوان این کار را انجام داد.
- با اجرای دستور زیر و دریافت فایل خروجی
makecert -r -n "CN=localhost" -b 01/01/2000 -e 01/01/2099 -eku 1.3.6.1.5.5.7.3.1 -sv localhost.pvk localhost.cer cert2spc localhost.cer localhost.spc pvk2pfx -pvk localhost.pvk -spc localhost.spc -pfx localhost.pfx
- اجرای فایل localhost.pfx و وقتی پنجره Certificate Import Wizard باز شد، Next را میزنیم.
- نام فایل انتخاب شده را در این قسمت مشاهده میکنیم و Next را میزنیم.
- در صورت داشتن کلمه عبور، آن را وارد کرده (که در اینجا کلمه عبوری را تعریف نکردهایم) و Next را میزنیم.
- صفحه Place all certificates in the following store را انتخاب میکنیم و بر روی دکمه Browse کلیک میکنیم.
- از پنجره باز شده، Trusted Root Certification Authorities را انتخاب میکنیم و بر روی دکمه OK، کلیک میکنیم.
- سپس Next را میزنیم و در پایان بر روی دکمه Finish کلیک میکنیم.
- پس از اتمام Wizard، پنجره Security Warning به شما نمایش داده میشود که باید بر روی Yes کلیک کنید. بعد از تایید، پیام .The import was successful به شما نمایش داده میشود.
نکته: در صورتی که بخواهید برنامه شما (windows form) بتواند به سرور از طریق HTTPS اتصال پیدا کند، باید این فایل pfx بر روی هر کلاینت نصب شده باشد. شما میتوانید با اجرای دستور زیر در ابتدای فایل program.cs این کار را انجام دهید.
var cert = new X509Certificate2( Properties.Resources.localhost ); var store = new X509Store( StoreName.AuthRoot, StoreLocation.LocalMachine ); store.Open(OpenFlags.ReadWrite); store.Add(cert); store.Close();
منسوخ شدن DllImport در دات نت 7
dotnet add package Microsoft.Windows.CsWin32 --prerelease
DwmRegisterThumbnail DwmUpdateThumbnailProperties DWM_TNP_*
// نصب لودرهای مورد نظر npm install css-loader style-loader -D
//index.html file <html> <head> <title>webpack part 4</title> </head> <body> <h1>webpack is awesome</h1> <p>part 4 of tutorial</p> <div>i have a background</div> <h1>تست فونت !</h1> <script src="/assets/js/bundle.js"> </script> </body> </html>
//webpack.config.js var path = require("path"); var webpack = require("webpack"); module.exports = { context: path.resolve("js"), entry: ['./main.js'] , output: { path: path.resolve("build/js"), publicPath: "assets/js", filename: 'bundle.js' }, devServer: { contentBase: "assets" } , watch: true , module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader' } ] } }
loader:'style-loader!css-loader'
// main.js file require("./../assets/main.css"); console.log(`i'm bundled by webpack`);
// main.css body{ background-color: #DAA520; }
در تصویر بالا مشخص است که در تگ Head صفحه، یک تگ جدید style، توسط وبپک ایجاد شده و استایل ما به صفحه تزریق شدهاست. همچنین اگر وبپک را به حالت Minify کردن باندل ببریم (در مطلب قبلی نحوهی این کار ذکر شد)، باندل نهایی برای فایلهای css نیز Minify خواهد شد.
استفاده از Sass با کمک وبپک
روش استفاده از Sass نیز تفاوتی با css نخواهد داشت و فقط کافی است Loader آن را در پروژه نصب کنیم و در نهایت آن را در فایل پیکربندی، به وبپک معرفی کنیم. با دستور زیر لودر Sass را در پروژه وارد میکنیم:
// نصب لودر sass npm install -D sass-loader node-sass
( node-sass به عنوان وابستگی لودر sass، در کنار آن نصب شده است)
حال به فایل پیکربندی میرویم و لودر جدید را به قسمت لودرها اضافه میکنیم:
// webpack.config.js module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!sass-loader' } ] }
در پوشهی assets نیز فایل جدیدی را با عنوان main.scss ساخته و محتوای زیر را در آن وارد میکنیم:
// main.scss $background-color:#DAA520; body{ background-color: $background-color; }
سپس در فایل main.js به جای وارد کردن فایل css قبلی، فایل scss جدید را با کمک require وارد میکنیم و در ادامه وبپک را اجرا میکنیم. خواهیم دید که مانند قبل بدون مشکلی وبپک اجرا شده، فایل scss را به css ترجمه کرده و سپس به کمک بقیه لودرها، به باندل اضافه میکند. استفاده از بقیهی فریمورکهای css مانند Less و ... نیز با کمک لودر آنها به همین صورت قابل انجام است.
استفاده از Autoprefixer
همان طور که تمامی قابلیتهای نسخهی جدید جاوااسکریپت در همهی مرورگرها به صورت سراسری پشتیبانی نمیشود، برای css نیز چنین مشکل مشابهی وجود دارد و برای استفادهی بهینهی از برخی قابلیتها نیاز داریم تا prefixهای مورد نیاز مرورگرهای مختلف را به فایلهای css مان اضافه کنیم. میتوانیم این روند را با کمک یک لودر وبپک، ساده و به صورت خودکار کرد. برای نصب این لودر دستور زیر را وارد میکنیم:
npm install -D autoprefixer-loader
و بعد از نصب شدن آن، در فایل پیکربندی وبپک به لودرهایی که برای فایلهای css و scss اضافه کرده بودیم، این لودر را نیز به صورت زنجیر وار اضافه میکنیم:
//webpack.config.js module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader!autoprefixer-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!autoprefixer-loader!sass-loader' } ] }
در هر دو لودری که برای css و scss ساخته بودیم، از لودر autoprefixer استفاده کردیم. برای تست اینکه این لودر بدون مشکل کار میکند، در فایل main.scss تغییر زیر را ایجاد میکنیم:
//main.scss $background-color:#DAA520; body{ background-color: $background-color; display: flex; }
حال با اجرای وبپک خواهیم دید که prefixهای مورد نیاز توسط لودر اضافه شده اند ( این لودر از کتابخانهی postcss کمک میگیرد).
باندل کردن تصاویر و فونتها با کمک وبپک
تا اینجا با نحوهی وارد کردن فایلهای استایل، مانند css و ... به باندل آشنا شدیم. در ادامه قصد داریم که تصاویر و فونتها را نیز وارد باندل کنیم. روند کار شبیه به گذشته است و این کار نیز به کمک لودرهای وبپک انجام خواهد شد.
جهت باندل کردن تصاویر و فونتها، به لودر جدیدی با نام url-loader احتیاج داریم. قبل از هر چیزی این لودر را در پروژه با کمک npm نصب میکنیم:
npm install -D url-loader file-loader
(لودر file-loader به عنوان وابستگی مورد نیاز است)
روند همچنان مثل گذشته است و پس از نصب لودر، وارد فایل پیکربندی شده و لودر جدید را به وبپک معرفی میکنیم:
//webpack.config.js file module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader!autoprefixer-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!autoprefixer-loader!sass-loader' },{ test:/\.(png|jpg|ttf|eot)$/ ,exclude:/node_modules/ ,loader:'url-loader?limit=100000' } ] }
در لودر اضافه شده، پسوند فایلهایی را که قصد داریم به باندل وارد شوند، معرفی میکنیم. در اینجا فرمتهای png , jpg ,ttf, eot ذکر شدهاند.
تنها نکتهی جدید، در مشخص کردن نام لودر وجود دارد و آن نیز قسمت پس از علامت ؟ میباشد. هنگام مشخص کردن اینکه از چه لودری قصد استفاده داریم، میتوانیم با استفاده از ؟ پارامترهایی را به لودر مورد نظر ارسال کنیم. در اینجا به پارامتر limit، مقدار 100000 را دادهایم که برای این لودر به این معناست که اگر حجم فایل در حال پردازش، حجمی بیشتر از این مقدار را داشت، این فایل را به صورت یک لینک جدا از باندل قرار بده. ولی اگر حجمی کمتر از این مقدار داشت، لودر به صورت خودکار فایل را به فرمت Base64 انکود میکند و در درون باندل قرار میدهد.
برای تست اینکه آیا این لودر به درستی کار میکند یا نه، یک تصویر نمونه را در فولدر assets قرار میدهیم و سپس در فایل main.scss تغییرات زیر را انجام میدهیم.
حجم عکس قرار داده شده نزدیک به 400 کیلوبایت است و با مقدار محدودیت مشخص شده، تصویر مورد نظر از باندل توسط وبپک خارج میشود و به صورت جداگانه در بیلد نهایی قرار میگیرد. در تصویر زیر مشخص است که مرورگر درخواست جداگانه ای برای تصویر ارسال کرده است:
حال محدودیت حجم فایل را بالا میبریم و میتوان دید که تصویر در باندل نهایی به صورت انکود شده قرار گرفته است .
قطعا انجام این کار برای تصاویری با حجم بالا مناسب نخواهد بود و برنامه نویس بسته به نیاز بایستی مقدار محدودیت حجم را برای لودر مشخص کند.
در تعریف بالا دیدیم که فرمتهای مورد نیاز برای وارد کردن فونت را نیز علاوه بر تصاویر، برای وبپک مشخص کردهایم. روند وارد کردن فونتها به باندل نیز تفاوتی با تصاویر ندارد و کافی است تعاریف مورد نیاز را در فایلهای css داشته باشیم.
برای مثال فونت ساحل در پوشهی assets قرار داده شده و در فایل main.scss تغییرات زیر انجام شدهاند:
// main.scss $background-color:#DAA520; div{ background-image: url("galaxy.jpg"); } @font-face { font-family: Sahel; src: url('Sahel.eot'); src: url('Sahel.eot?#iefix') format('embedded-opentype'), url('Sahel.woff') format('woff'), url('Sahel.ttf') format('truetype'); font-weight: normal; } @font-face { font-family: Sahel; src: url('Sahel-Bold.eot'); src: url('Sahel-Bold.eot?#iefix') format('embedded-opentype'), url('Sahel-Bold.woff') format('woff'), url('Sahel-Bold.ttf') format('truetype'); font-weight: bold; } @font-face { font-family: Sahel; src: url('Sahel-Black.eot'); src: url('Sahel-Black.eot?#iefix') format('embedded-opentype'), url('Sahel-Black.woff') format('woff'); font-weight: 900; } body{ background-color: $background-color; font-family: 'Sahel'; display: flex; }
تصویر زیر، نتیجهی اجرای وبپک برای تولید باندل است. در تصویر میتوان دید که هم فونتها و هم فایلهای تصاویر، توسط وبپک شناسایی شده و وارد باندل شدهاند:
روش دیگری برای وارد کردن تصاویر نیز موجود است؛ به این صورت که به فرض مثال یک تگ img در اسکریپت ساخته و سپس پروپرتی src آن را با کمک require برابر با آدرس تصویر مورد نظر قرار میدهیم. این روش نیز برای وبپک قابل فهم بوده و فایل وارد باندل میشود. در ادامه مثالی از این روش آورده شده است:
var img = document.createElement("img"); img.width="200px"; img.height="200px"; img.src= require("path to some image");
چند نکتهی پایانی :
1. در فایل پیکربندی همیشه پسوند فایلهایی را که در کلید entry قرار داشتند، مشخص کردیم:
entry:['./main.js','./shared.ts']
با کلیدی با نام resolve در فایل پیکربندی میتوان مشخص کرد در صورتیکه پسوند فایلی مشخص نبود، به ترتیب مشخص شده به دنبال آن بگردد. به طور مثال:
// webpack.config.js resolve:{ extensions:['','.js','.ts'] }
در تعریف بالا ذکر میشود در صورتیکه پسوند فایل ورودی مشخص نبود، ابتدا به دنبال فایل بدون پسوند، سپس فایلهایی با پسوند js و در نهایت به دنبال فایلهایی با پسوند ts بگرد. توجه داشته باشید که ترتیب مشخص کردن پسوند فایلها مهم است و وبپک بر اساس این ترتیب به دنبال فایل مورد نظر خواهد گشت.
حال میتوان مقدار کلید entry را اینطور تعریف کرد:
entry:['./main','./shared']
2.استفاده از فایلهای css ی که در درونشان فونتهای مورد نیاز لینک شدهاند تنها با استفاده از لودر css قابل انجام نیست. به طور مثال استفاده از کتابخانهی بوت استرپ تنها با این لودر ممکن نیست و بایستی لودر url-loader نیز در پروژه نصب شده باشد تا در هنگامیکه وبپک به فونتها برخورد کرد، بتواند آنها را وابسته به شرایط، وارد باندل نهایی کند.
فایلهای پروژه: dntwebpack-part4.zip
Host.CreateDefaultBuilder(args)
.ConfigureLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.AddApplicationInsights(); })
{ "inputs": [ { "type": "ApplicationInsights" } ], "outputs": [ { "type": "StdOutput" // console output } ], "schemaVersion": "2016-08-11" }
using (var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json")) { CreateHostBuilder(args, pipeline) .Build() .Run(); }
public static IHostBuilder CreateHostBuilder(string[] args, DiagnosticPipeline pipeline) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services => services.AddSingleton<ITelemetryProcessorFactory>(sp => new EventFlowTelemetryProcessorFactory(pipeline)))
.ConfigureLogging(logginBuilder =>
{
logginBuilder.ClearProviders();
loggingBuilder.AddApplicationInsights();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});