Requirejs ทำไมและเมื่อใดจึงควรใช้ shim config


98

ฉันอ่านเอกสารrequirejsจากที่นี่API

requirejs.config({
    shim: {
        'backbone': {
            //These script dependencies should be loaded before loading
            //backbone.js
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                return this.Foo.noConflict();
            }
        }
    }
});

แต่ผมไม่ได้รับการชิมส่วนหนึ่งของมัน ทำไมฉันถึงใช้ shim และฉันจะกำหนดค่าได้อย่างไรฉันจะได้รับคำชี้แจงเพิ่มเติมได้อย่างไร

โปรดอธิบายพร้อมตัวอย่างเหตุผลและเวลาที่เราควรใช้ shim ขอบคุณ.

คำตอบ:


110

การใช้ shim หลักคือไลบรารีที่ไม่รองรับ AMD แต่คุณต้องจัดการการอ้างอิง ตัวอย่างเช่นในตัวอย่าง Backbone และ Underscore ด้านบน: คุณรู้ว่า Backbone ต้องการขีดล่างดังนั้นสมมติว่าคุณเขียนโค้ดของคุณดังนี้:

require(['underscore', 'backbone']
, function( Underscore, Backbone ) {

    // do something with Backbone

}

RequireJS จะเริ่มต้นคำขอแบบอะซิงโครนัสสำหรับทั้ง Underscore และ Backbone แต่คุณไม่รู้ว่าอันไหนจะกลับมาก่อนจึงเป็นไปได้ว่า Backbone จะพยายามทำอะไรบางอย่างกับ Underscore ก่อนที่จะโหลด

หมายเหตุ:ตัวอย่างขีดล่าง / กระดูกสันหลังนี้ถูกเขียนขึ้นก่อนไลบรารีทั้งสองที่รองรับ AMD แต่หลักการถือเป็นจริงสำหรับไลบรารีใด ๆ ในปัจจุบันที่ไม่รองรับ AMD

เบ็ด "init" ช่วยให้คุณทำสิ่งขั้นสูงอื่น ๆ เช่นหากโดยปกติไลบรารีจะส่งออกสองสิ่งที่แตกต่างกันไปยังเนมสเปซส่วนกลาง แต่คุณต้องการกำหนดสิ่งเหล่านี้ใหม่ภายใต้เนมสเปซเดียว หรือบางทีคุณอาจต้องการแก้ไขลิงบนเมธอดในไลบรารีที่คุณกำลังโหลด

พื้นหลังเพิ่มเติม:


เช่นโค้ดตัวอย่าง yout UnderscoreและBackboneที่นี่ใช้เหมือนปกติshimในกรณีนี้จะทำอย่างไร? ใช้ได้require( function() { _.extend({}); })ไหม? มันเข้าใจ_ไหม?
Stiger

"RequireJS จะเริ่มต้นคำขอแบบอะซิงโครนัสสำหรับทั้ง Underscore และ Backbone" -> เป็นไปได้หรือไม่ที่จะป้องกันสิ่งนี้ในกรณีที่โหลดไลบรารีไว้แล้ว
Codii

1
@Codii ถูกต้องหากไลบรารีโหลดแล้วจะไม่เริ่มต้นการร้องขอเซิร์ฟเวอร์อื่น แต่ประเด็นของ RequireJS คือโค้ดของคุณไม่จำเป็นต้องสนใจว่าจะเกิดขึ้นหรือไม่ อาจตั้งคำถามใหม่สำหรับกรณีการใช้งานของคุณโดยเฉพาะ?
ระเบิด

63

ตามเอกสาร RequireJS API shim ช่วยให้คุณ

กำหนดค่าการอ้างอิงการเอ็กซ์พอร์ตและการกำหนดค่าเริ่มต้นแบบกำหนดเองสำหรับสคริปต์ "browser globals" รุ่นเก่าที่ไม่ใช้ define () เพื่อประกาศการอ้างอิงและตั้งค่าโมดูล

- การกำหนดค่าการอ้างอิง

สมมติว่าคุณมีโมดูลจาวาสคริปต์ 2 โมดูล (moduleA และ moduleB) และหนึ่งในนั้น (moduleA) ขึ้นอยู่กับโมดูลอื่น ๆ (moduleB) ทั้งสองอย่างนี้จำเป็นสำหรับโมดูลของคุณเองดังนั้นคุณจึงระบุการอ้างอิงในต้อง () หรือกำหนด ()

require(['moduleA','moduleB'],function(A,B ) {
    ...
}

แต่เนื่องจากต้องการให้ตัวเองติดตาม AMD คุณจึงไม่รู้ว่าจะดึงข้อมูลใดมาก่อน นี่คือจุดที่ชิมมาเพื่อช่วยเหลือ

require.config({
    shim:{
       moduleA:{
         deps:['moduleB']
        } 
    }

})

สิ่งนี้จะทำให้แน่ใจว่า moduleB จะถูกดึงข้อมูลเสมอก่อนที่จะโหลด moduleA

- การกำหนดค่าการส่งออก

การส่งออก Shim จะบอก RequireJS ว่าสมาชิกใดในวัตถุส่วนกลาง (หน้าต่างสมมติว่าคุณอยู่ในเบราว์เซอร์แน่นอน) คือค่าโมดูลที่แท้จริง ให้บอกว่า moduleA เพิ่มตัวเองwindowเป็น 'modA' (เช่นเดียวกับ jQuery และขีดล่างทำเป็น $ และ _ ตามลำดับ) จากนั้นเราสร้างมูลค่าการส่งออกของเราเป็น 'modA'

require.config({
    shim:{
       moduleA:{
         exports:'modA'
        } 
    }

จะให้ RequireJS อ้างอิงภายในกับโมดูลนี้ modA ส่วนกลางจะยังคงมีอยู่ในเพจด้วย

- กำหนดค่าเริ่มต้นที่กำหนดเองสำหรับสคริปต์ "เบราว์เซอร์ส่วนกลาง" รุ่นเก่า

นี่อาจเป็นคุณสมบัติที่สำคัญที่สุดของ shim config ซึ่งช่วยให้เราสามารถเพิ่มสคริปต์ "browser global", "non-AMD" (ซึ่งไม่เป็นไปตามรูปแบบโมดูล) เป็นการอ้างอิงในโมดูลของเราเอง

ให้บอกว่า moduleB เป็น javascript แบบเก่าที่มีเพียงสองฟังก์ชัน funcA () และ funcB ()

function funcA(){
    console.log("this is function A")
}
function funcB(){
    console.log("this is function B")
}

แม้ว่าฟังก์ชันทั้งสองนี้จะพร้อมใช้งานในขอบเขตหน้าต่าง RequireJS ขอแนะนำให้เราใช้งานผ่านตัวระบุ / หมายเลขอ้างอิงส่วนกลางเพื่อหลีกเลี่ยงความสับสน ดังนั้นการกำหนดค่า shim เป็น

shim: {
    moduleB: {
        deps: ["jquery"],
        exports: "funcB",
        init: function () {
            return {
                funcA: funcA,
                funcB: funcB
            };
        }
    }
}

ค่าที่ส่งคืนจากฟังก์ชัน init ถูกใช้เป็นค่าการส่งออกโมดูลแทนอ็อบเจ็กต์ที่พบผ่านสตริง "เอ็กซ์พอร์ต" สิ่งนี้จะช่วยให้เราใช้ funcB ในโมดูลของเราเองเป็น

require(["moduleA","moduleB"], function(A, B){
    B.funcB()
})

หวังว่านี่จะช่วยได้


3
เข้าใจง่าย! คำถามหนึ่ง: ในตัวอย่างสุดท้ายคุณสมบัติ "ส่งออก" ถูกละเว้นหรือไม่
Niko Bellic

ไม่มันไม่ถูกละเลย หากมีการละเว้นคุณสมบัติ "ส่งออก" ในตัวอย่างสุดท้ายดังนั้นออบเจ็กต์ที่คุณส่งผ่านเป็นพารามิเตอร์ ('B' ในกรณีนี้) จะไม่ถูกกำหนดเนื่องจาก moduleB ไม่สอดคล้องกับ AMD และจะไม่ส่งคืนวัตถุเพื่อให้ RequireJS ใช้ ( ดังนั้น 'B.funcB' จะไม่ทำงาน)
nalinc

อืม. ฉันคิดว่ามูลค่าของการส่งออกจะถูกลบล้างโดยวัตถุที่ส่งคืนในฟังก์ชัน init ดังนั้นพารามิเตอร์ B จะเป็นวัตถุ {funcA: funcA, funcB: funcB} ไม่ใช่แค่ funcB ด้วยตัวมันเอง นี่มันไม่จริงเหรอ?
Niko Bellic

4
Niko Bellic ถูกต้องไม่สนใจการส่งออก (ฉันเพิ่งทดสอบ) วัตถุ B คือวัตถุที่ส่งคืนโดยฟังก์ชันที่ระบุในส่วน 'init' หากคุณลบส่วน 'init' ออกวัตถุ B จะกลายเป็นฟังก์ชัน funcB ดังนั้นคุณจะทำ B () แทน B.funcB () และเห็นได้ชัดว่า funcA จะไม่สามารถเข้าถึงได้ในกรณีนั้น
user4205580

-2

คุณต้องเพิ่มเส้นทางใน requirejs.config เพื่อประกาศเช่น:

requirejs.config({
    paths: {
          'underscore' : '.../example/XX.js' // your JavaScript file
          'jquery' : '.../example/jquery.js' // your JavaScript file
    }
    shim: {
        'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                return this.Foo.noConflict();
            }
        }
    }
});

1
คำตอบนี้คือการถ่ายโอนข้อมูลรหัสที่ไม่ได้อธิบายว่า "ทำไมและเมื่อใดจึงควรใช้ shim config" หากคุณแก้ไขคำตอบของคุณเพื่อให้คำอธิบายตรวจสอบให้แน่ใจว่าคุณกำลังเพิ่มสิ่งใหม่ซึ่งยังไม่ครอบคลุมคำตอบก่อนหน้านี้
หลุยส์

คัดลอกวางโดยไม่มีข้อเสนอแนะในเชิงบวก
william.eyidi

ควรเป็นลูกน้ำก่อน shim:
Scott
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.