Bundle and jQuery or bootstrap images

9 ביוני 2014

תגיות: , ,
אין תגובות

מנגנון ה – bundling and optimization של asp.net הוא מנגנון נהדר שמגיע לפתור לנו מספר בעיות.

  • ספריות (כמו jQuery, angular ואחרים) מגיעות בדרך כלל עם קובץ לזמן פיתוח וקובץ min שמכיל את כל התוכן בצורה מקוצרת (כל הטקסט בשורה אחת, שמות מקוצרים של משתנים וכו’), נרצה לוודא שבזמן פיתוח נשתמש בקובץ הרגיל ובזמן שהמשתמש גולש נשתמש בקובץ המכווץ.
  • עבור הקוד שאנחנו כותבים נרצה גם כן מנגנון שיודע לייצר בזמן שהמתשמש גולש קובץ “min” עם המידע.
  • כל קובץ js או css הינו request נפרד לשרת, ניתן לאחד מספר קבצים לבקשה אחת מהשרת – כך שטעינת העמוד תהיה מהירה יותר.
  • במידה ועשינו שינויים בקובץ ה – js או ה – css, נרצה שהמשתמש יקבל את הקובץ המעודכן ללא שנצטרך להגיד לו “תרפרש את העמוד”.

 

כדי לקבל את כל היכולות האלו, נוכל להשתמש עם מנגנון ה – bundling and optimization, במידה ובחרנו פרוייקט מסוג basic, כבר יש לנו את היכולות הללו, במידה ועשינו empty נשתמש ב – nuget כדי להתקין, נחפש את חבילת Microsoft.AspNet.Web.Optimizatio ונתקין אותה.

לאחר מכן ב – ניצור מחלקה תחת App_Start בשם BundleConfig, שבתוכו תהיה מתודה בשם RegisterBundles, (כך)

Code Snippet
// For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
    //BundleTable.EnableOptimizations = true;

    JS(bundles);
    CSS(bundles);

}

הקריאה למתודה הזו תקרה ב – Application_Start (השורה האחרונה)

Code Snippet
protected void Application_Start()
{
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

 

כעת בתוך המתודה עצמה ניצור bundle של קבצי JS, יראה משהו בסגנון הזה:

Code Snippet
private static void CSS(BundleCollection bundles)
{
    bundles.Add(new StyleBundle("~/Content/css/libs")
        .Include("~/Content/libs/googleFonts.css")
        .Include(
                "~/Content/libs/bootstrap/css/font-awesome.css")
        .Include(
                "~/Content/libs/bootstrap/css/bootstrap.css",
                "~/Content/libs/bootstrap/css/bootstrap-rtl.css")
        .Include("~/Content/libs/jQuery/blitzer/jquery-ui-1.10.4.css",
                "~/Content/libs/jQuery/jquery.timepicker.css")
        .Include("~/Content/libs/angular/fullcalendar.css"));

    bundles.Add(new StyleBundle("~/Content/css/site")
        .Include("~/Content/site/app.css",
                "~/Content/site/appOverride.css"));

    bundles.Add(new StyleBundle("~/Content/css/site/Login")
        .Include("~/Content/site/Login/Login.css"));
}

private static void JS(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/scripts/libs")
                .Include(
                    "~/Scripts/libs/jQuery/jquery-{version}.js",
                    "~/Scripts/libs/jQuery/noty/jquery.noty.js",
                    "~/Scripts/libs/jQuery/noty/themes/*.js",
                    "~/Scripts/libs/jQuery/noty/layouts/*.js",
                    "~/Scripts/libs/jQuery/jquery-ui-{version}.js",
                    "~/Scripts/libs/jQuery/jquery.timepicker.js",
                    "~/Scripts/libs/jQuery/jquery.ui.datepicker-he.js")
                .Include(
                    "~/Scripts/libs/angular/angular.js",
                    "~/Scripts/libs/angular/angular-ui-router.js",
                    "~/Scripts/libs/angular/angular-animate.js",
                    "~/Scripts/libs/angular/angular-locale_he-il.js",
                    "~/Scripts/libs/angular/angular-route.js",
                    "~/Scripts/libs/angular/directives/ui-bootstrap/ui-bootstrap-tpls-0.11.0.js",
                    "~/Scripts/libs/angular/directives/ui-calendar/moment.js",
                    "~/Scripts/libs/angular/directives/date.js",
                    "~/Scripts/libs/angular/directives/timepickerdirective.js",
                    "~/Scripts/libs/angular/directives/ui-calendar/fullcalendar.js",
                    "~/Scripts/libs/angular/directives/ui-calendar/gcal.js",
                    "~/Scripts/libs/angular/directives/ui-calendar/calendar.js")
                .Include(
                    "~/Scripts/libs/bootstrap/bootstrap.js"));

    bundles.Add(new ScriptBundle("~/bundles/scripts/site")
                .Include(
                "~/Scripts/site/helpers/*.js")
                .Include(
                "~/Scripts/site/App.js")
            .Include(
                "~/Scripts/site/moduls/misc/alerts.js",
                "~/Scripts/site/moduls/misc/confirmModalController.js",
                    "~/Scripts/site/moduls/misc/questionsModalController.js")
            .Include(
                "~/Scripts/site/moduls/persons/personService.js",
                "~/Scripts/site/moduls/persons/newPersonController.js",
                "~/Scripts/site/moduls/persons/detailsPersonController.js",
                    "~/Scripts/site/moduls/persons/personsListController.js",
                "~/Scripts/site/moduls/persons/persons.js"
                )
            .Include("~/Scripts/site/directives/*.js")
            .Include(
                "~/Scripts/site/moduls/dat/menuController.js",
                "~/Scripts/site/moduls/dat/dat.js"
                ));

    bundles.Add(new ScriptBundle("~/bundles/scripts/login").
        Include("~/Scripts/site/moduls/login/login.js"));

}

בדרך כלל – אני מחלק את הרישום בין קבצי ה – “libs” לקבצי ה – “site”, בסופו של דבר כל bundle בזמן פיתוח הקבצים יורדים כרגיל, ובזמן שהמשתמש גולש (למעשה אם בקונפיג מוגדר בתוך system.web בתגית compilation ש – debug=false או לחילופין BundleTable.EnableOptimizations = true) כל הקבצים יורדים בגרסת ה – min שלהם (או שקיים, או שנוצר בזמן ריצה) כולם מתאחדים לבקשה אחת מהשרת (כל הגדרה של bundle) ובמידה והיו שינויים בקבצים, יודעים להוריד את הגרסה החדשה.

עד כאן ההסבר המהיר והבסיסי על bundle, הבעייה היא מה יקרה כשנשתמש ב – jQuery ui וספריות מהסוג הזה, שבקובץ ה – css שלהם,  יש הפנייה רלטיבית לתמונות, וכמובן ברגע שהכתובת של קובץ ה – css משתנה (בזמן שהמתשתמש גולש) ההפנייה הרלטיבית לא עובדת יותר.

יש מספר דרכים לפתור זאת, הדרך המהירה ביותר (מבחינת פיתוח) היא לכתוב את הקוד הבא:

Code Snippet
private static void CSS(BundleCollection bundles)
{
    var styleBundle = new StyleBundle("~/Content/css/libs")
        .Include("~/Content/libs/googleFonts.css")
        .Include(
                "~/Content/libs/bootstrap/css/font-awesome.css")
        .Include(
                "~/Content/libs/bootstrap/css/bootstrap.css",
                "~/Content/libs/bootstrap/css/bootstrap-rtl.css")
        .Include("~/Content/libs/jQuery/blitzer/jquery-ui-1.10.4.css",
                "~/Content/libs/jQuery/jquery.timepicker.css")
        .Include("~/Content/libs/angular/fullcalendar.css");

    if (BundleTable.EnableOptimizations)
    {
        styleBundle.Transforms.Add(new ProperUrlRewrite());
    }

    bundles.Add(styleBundle);

    bundles.Add(new StyleBundle("~/Content/css/site")
       .Include("~/Content/site/app.css",
                "~/Content/site/appOverride.css"));

    bundles.Add(new StyleBundle("~/Content/css/site/Login")
       .Include("~/Content/site/Login/Login.css"));
}

public sealed class ProperUrlRewrite : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        string content = response.Content;
        // replace to regex
        content = content.Replace("../fonts/", "../libs/bootstrap/fonts/");
        content = content.Replace("images/", "../libs/jQuery/blitzer/images/");

        response.Content = content;
    }
}

כמובן בקוד שמחליף את ההפנייה הרלטיבית, יש לנות לנתיב המתאים עבורכם.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *