ฉันจะระบุคำสั่งรวม ScriptBundle ที่ชัดเจนได้อย่างไร


91

ฉันพยายามออกคุณลักษณะ ScriptBundle MVC4 System.Web.Optimization 1.0

ฉันมีการกำหนดค่าต่อไปนี้:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        // shared scripts
        Bundle canvasScripts =
            new ScriptBundle(BundlePaths.CanvasScripts)
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/json2.js")
                .Include("~/Scripts/columnizer.js")
                .Include("~/Scripts/jquery.ui.message.min.js")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts);
    }
}

และมุมมองต่อไปนี้:

<script type="text/javascript" src="@Scripts.Url(BundlePaths.CanvasScripts)"></script>

ที่เป็นBundlePaths.CanvasScripts "~/bundles/scripts/canvas"มันทำให้สิ่งนี้:

<script type="text/javascript" src="/bundles/scripts/canvas?v=UTH3XqH0UXWjJzi-gtX03eU183BJNpFNg8anioG14_41"></script>

จนถึงตอนนี้ดีมากยกเว้น~/Scripts/Shared/achievements.jsเป็นสคริปต์แรกในซอร์สที่รวม ขึ้นอยู่กับทุกสคริปต์ที่รวมอยู่ก่อนหน้านั้นในไฟล์ScriptBundle. ฉันจะมั่นใจได้อย่างไรว่าจะเป็นไปตามลำดับที่ฉันเพิ่มคำสั่งรวมลงในชุด

อัปเดต

นี่เป็นแอปพลิเคชัน ASP.NET MVC 4 ที่ค่อนข้างใหม่ แต่กำลังอ้างอิงถึงแพ็คเกจก่อนวางจำหน่ายของเฟรมเวิร์กการเพิ่มประสิทธิภาพ ฉันลบมันและเพิ่มแพคเกจ RTM จากhttp://nuget.org/packages/Microsoft.AspNet.Web.Optimization ด้วยเวอร์ชัน RTM ที่มี debug = true ใน web.config@Scripts.Render("~/bundles/scripts/canvas")แสดงแท็กสคริปต์แต่ละแท็กตามลำดับที่ถูกต้อง

ด้วย debug = false ใน web.config สคริปต์ที่รวมจะมีสคริปต์ successments.js ก่อน แต่เนื่องจากเป็นนิยามฟังก์ชัน (ตัวสร้างวัตถุ) ที่เรียกในภายหลังจึงทำงานโดยไม่มีข้อผิดพลาด บางที minifier อาจฉลาดพอที่จะคิดหาการอ้างอิง?

ฉันยังลอง IBundleOrdererใช้งานที่ Darin Dimitrov แนะนำกับ RTM ด้วยตัวเลือกการดีบักทั้งสองตัวและมันก็ทำงานเหมือนกัน

ดังนั้นเวอร์ชันที่ลดขนาดจึงไม่อยู่ในลำดับที่ฉันคาดหวัง แต่ใช้งานได้

คำตอบ:


18

ฉันไม่เห็นพฤติกรรมนี้บนบิต RTM คุณกำลังใช้ Microsoft ASP.NET Web Optimization Framework 1.0.0 บิต: http://nuget.org/packages/Microsoft.AspNet.Web.Optimizationหรือไม่

ฉันใช้คำซ้ำที่คล้ายกันกับตัวอย่างของคุณโดยอ้างอิงจากเว็บไซต์แอปพลิเคชันอินเทอร์เน็ต MVC4 ใหม่

ฉันเพิ่มไปยัง BundleConfig.RegisterBundles:

        Bundle canvasScripts =
            new ScriptBundle("~/bundles/scripts/canvas")
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts); 

จากนั้นในหน้าดัชนีเริ่มต้นฉันเพิ่ม:

<script src="@Scripts.Url("~/bundles/scripts/canvas")"></script>

และฉันตรวจสอบแล้วว่าใน javascript ที่ย่อขนาดสำหรับบันเดิลนั้นเนื้อหาของ successments.js อยู่หลังจาก modernizr ...


ฉันอัปเกรดเป็นเวอร์ชัน 1.0 ดูคำถามที่อัปเดตของฉัน เนื้อหาของ successments.js จะรวมอยู่ในเวอร์ชันที่ย่อขนาดก่อน แต่จะใช้งานได้เนื่องจากมีฟังก์ชันที่เรียกในภายหลัง
jrummell

115

คุณสามารถเขียนตัวกำหนดบันเดิลที่กำหนดเอง ( IBundleOrderer) เพื่อให้แน่ใจว่าบันเดิลรวมอยู่ในลำดับที่คุณลงทะเบียนไว้:

public class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

แล้ว:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        var bundle = new Bundle("~/bundles/scripts/canvas");
        bundle.Orderer = new AsIsBundleOrderer();
        bundle
            .Include("~/Scripts/modernizr-*")
            .Include("~/Scripts/json2.js")
            .Include("~/Scripts/columnizer.js")
            .Include("~/Scripts/jquery.ui.message.min.js")
            .Include("~/Scripts/Shared/achievements.js")
            .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(bundle);
    }
}

และในมุมมองของคุณ:

@Scripts.Render("~/bundles/scripts/canvas")

10
สิ่งนี้ควรใช้งานได้ แต่ก็ไม่จำเป็นเช่นกันเนื่องจากตัวกำหนดค่าเริ่มต้นโดยทั่วไปจะเคารพลำดับของการรวม (มันส่งเสริมไฟล์พิเศษเพียงไม่กี่ไฟล์ที่ด้านบนเช่น jquery, reset.css / normalize.css เป็นต้น) ไม่ควรส่งเสริมความสำเร็จ js ที่ด้านบน
Hao Kung

1
@flipdoubt ยื่นปัญหาที่นี่ด้วย repro: aspnetoptimization.codeplex.com/workitem/list/advanced
Hao Kung

1
มันใช้งานได้ดีขอบคุณ! ฉันเห็นด้วย แต่ไม่ควรจำเป็น
CBarr

2
สิ่งนี้ใช้ได้กับฉัน มันกำลังโปรโมต jqueryui ผ่าน bootstrap เมื่ออ้างอิงจากstackoverflow.com/questions/17367736/…ฉันต้องการให้มันพลิก
Sethcran

1
@ ห่าวกุ้งสั่งไฟล์ในincludeไดเร็กทอรีได้ไหม?
shaijut

52

ขอบคุณดาริน ฉันได้เพิ่มวิธีการขยายแล้ว

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

การใช้งาน

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js",
                    "~/Scripts/jquery-migrate-{version}.js",

                    "~/Scripts/jquery.validate.js",
                    "~/Scripts/jquery.validate.messages_fr.js",
                    "~/Scripts/moon.jquery.validation-{version}.js",

                    "~/Scripts/jquery-ui-{version}.js"
                    ).ForceOrdered());

9
เนียนสวย! : D ตอนนี้ฉันต้องเปลี่ยนFileInfoสำหรับBundleFileลายเซ็นวิธีการอินเทอร์เฟซ พวกเขาเปลี่ยนมัน
Leniel Maccaferri

ใช่พวกเขาเปลี่ยนมันในเวอร์ชันก่อนวางจำหน่ายซึ่งใช้กรอบ Owin
Softlion

Off-Topic เล็กน้อย: ใครมีข้อมูลเพิ่มเติมเกี่ยวกับBundleFileชั้นเรียนนี้หรือไม่? ในการรวมทรัพยากรที่ฝังไว้ฉันกำลังพยายามสร้างอินสแตนซ์นั้นและต้องใช้VirtualFileพารามิเตอร์(ลูกคอนกรีตของ) ในตัวสร้าง
superjos

ฉันมีคำถามเหมือนกันฉันต้องการสร้างอินสแตนซ์ BundleFile แต่ไม่รู้วิธี
Rui

2
@superjos ฉันรู้ว่ามันค่อนข้างเก่า แต่ฉันจะตอบในกรณีที่คนอื่นมีปัญหา เป็นส่วนหนึ่งของ System.Web.Optimization
Talon

47

อัปเดตคำตอบโดย SoftLion เพื่อจัดการกับการเปลี่ยนแปลงใน MVC 5 (BundleFile เทียบกับ FileInfo)

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

การใช้งาน:

    bundles.Add(new ScriptBundle("~/content/js/site")
        .Include("~/content/scripts/jquery-{version}.js")
        .Include("~/content/scripts/bootstrap-{version}.js")
        .Include("~/content/scripts/jquery.validate-{version}")
        .ForceOrdered());

ฉันชอบใช้ไวยากรณ์ที่คล่องแคล่ว แต่ก็ใช้ได้กับการเรียกวิธีเดียวและสคริปต์ทั้งหมดส่งผ่านเป็นพารามิเตอร์


2
ทำงานใน MVC 5 ขอบคุณ
Pascal Carmoni

4
ยอดเยี่ยม. MS imho
Angelo

ทำงานได้อย่างมีเสน่ห์ใน Web Forms เช่นกัน ... โดยพื้นฐานแล้วควรใช้งานได้ดีกับเวอร์ชันล่าสุดทั้งหมด!
Sunny Sharma

วิธีแก้ปัญหาที่ง่ายและสะอาดมาก ขอบคุณมาก.
bunjeeb

5

คุณควรจะตั้งค่าลำดับได้ด้วยความช่วยเหลือของ BundleCollection.FileSetOrderList มีลักษณะที่โพสต์บล็อกนี้: http://weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx โค้ดในอินสแตนซ์ของคุณจะเป็นดังนี้:

BundleFileSetOrdering bundleFileSetOrdering = new BundleFileSetOrdering("js");
bundleFileSetOrdering.Files.Add("~/Scripts/modernizr-*");
bundleFileSetOrdering.Files.Add("~/Scripts/json2.js");
bundleFileSetOrdering.Files.Add("~/Scripts/columnizer.js");
bundleFileSetOrdering.Files.Add("~/Scripts/jquery.ui.message.min.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/achievements.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/canvas.js");
bundles.FileSetOrderList.Add(bundleFileSetOrdering);

1

คุณควรพิจารณาใช้ Cassette http://getcassette.net/ซึ่งสนับสนุนการตรวจหาการอ้างอิงสคริปต์โดยอัตโนมัติตามการอ้างอิงสคริปต์ที่พบในแต่ละไฟล์

หากคุณต้องการใช้โซลูชัน MS Web Optimization แต่ชอบแนวคิดในการจัดเรียงสคริปต์ตามการอ้างอิงสคริปต์คุณควรอ่านโพสต์บล็อกของฉันที่http://blogs.microsoft.co.il/oric/2013/12/27/building-single -page-application-bundle-orderer /


1

คำตอบของ @Darin Dimitrov ทำงานได้ดีสำหรับฉัน แต่โครงการของฉันเขียนด้วย VB ดังนั้นนี่คือคำตอบของเขาที่แปลงเป็น VB

Public Class AsIsBundleOrderer
    Implements IBundleOrderer

    Public Function IBundleOrderer_OrderFiles(ByVal context As BundleContext, ByVal files As IEnumerable(Of FileInfo)) As IEnumerable(Of FileInfo) Implements IBundleOrderer.OrderFiles
        Return files
    End Function
End Class

วิธีใช้:

Dim scriptBundleMain = New ScriptBundle("~/Scripts/myBundle")
scriptBundleMain.Orderer = New AsIsBundleOrderer()
scriptBundleMain.Include(
    "~/Scripts/file1.js",
    "~/Scripts/file2.js"
)
bundles.Add(scriptBundleMain)

ฉันได้รับข้อผิดพลาดนี้Class 'AsIsBundleOrderer' must implement 'Function OrderFiles(context as ....)' for interface 'System.Web.Optimization.IBundleOrderer'เรื่อย ๆ: มีความคิดอย่างไร
Mark Pieszak - Trilon.io
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.