web-dev-qa-db-ja.com

Browserify-shimを使用して汎用jQueryプラグインを構成しますか?

Browserify-shimを使用していますが、汎用のjQueryプラグインを使用します。 Browserify-shimのドキュメントを何度も確認しましたが、何が起こっているのか、プラグインを置く場所、jQueryオブジェクトにアタッチする場所などをどのように知っているのか理解できないようです。 :

"browser": {
  "jquery": "./src/js/vendor/jquery.js",
  "caret": "./src/js/vendor/jquery.caret.js"
},

"browserify-shim": {
  "caret": {
     "depends": ["jquery:$"]
  }
}

Browserify-shimのドキュメントに記載されている例によれば、このプラグイン(およびすべてではないにしてもほとんどのjQueryプラグイン)がjQueryオブジェクトに自身をアタッチするため、エクスポートを指定したくありません。上記で何か間違ったことをしていない限り、使用したときになぜ機能しないのかわかりません(関数が定義されていないことを示すエラーが表示されます)。下記参照:

$('#contenteditable').caret(5);  // Uncaught TypeError: undefined is not a function

だから私の質問は、browserifyとbrowserify-shimで一般的なjQueryプラグイン(jQueryオブジェクトに自分自身をアタッチする)をどのように設定するのですか?

40
Glen Selle

これを再検討し、さらにいくつかのことを試した後、私はついにbrowserify-shimが何をして、どのようにそれを使用するかについて頭を包みました。私にとって、browserify-shimの使用方法を最終的に理解する前に理解しなければならない重要な原則が1つありました。 2つの異なるユースケースでbrowserify-shimを使用するには、基本的に2つの方法があります。公開とシムです。

バックグラウンド

マークアップにスクリプトタグをドロップするだけだとします(テストや、キャッシュ、CDNなどのパフォーマンス上の理由のため)。マークアップにスクリプトタグを含めると、ブラウザーはスクリプトにヒットして実行し、ウィンドウオブジェクト(JSではグローバルとも呼ばれます)にプロパティをアタッチします。もちろん、myGlobalまたは_window.myGlobal_を実行することでアクセスできます。しかし、どちらの構文にも問題があります。 CommonJS仕様に準拠していません。つまり、モジュールがCommonJS構文(require())のサポートを開始すると、それを利用できなくなります。

ソリューション

Browserify-shimでは、CommonJS require()構文を使用して、「公開」したいグローバルを指定できます。 _var whatever = global;_または_var whatever = window.global;_を行うことはできますが、var whatever = require('global')を行うことはできず、適切なlib/moduleを提供することを期待できます。変数の名前について混同しないでください。 arbitrary意的なものであれば何でもかまいません。基本的に、グローバル変数をローカル変数にしています。馬鹿げているように聞こえますが、ブラウザでのJSの悲しい状態です。繰り返しになりますが、ライブラリがCommonJS構文をサポートすると、ウィンドウオブジェクトのグローバルを介してアタッチされることはありません。つまり、require()構文を使用してローカル変数に割り当て、必要な場所で使用する必要があります。

注: browserify-shim docs/examplesで変数の命名が少しわかりにくいことがわかりました。重要なのは、libを含めることですあたかもそれは適切に動作するCommonJSモジュールでした。したがって、最終的に行うことは、myGlobal require('myGlobal')が必要なとき、実際には_window.myGlobal_であるウィンドウオブジェクトのグローバルプロパティを与えたいだけであることをbrowserifyに伝えることです。

実際、require関数が実際に何をするのか興味があれば、それは非常に簡単です。ここでは、内部で何が起こるかを示します。

_var whatever = require('mygGlobal');
_

になる...

_var whatever = window.mygGlobal;
_

露出

そこで、その背景で、browserify-shim configでモジュール/ライブラリを公開する方法を見てみましょう。基本的に、browserify-shimに2つのことを伝えます。 require()を呼び出したときにアクセスできるようにする名前と、ウィンドウオブジェクトで検出されると予想されるグローバル。そのため、ここで_global:*_構文が使用されます。例を見てみましょう。 index.htmlのスクリプトタグとしてjqueryをドロップしたいので、パフォーマンスが向上します。私の設定で必要なことは次のとおりです(これはpackage.jsonまたは外部設定JSファイルにあります)。

_"browserify-shim": {
  "jquery": "global:$"
}
_

その意味は次のとおりです。 jQueryを別の場所に含めました(browserify-shimにはタグを配置する場所がわかりませんが、知る必要はありません)が、必要なのはウィンドウの_$_プロパティを指定することだけです文字列パラメーター「jquery」を持つモジュールが必要な場合はオブジェクト。さらに説明するために。私もこれを行うことができた:

_"browserify-shim": {
  "thingy": "global:$"
}
_

この場合、jQueryオブジェクトのインスタンスを取得するために、require関数にパラメーターとして「thingy」を渡す必要があります(_window.$_からjQueryを取得するだけです)。

_var $ = require('thingy');
_

はい、繰り返しますが、変数名は何でもかまいません。 _$_が、実際のjQueryライブラリが使用するグローバルプロパティ_$_と同じであることについて特別なことはありません。混乱を避けるために同じ名前を使用するのは理にかなっていますが。これは、package.jsonの_$_オブジェクトの_global:$_値によって選択された、ウィンドウオブジェクトの_browserify-shim_プロパティを参照することになります。

シミング

わかりました、それでほとんど露出をカバーします。 browserify-shimのもう1つの主な機能はシミングです。それは何ですか? Shimmingは、スクリプトタグなどのHTMLマークアップにlibまたはモジュールを含めるのではなく、JSファイルをローカルに取得する場所をbrowserify-shimに指示することを除いて、基本的に公開と同じことを行います。 _global:*_構文を使用する必要はありません。それでは、jQueryの例に戻りましょう。ただし、今回はCDNからjQueryをロードするのではなく、単にすべてのJSファイルにバンドルするものとします。そのため、構成は次のようになります。

_"browser": {
  "jquery": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file
},
"browserify-shim": {
  "jquery": "$"
},
_

この構成は、指定されたローカルパスからjQueryをロードし、ウィンドウオブジェクトから$プロパティを取得し、jQueryが "jquery"のrequire関数に文字列パラメーターを要求するときにそれを返すようbrowserify-shimに指示します。繰り返しますが、説明のために、これを他の名前に変更することもできます。

_"browser": {
  "thingy": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file
},
"browserify-shim": {
  "thingy": "$"
},
_

必要なものは次のとおりです。

_var whatever = require('thingy');
_

exportsプロパティと、libをbrowserify-shimに伝えることができるdependsプロパティを使用したロングハンド構文の詳細については、browserify-shimのドキュメントを参照することをお勧めします別のlib/moduleに依存します。ここで説明したことは両方に当てはまります。これが、browserify-shimが実際に何をしていて、それをどのように使用するかを理解するのに苦労している他の人を助けることを願っています。

匿名シミング

匿名シミングは、browserifyの_--standalone_オプションを使用してjQueryなどのライブラリをUMDモジュールに変換できるbrowserify-shimの代替です。

_$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js
_

スクリプトタグにドロップした場合、このモジュールはthingyとしてjQueryをウィンドウオブジェクトに追加します。もちろん、_$_または任意の名前にすることもできます。

ただし、ブラウザ化されたアプリバンドルvar $ = require("./dist/jquery-UMD.js");requireedされている場合、jQueryはウィンドウオブジェクトに追加せずにアプリ内で使用できます。

このメソッドはbrowserify-shimを必要とせず、moduleオブジェクトを探し、そのファクトリにnoGlobalフラグを渡すjQueryのCommonJS認識を活用して、ウィンドウオブジェクトにアタッチしないように指示します。 。

97
Glen Selle

具体的な例を探しているすべての人にとって:

以下は、jQuery/_package.json_オブジェクトにアタッチするjQueryプラグインの_app.js_および_$_ファイルの例です。例:$('div').expose()jQueryが必要なときにグローバル変数(_window.jQuery_)にしたくないので、jQueryは_'exports': null_に設定されています。ただし、プラグインはそれ自体をアタッチできるグローバルjQueryオブジェクトを想定しているため、ファイル名の後に依存関係で指定する必要があります:_./jquery-2.1.3.js:jQuery_。さらに、プラグインを使用する場合は、プラグインを使用しない場合でも、実際にはjQueryグローバルをエクスポートする必要があります。

package.json

_{
  "name": "test",
  "version": "0.1.0",
  "description": "test",
  "browserify-shim": {
    "./jquery-2.1.3.js": { "exports": null },
    "./jquery.expose.js": { "exports": "jQuery", "depends": [ "./jquery-2.1.3.js:jQuery" ] }
  },
  "browserify": {
    "transform": [
      "browserify-shim"
    ]
  }
}
_

app.js

_// copy and delete any previously defined jQuery objects
if (window.jQuery) {
  window.original_jQuery = window.jQuery;
  delete window.jQuery;

  if (typeof window.$.fn.jquery === 'string') {
    window.original_$ = window.$;
    delete window.$;
  }
}

// exposes the jQuery global
require('./jquery.expose.js');
// copy it to another variable of my choosing and delete the global one
var my_jQuery = jQuery;
delete window.jQuery;

// re-setting the original jQuery object (if any)
if (window.original_jQuery) { window.jQuery = window.original_jQuery; delete window.original_jQuery; }
if (window.original_$) { window.$ = window.original_$; delete window.original_$; }

my_jQuery(document).ready(function() {
  my_jQuery('button').click(function(){
    my_jQuery(this).expose();
  });
});
_

上記の例では、コードでグローバルを設定したくありませんでしたが、プラグインを機能させるために一時的に設定する必要がありました。 jQueryのみが必要な場合は、これを行うだけで回避策は必要ありません:var my_jQuery = require('./jquery-2.1.3.js')。 jQueryがグローバルとして公開されることに問題がない場合は、上記の_package.json_の例を次のように変更できます。

_  "browserify-shim": {
    "./jquery-2.1.3.js": { "exports": "$" },
    "./jquery.expose.js": { "exports": null, "depends": [ "./jquery-2.1.3.js" ] }
_

(この質問を見つけたときのように)具体的な例を探していた一部の人々に役立つことを願っています。

13
gottlike

完全を期すために、jQueryのCommonJS認識を活用して、実際にシムする必要なくwindowオブジェクトの汚染を心配する必要のない方法を紹介します。

特徴

  1. バンドルに含まれるjQuery
  2. バンドルに含まれるプラグイン
  3. windowオブジェクトの汚染なし

構成

./ package.jsonで、browserノードを追加して、リソースの場所のエイリアスを作成します。 これは純粋に便宜上のものであり、モジュールとグローバルスペース(スクリプトタグ)の間に通信がないため、実際に何もシムする必要はありません

{
  "main": "app.cb.js",
  "scripts": {
    "build": "browserify ./app.cb.js > ./app.cb.bundle.js"
  },
  "browser": {
    "jquery": "./node_modules/jquery/dist/jquery.js",
    "expose": "./js/jquery.expose.js",
    "app": "./app.cb.js"
  },
  "author": "cool.blue",
  "license": "MIT",
  "dependencies": {
    "jquery": "^3.1.0"
  },
  "devDependencies": {
    "browserify": "^13.0.1",
    "browserify-shim": "^3.8.12"
  }
}

方法

  • JQueryは最近CommonJSに対応しているため、browserifyによって提供されるmoduleオブジェクトの存在を検知し、インスタンスを返します。 windowオブジェクトに追加します。
  • アプリでrequire jqueryをmodule.exportsオブジェクトに追加します(共有する必要のある他のコンテキストとともに)。
  • プラグインの先頭に1行追加して、アプリが作成したjQueryインスタンスにアクセスすることを要求します。
  • アプリで、jQueryインスタンスを$にコピーし、プラグインでjQueryを使用します。
  • デフォルトのオプションを使用してアプリをブラウザ化し、結果のバンドルをHTMLのスクリプトタグにドロップします。

コード

app.cb.js

var $ = module.exports.jQuery = require("jquery");
require('expose');

$(document).ready(function() {

    $('body').append(
        $('<button name="button" >Click me</button>')
            .css({"position": "relative",
                  "top": "100px", "left": "100px"})
            .click(function() {
                $(this).expose();
            })
    );
});

プラグインの上部

var jQuery = require("app").jQuery;

hTMLで

<script type="text/javascript" src="app.cb.bundle.js"></script>

バックグラウンド

JQueryで使用されるパターンは、CommonJS環境を検知した場合、noGlobalフラグを使用してファクトリを呼び出すことです。インスタンスをwindowオブジェクトに追加せず、常にインスタンスを返します。

CommonJSコンテキストは、デフォルトでbrowserifyによって作成されます。以下は、jQueryモジュール構造を示すバンドルからの簡単な抜粋です。わかりやすくするために、windowオブジェクトの同型処理を扱うコードを削除しました。

3: [function(require, module, exports) {

    ( function( global, factory ) {

        "use strict";

        if ( typeof module === "object" && typeof module.exports === "object" ) {
            module.exports = factory( global, true );
        } else {
            factory( global );
        }

    // Pass this if window is not defined yet
    } )( window, function( window, noGlobal ) {

    // ...

    if ( !noGlobal ) {
        window.jQuery = window.$ = jQuery;
    }

    return jQuery;
    }) );
}, {}]

私が見つけた最良の方法は、ノードモジュールシステムで物事を機能させることです。そうすると、ブラウザ化後に毎回機能します。
jsdomを使用してwindowオブジェクトをシムし、コードが同型になるようにします。次に、ノードで動作するように焦点を合わせます。次に、モジュールとグローバルスペース間のトラフィックをシムし、最終的にブラウザー化して、ブラウザーでのみ機能するようにします。

1
Cool Blue

私はワードプレスを使用していました。したがって、windowオブジェクトで使用可能なwordpressコアのjQueryを使用することを強いられました。

Npmからslick()プラグインを使用しようとしたときに、slick() not definedエラーが生成されていました。 _browserify-shim_を追加してもあまり役に立ちませんでした。

掘り下げてみると、require('jquery')が常に一貫していないことがわかりました。

私のテーマのjavascriptファイルでは、wordpressコアのjqueryを呼び出していました。

しかし、slick jqueryプラグインでは、ノードモジュールから最新のjqueryを呼び出していました。

最後に、私はそれを解決することができました。したがって、_package.json_およびgulpfile構成を共有します。

package.json:

_"browserify": { "transform": [ "browserify-shim" ] }, "browserify-shim": { "jquery": "global:jQuery" },_

gulpfile.babel.js:

browserify({entries: 'main.js', extensions: ['js'], debug: true}) .transform(babelify.configure({ presets: ["es2015"] })) .transform('browserify-shim', {global: true})

変換 'browserify-shim'を実行することは重要な部分でしたが、以前は行方不明でした。それなしでは、_browserify-shim_は一貫していませんでした。

0
Jashwant