必要な理由とシム設定を使用するタイミング


97

こちらのAPIからrequirejsドキュメントを読みました

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();
            }
        }
    }
});

しかし、私はそれのシムの一部を取得していません。なぜシムを使用する必要があり、どのように構成する必要がありますか?

シムを使用する理由と時期を例を挙げて説明してください。ありがとう。

回答:


110

シムの主な用途は、AMDをサポートしないライブラリでの使用ですが、それらの依存関係を管理する必要があります。たとえば、上記のバックボーンとアンダースコアの例では、バックボーンにはアンダースコアが必要であることを知っているので、次のようにコードを記述したとします。

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

    // do something with Backbone

}

RequireJSは、UnderscoreとBackboneの両方の非同期要求を開始しますが、どちらが最初に戻るのかわからないため、Backboneが読み込まれる前にUnderscoreで何かをしようとする可能性があります。

注:このアンダースコア/バックボーンの例は、これらの両方のライブラリがAMDをサポートする前に作成されました。しかし、この原則は、AMDをサポートしない今日のライブラリーにも当てはまります。

「init」フックを使用すると、他の高度なことを実行できます。たとえば、ライブラリは通常、2つの異なるものをグローバル名前空間にエクスポートするが、それらを単一の名前空間で再定義する場合などです。または、ロードしているライブラリのメソッドにサルのパッチを適用したい場合もあります。

その他の背景:


例のコードのように、ここUnderscoreBackboneここでは通常のように使用shimしますが、この場合はどうしますか?使用できますrequire( function() { _.extend({}); })か?分かり_ますか?
Stiger 2014

「RequireJSはアンダースコアとバックボーンの両方の非同期リクエストを開始します」->ライブラリがすでにロードされている場合、これを防ぐことはできますか?
Codii、2015年

1
@Codii正しい、ライブラリが既にロードされている場合、別のサーバーリクエストは開始されませんが、RequireJSのポイントは、コードがそれが発生するかどうか、または発生する方法を気にする必要がないことです。おそらく、あなたの特定のユースケースについて新しい質問を始めますか?
explunit 2015年

63

RequireJS APIドキュメントに従って、shimを使用すると

依存関係を宣言してモジュール値を設定するためにdefine()を使用しない古い従来の「ブラウザグローバル」スクリプトの依存関係、エクスポート、およびカスタム初期化を構成します。

-依存関係の構成

2つのjavascriptモジュール(moduleAとmoduleB)があり、そのうちの1つ(moduleA)が他のモジュール(moduleB)に依存しているとします。これらは両方とも独自のモジュールに必要なので、require()またはdefine()で依存関係を指定します

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

しかし、それ自体がAMDに従う必要があるため、どれが早期にフェッチされるかはわかりません。これはシムが助けになるところです。

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

})

これにより、moduleAがロードされる前にmoduleBが必ずフェッチされるようになります。

-エクスポートの構成

Shimエクスポートは、グローバルオブジェクト(もちろん、ブラウザーを使用している場合はウィンドウ)のどのメンバーが実際のモジュール値であるかをRequireJSに通知します。moduleAがそれ自体をwindow'modA'として追加すると(jQueryと同じようにアンダースコアがそれぞれ$と_として追加されます)、エクスポート値を 'modA'にします。

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

RequireJSにこのモジュールへのローカル参照を提供します。グローバルmodAはまだページにも存在します。

-古い「ブラウザグローバル」スクリプトのカスタム初期化

これはおそらく、shim configの最も重要な機能であり、「ブラウザグローバル」、「AMD以外」のスクリプト(モジュールパターンにも従わない)を独自のモジュールの依存関係として追加できます。

moduleBが、2つの関数funcA()とfuncB()だけの単純な古いJavaScriptであるとしましょう。

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

これらの関数はどちらもウィンドウスコープで使用できますが、RequireJSでは、混乱を避けるために、グローバル識別子/ハンドルを通じてこれらを使用することをお勧めします。したがって、シムを次のように構成します

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

init関数からの戻り値は、「exports」文字列を介して見つかったオブジェクトの代わりに、モジュールのエクスポート値として使用されます。これにより、独自のモジュールでfuncBを使用できます。

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

これがお役に立てば幸いです。


3
わかりやすい!1つの質問:最後の例では、 "exports"プロパティは単に無視されますか?
Niko Bellic 2015年

いいえ、無視されていません。最後の例で「exports」プロパティが無視された場合、パラメーターとして渡すオブジェクト(この場合は「B」)は未定義になります。moduleBはAMDに準拠しておらず、RequireJSが使用するオブジェクトを返さなかったためです(したがって、「B.funcB」は機能しません)。
nalinc 2015年

うーん。エクスポートの値は、init関数で返されるオブジェクトによって上書きされると思いました。したがって、パラメータBは、単なるfuncBだけではなく、オブジェクト{funcA:funcA、funcB:funcB}になります。これは本当ではないですか?
Niko Bellic 2015年

4
Niko Bellicは正解です。エクスポートは無視されます(テストしたばかりです)。オブジェクトBは、「init」部分で指定された関数によって返されるオブジェクトです。「init」部分を削除した場合、オブジェクトBは関数funcBになるため、B.funcB()の代わりにB()を実行します。その場合、明らかにfuncAはアクセスできなくなります。
user4205580 2016年

-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を使用する理由とタイミング」を説明するコードダンプです。説明を提供するために回答を編集する場合、以前の回答ではまだカバーされていない何か新しいものを追加していることを確認してください
Louis

正のフィードバックなしのコピーペースト
william.eyidi

シムの前のカンマである必要があります:
スコット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.