Membutuhkan mengapa dan kapan menggunakan konfigurasi shim

97

Saya membaca dokumen requirejs dari sini 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();
            }
        }
    }
});

tetapi saya tidak mendapatkan bagian shim darinya. mengapa saya harus menggunakan shim dan bagaimana cara mengkonfigurasi, dapatkah saya mendapatkan klarifikasi lebih lanjut

tolong ada yang bisa menjelaskan dengan contoh mengapa dan kapan kita harus menggunakan shim. Terima kasih.

Anil Gupta
sumber

Jawaban:

110

Penggunaan utama shim adalah dengan pustaka yang tidak mendukung AMD, tetapi Anda perlu mengelola dependensinya. Misalnya, pada contoh Backbone dan Underscore di atas: Anda tahu bahwa Backbone membutuhkan Underscore, jadi misalkan Anda menulis kode seperti ini:

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

    // do something with Backbone

}

RequireJS akan memulai permintaan asynchronous untuk Underscore dan Backbone, tetapi Anda tidak tahu mana yang akan kembali lebih dulu sehingga mungkin Backbone akan mencoba melakukan sesuatu dengan Underscore sebelum dimuat.

CATATAN: contoh garis bawah / backbone ini ditulis sebelum kedua pustaka tersebut mendukung AMD. Tetapi prinsip tersebut berlaku untuk semua perpustakaan saat ini yang tidak mendukung AMD.

Hook "init" memungkinkan Anda melakukan hal-hal lanjutan lainnya, misalnya jika sebuah perpustakaan biasanya mengekspor dua hal yang berbeda ke dalam namespace global tetapi Anda ingin mendefinisikannya kembali di bawah satu namespace. Atau, mungkin Anda ingin melakukan patch monyet pada metode di library yang Anda muat.

Lebih banyak latar belakang:

meledak
sumber
Seperti kode contoh Anda, Underscoredan di Backbonesini digunakan seperti biasa, apa yang shimdilakukan dalam kasus ini? Dapatkah saya menggunakan require( function() { _.extend({}); })? Apakah itu mengerti _?
Stiger
"RequireJS akan memulai permintaan asinkron untuk kedua Underscore dan Backbone" -> Apakah mungkin untuk mencegah hal ini, jika pustaka sudah dimuat?
Codii
1
@Codii benar, jika pustaka sudah dimuat itu tidak akan memulai permintaan server lain, tetapi poin dari RequireJS adalah bahwa kode Anda tidak perlu peduli jika / bagaimana itu terjadi. Mungkin memulai pertanyaan baru untuk kasus penggunaan khusus Anda?
meledak
63

Sesuai dokumentasi RequireJS API, shim memungkinkan Anda

Konfigurasikan dependensi, ekspor, dan inisialisasi khusus untuk skrip "browser global" tradisional yang lebih lama yang tidak menggunakan define () untuk mendeklarasikan dependensi dan menyetel nilai modul.

- Konfigurasi dependensi

Katakanlah Anda memiliki 2 modul javascript (moduleA dan moduleB) dan salah satunya (moduleA) bergantung pada yang lain (moduleB). Keduanya diperlukan untuk modul Anda sendiri sehingga Anda menentukan dependensi di require () atau define ()

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

Tetapi karena mengharuskan dirinya mengikuti AMD, Anda tidak tahu mana yang akan diambil lebih awal. Di sinilah shim datang untuk menyelamatkan.

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

})

Ini akan memastikan moduleB selalu diambil sebelum moduleA dimuat.

- Konfigurasi ekspor

Ekspor Shim memberi tahu RequireJS anggota apa pada objek global (jendela, dengan asumsi Anda berada di browser, tentu saja) adalah nilai modul yang sebenarnya. Katakanlah moduleA menambahkan dirinya ke windowas 'modA' (seperti jQuery dan underscore masing-masing sebagai $ dan _), lalu kita membuat nilai ekspor 'modA'.

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

Ini akan memberi RequireJS referensi lokal ke modul ini. ModA global akan tetap ada di halaman juga.

-Inisialisasi kustom untuk skrip "browser global" yang lebih lama

Ini mungkin fitur terpenting dari shim config yang memungkinkan kita menambahkan skrip 'browser global', 'non-AMD' (yang juga tidak mengikuti pola modular) sebagai dependensi dalam modul kita sendiri.

Katakanlah moduleB adalah javascript lama biasa dengan hanya dua fungsi funcA () dan funcB ().

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

Meskipun kedua fungsi ini tersedia dalam cakupan jendela, RequireJS merekomendasikan kita untuk menggunakannya melalui pengenal / pegangan globalnya untuk menghindari kebingungan. Jadi mengkonfigurasi shim sebagai

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

Nilai yang dikembalikan dari fungsi init digunakan sebagai nilai ekspor modul daripada objek yang ditemukan melalui string 'ekspor'. Ini akan memungkinkan kita untuk menggunakan funcB dalam modul kita sendiri sebagai

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

Semoga ini bisa membantu.

nalinc
sumber
3
Mudah dimengerti! Satu pertanyaan: pada contoh terakhir, apakah properti "ekspor" diabaikan begitu saja?
Niko Bellic
Tidak, itu tidak diabaikan. Jika properti "ekspor" diabaikan dalam contoh terakhir, maka objek yang Anda berikan sebagai parameter ('B' dalam kasus ini) tidak akan ditentukan karena moduleB TIDAK sesuai dengan AMD dan tidak akan mengembalikan objek untuk digunakan oleh RequireJS ( maka 'B.funcB' tidak akan berfungsi).
nalinc
Hmm. Saya pikir nilai ekspor akan dikesampingkan oleh objek yang dikembalikan dalam fungsi init. Jadi parameter B adalah objek {funcA: funcA, funcB: funcB}, bukan hanya funcB itu sendiri. Apa ini tidak benar?
Niko Bellic
4
Niko Bellic benar, ekspor IS diabaikan (saya baru saja mengujinya). Objek B adalah objek yang dikembalikan oleh fungsi yang ditentukan di bagian 'init'. Jika Anda menghapus bagian 'init', objek B akan menjadi function funcB, jadi Anda cukup melakukan B () daripada B.funcB (). Dan jelas FuncA akan menjadi tidak dapat diakses dalam kasus itu.
pengguna4205580
-2

Anda harus menambahkan jalur di requirejs.config untuk dideklarasikan, contoh:

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();
            }
        }
    }
});
Rachman Anwar
sumber
1
Jawaban ini adalah dump kode yang tidak menjelaskan "mengapa dan kapan menggunakan konfigurasi shim". Jika Anda mengedit jawaban Anda untuk memberikan penjelasan, pastikan Anda menambahkan sesuatu yang baru, yang belum tercakup dalam jawaban sebelumnya
Louis
salin tempel tanpa umpan balik positif
william.eyidi
harus koma sebelum shim:
Scott