ASP.NET กับการจัด JavaScript ให้ดีขึ้น

แรงจูงใจ …

นักพัฒนา web application อย่าง ASP.NET โดยส่วนใหญ่มักจะหละหลวงเรื่องการจัดการ javascript ที่ดี และไม่สนใจที่จะกลับมาจัดการมันอีก คนที่มาดูแลต่อก็จะเครียดเมื่อมาเจอ javascript เป็นปริมาณมากที่ต้องแก้ไขจัดการ bug ที่คังข้างอยู่ใน application (technical debt) ในที่สุดผู้ที่ดูแลต่อก็ไม่มีทางเลือกอื่นนอกจาก ดันทุรังแก้ไข bug ไปตามน้ำ(เสียๆ) พร้อมกับทิ้งหนี้สินทางเทคนิคเพิ่มเขาไปอีก และหนีไป เป็นวงจรแห่งหนี้สินทางเทคนิคแบบนี้เรื่อยไป จนกระทั่งพบ hero ตัวจริงมาลงแรงใช้หนี้สินนี้ทั้งหมดด้วยการทำ refactoring code

แต่อย่าให้ถึงตรงนั้นเลย เรามาเริ่มต้นให้ดีกันตั้งแต่ตอนนี้ และเดี๋ยวนี้กันเลยดีกว่า บทความนี้ก็จะเสนอวิธีการจัดการ javascript ใน ASP.NET ซึ่งหลังจากคุณอ่านบทความนี้จบแล้ว ปัญหาเหล่านี้จะได้รับการแก้ไข

  • Inline JS: Page ที่อ้วนตุตะสาเหตุเกิดมาจากกิน JavaScript มากเกินไป หรือใส่ javascript เข้าไปใน page ตรงๆ
  • Deploying JS: ลืม deploy ไฟร์ JavaScript
  • Bad References: การเชื่อมโยงไปยัง JavaScript ไม่ทำงานเมื่อ copy ไปใช้ใน web application ที่อื่น
  • Dependencies: จำเป็นต้องจำให้ได้ว่าใน page นี้อ้างอิงไฟล์ JavaScript อะไรบ้าง
  • Unused JS: การอ้างอิง JavaScript บน page ที่ไม่ได้ใช้งาน
  • HTTP / HTTPS: การอ้างอิง JavaScript บน HTTP จาก HTTPS page
  • Refactoring: การ refactoring สำหรับ version ใหม่ใช้เวลามาก
  • Redundancy: รวม JavaScript ไฟล์เดิมซ้ำ

เครื่องมือที่จำเป็น …

หวังว่าคุณผู้อ่านคงจะมี Visual Studio 2010 อยู่ที่เครื่องกันทุกคนครับ ถ้าไม่มีก็ไป load ตัว Express ใช้ทดลองทำตามบทความนี้ไปด้วยกันก็ได้ครับ

ทบทวนกันก่อน …

ส่วนใหญ่ของปัญหาข้างต้นมีสาเหตุมาจากการวาง JavaScript หรือการอ้างอิงไปยังไฟล์โดยตรง JavaScript ในหน้า ASPX วิธีแก้ปัญหาเกือบทั้งหมดข้างต้นคือการใช้ความสามารถในตัว ASP.NET ในการฝังไฟล์ JavaScript เข้าไปใน DLL แล้วอ้างอิงไฟล์แบบไดนามิกแทน บทความนี้ ผมจะนำเสนอความสามารถเหล่านั้น ผมจะนำเสนอไปทีละขั้นตอน ตามผมมาครับ

เริ่มต้น …

1. สร้าง web projects ขึ้นมาครับ ตั้งชื่อว่า ManageJavaScriptDemo ตามภาพครับ

2. เพิ่ม JavaScript แต่เราจะไม่เพิ่มที่  web page ของเราครับ ให้เราสร้าง projects ขึ้นมาใหม่ ตั้งชื่อว่า MyJavaScriptLib ตามภาพครับ

3. สร้าง folder JavaScripts และเพิ่ม javascript file เข้าไปใน folder นี้อีก 2 file ครับ คือ “ShowMessage.js” และ “GreetUser.js” ตามภาพข้างล่างครับ

4. เขียนรหัส javascript นี้ไว้ที่ ShowMessage.js

function ShowMessage(msg) {
alert(“ข้อความนี้มาจาก Website: ” + msg);
}

5. เขียนรหัส javascript นี้ไว้ที่ GreetUser.js

function GreetUser() {
ShowMessage(“สวัสดีผู้ใช้!”);
}

6. แก้ properties ให้ javascript ทั้งสอง file ฝังไว้ใน dll ดูตามภาพครับ

7. เพิ่มไฟร์ class JavaScriptHelper.cs เข้าไปครับ ตามภาพ

8. เพิ่ม reference System.Web เข้าไปใน project MyJavaScriptLib ตามภาพครับ

9. แก้ไขไฟร์ JavaScriptHelper.cs เติม code เข้าไปตามข้างล่างนี้ครับ

using System.Web.UI;

//รหัสข้างต้นนี่จะช่วยให้ฝัง JavaScript ไฟล์ของคุณ และจะสามารถเข้าถึงได้จากคอมพิวเตอร์ ของไคลเอนต์
[assembly: WebResource(“MyJavaScriptLib.JavaScripts.ShowMessage.js”, “application/x-javascript”)]
[assembly: WebResource(“MyJavaScriptLib.JavaScripts.GreetUser.js”, “application/x-javascript”)]

namespace MyJavaScriptLib
{
/// <summary>
/// เป็นตัวช่วยฝัง JavaScript ไฟล์ใน web page
/// </summary>
public class JavaScriptHelper
{

private const string NAME_SHOW_MESSAGE = “MyJavaScriptLib.JavaScripts.ShowMessage.js”;
private const string NAME_GREET_USER = “MyJavaScriptLib.JavaScripts.GreetUser.js”;

public static void Include_ShowMessage(ClientScriptManager manager)
{
IncludeJavaScript(manager, NAME_SHOW_MESSAGE);
}

public static void Include_GreetUser(ClientScriptManager manager)
{

// Dependency (ShowMessage.js).
Include_ShowMessage(manager);

// Include GreetUser.js.
IncludeJavaScript(manager, NAME_GREET_USER);

}

private static void IncludeJavaScript(ClientScriptManager manager, string resourceName)
{
var type = typeof(MyJavaScriptLib.JavaScriptHelper);
manager.RegisterClientScriptResource(type, resourceName);
}
}
}

ทำ javascript DLL …

ตอนนี้เราก็เสร็จส่วนของ javascript lib ที่ฝัง javascrip เข้าไปใน dll หลังจากนี้ก็กลับไปที่ web projects ManageJavaScriptDemo ของเราครับ เริ่มขั้นตามผมดังนี้ครับ

1. อ้างอิง lib MyJavaScriptLib เพื่อใช้งาน javascript ตามภาพครับ แล้วกด OK

2. ไปที่ file Default.aspx.cs ที่เป็น code behind เพื่อ include javascript lib ไว้ที่ page ตามนี้

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            MyJavaScriptLib.JavaScriptHelper.Include_GreetUser(Page.ClientScript);
        }
}

3. เพิ่ม javascrip ที่ page aspx ให้ตอน load แสดง alert ข้อความต้อนรับ

<script type=”text/javascript”>
window.onload = function () { GreetUser(); };
</script>

เสร็จแล้วครับ ลองทดสอบ run web project ขึ้นมาดู จะได้หน้าตา application ออกมาแบบนี้ครับ

เทคนิค Late Include …

บางครั้งเทคนิคข้างต้นไม่รวมไฟล์ JavaScript  ตัวอย่างเช่น ผมทำงานร่วมกับเครื่องมือ tird party ที่ป้องกันไม่ให้ ผมเรียก code .Net ก่อนขั้นตอนแสดงผล เมื่อคุณ include ฟังก์ชั่นดังกล่าวระหว่างขั้นตอนการแสดงผล, tag ของสคริปต์ไม่ได้รับการแทรกลงใน page ทั้งนี้เป็นเพราะการเริ่มต้นของ page นี้ได้มีการแสดงผลเป็น HTML ทางออกแก้ไขปัญหานี้ คือการสร้างรูปแบบอื่นของการทำงานจะแทรก tag สคริปต์ที่ใกล้ด้านล่างของ HTML ที่เรียกเทคนิคนี้ว่า “Late Include” เพื่อสามารถสนับสนุนเทคนิคนี้ ต้องทำการเปลี่ยนแปลงบางอย่างใน JavaScriptHelper ครับ

using System.Web;
using System.Web.UI;

[assembly: WebResource(“MyJavaScriptLib.JavaScripts.ShowMessage.js”, “application/x-javascript”)]
[assembly: WebResource(“MyJavaScriptLib.JavaScripts.GreetUser.js”, “application/x-javascript”)]

namespace MyJavaScriptLib
{
/// <summary>
/// เป็นตัวช่วยฝัง JavaScript ไฟล์ใน web page
/// </summary>
public class JavaScriptHelper
{

private const string TEMPLATE_SCRIPT = “<script type=\”text/javascript\” src=\”{0}\”></script>\r\n”;
private const string NAME_SHOW_MESSAGE = “MyJavaScriptLib.JavaScripts.ShowMessage.js”;
private const string NAME_GREET_USER = “MyJavaScriptLib.JavaScripts.GreetUser.js”;

public static void Include_ShowMessage(ClientScriptManager manager, bool late = false)
{
IncludeJavaScript(manager, NAME_SHOW_MESSAGE, late);
}

public static void Include_GreetUser(ClientScriptManager manager, bool late = false)
{

// Dependency (ShowMessage.js).
Include_ShowMessage(manager, late);

// Include GreetUser.js.
IncludeJavaScript(manager, NAME_GREET_USER, late);

}

private static void IncludeJavaScript(ClientScriptManager manager, string resourceName, bool late)
{
var type = typeof(MyJavaScriptLib.JavaScriptHelper);
if (!manager.IsStartupScriptRegistered(type, resourceName))
{
if (late)
{
var url = manager.GetWebResourceUrl(type, resourceName);
var scriptBlock = string.Format(TEMPLATE_SCRIPT, HttpUtility.HtmlEncode(url));
manager.RegisterStartupScript(type, resourceName, scriptBlock);
}
else
{
manager.RegisterClientScriptResource(type, resourceName);
manager.RegisterStartupScript(type, resourceName, string.Empty);
}
}
}
}
}

แก้ไข code behide ของ page Default ที่ file Default.aspx.cs เพื่อ load javascript ด้วยเทคนิค Late Include แบบนี้ครับ

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
MyJavaScriptLib.JavaScriptHelper.Include_GreetUser(Page.ClientScript, true);
}
พอลอง run page ขึ้นมาแล้วลอง ดู source ดูคุณจะเห็นว่า tag include javascript จะไปอยู่ล่างสุด

การเพิ่ม JavaScript จากภายนอก …

ทดสอบ load jQuery จากภายนอกมาใช้ดู เพิ่ม code เข้าไปที่ JavaScriptHelper ตามนี้ครับ

private const string NAME_JQUERY = “jQuery”;
private const string URL_JQUERY = “http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.js”;
private const string URL_JQUERY_HTTPS = “https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.js”;

private static void IncludeExternalJavaScript(Page page, string key, string httpUrl, string httpsUrl, bool late)
{
var manager = page.ClientScript;
var type = typeof(MyJavaScriptLib.JavaScriptHelper);
bool isStartupRegistered = manager.IsStartupScriptRegistered(type, key);
bool isScriptRegistered = manager.IsClientScriptIncludeRegistered(type, key);
if (!(isStartupRegistered || isScriptRegistered))
{
string url;
if (page.Request.Url.Scheme.ToLower() == “http”)
{
url = httpUrl;
}
else
{
url = httpsUrl;
}
if (late)
{
manager.RegisterStartupScript(type, key, string.Format(TEMPLATE_SCRIPT, HttpUtility.HtmlEncode(url)));
}
else
{
manager.RegisterClientScriptInclude(type, key, url);
}
}
}

public static void Include_jQuery(Page page, bool late = false)
{
if (page == null)
{
page = (Page)HttpContext.Current.Handler;
}
IncludeExternalJavaScript(page, NAME_JQUERY, URL_JQUERY, URL_JQUERY_HTTPS, late);
}

เติม code เพื่อ load jQury มาใช้ครับ

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
MyJavaScriptLib.JavaScriptHelper.Include_jQuery(Page);
MyJavaScriptLib.JavaScriptHelper.Include_GreetUser(Page.ClientScript);
}

วิธีเพิ่ม file JavaScript เข้า projects

  1. เพิ่ม *.js file ไว้ที่ folder JavaScripts ของ projects MyJavaScriptLib
  2. ตั้งค่า *.js file ที่ “build action” เป็น “embedded resource”
  3. เพิ่ม function ใน JavaScriptHelper ที่ใช้งาน *.js file ของใหม่นี้
  4. คุณก็เรียก function ที่สร้างใหม่นี้ได้แล้ว ใน page, control, หรือ masterpage

สรุปที่ทำมาแก้ปัญหาได้อย่างไร …

ครับเรามาสรุปปัญหาที่ได้รับการแก้ไขแล้ว ตามนี้ครับ

  • Inline JS: javascript ถูกย้ายไปอยู่ที่ file GreetUser.js, ShowMessage.js ที่อยู่ใน lib MyJavaScriptLib หมดแล้วดังนั้น page จะผอมลงและไม่อ้วนอีกแล้ว
  • Deploying JS: เราไม่ได้ include .js file แล้วครับแต่เรา include DLL MyJavaScriptLib  แทนการลืม include MyJavaScriptLib จะ error ตั้งแต่ตอน build projects แล้วครับ
  • Bad References: แม้ว่าคุณจะเปลี่ยน path ของ application คุณยังไง คุณจะไม่ต้องกังวลเกี่ยวกับการเปลี่ยน path JavaScript ของคุณอีกต่อไป
  • Dependencies: Dependencies มีการจัดการโดยอัตโนมัติ หากคุณใส่ “GreetUser.js” และ “ShowMessage.js” จะได้รับการ include โดยอัตโนมัติ
  • Unused JS: จะไม่มี JavaScript include อยู่ใน page จนกว่าคุณจะเรียกใช้ฟังก์ชัน นี่เป็นวิธีการเลี่ยงการ inclide js ที่ไม่ได้ใช้
  • HTTP / HTTPS: code ผลลัพย์ของ tag script ที่ไม่รวมโพรโทคอ ดังนั้นโพรโทคอเดียวกันควรจะเป็น page ปัจจุบัน
  • Refactoring: หากคุณต้องการใช้รุ่นที่แตกต่างกันของสคริป, คุณจะต้องปรับเปลี่ยนมันในที่เดียว นี่อาจเป็นประโยชน์ ตัวอย่างเช่นถ้าคุณตัดสินใจที่จะเปลี่ยนไปใช้รุ่น CDN ของ jQuery มากกว่า hosting ของตัวคุณเอง นอกจากนี้ยังจะเป็นประโยชน์สำหรับการอัพเกรด jQuery เป็นรุ่นใหม่
  • Redundancy: ไม่ว่าคุณจะเลียก include js กี่ครั้งก็ตาม แท็กของสคริปต์จะถูก include อยู่ใน page เพียงครั้งเดียว

ขอขอบคุณที่มาของบทความนี้: Managing Your JavaScript Library in ASP.NET

… ขอบคุณครับ …

Advertisements

#asp-net, #javascript