モノMagento 2は「ミックスイン」と呼ばれるものをどのように実装していますか?


16

Magento 2のRequireJSベースのオブジェクトシステムには、「ミックスイン」と呼ばれる機能が含まれています。Magento 2のミックスインは、ソフトウェアエンジニアが通常ミックスイン/特性と考えるものではありません。代わりに、Magento 2ミックスインを使用すると、RequireJSモジュールが返すオブジェクト/値を、メインプログラムがそのオブジェクト/値を使用する前に変更できます。このようにMagento 2ミックスインを設定します(requirejs-config.jsファイルを使用)

var config = {
    'config':{
        'mixins': {
            //the module to modify
            'Magento_Checkout/js/view/form/element/email': {
                //your module that will do the modification
                'Pulsestorm_RequireJsRewrite/hook':true
            }
        }
    }
};

次に、hook.js(または構成したRequireJSモジュール)が必要です。

define([], function(){
    console.log("Hello");
    return function(theObjectReturnedByTheModuleWeAreHookingInto){
        console.log(theObjectReturnedByTheModuleWeAreHookingInto);
        console.log("Called");
        return theObjectReturnedByTheModuleWeAreHookingInto;
    };
});

関数を返します。Magentoはこの関数を呼び出し、変更する「モジュール」への参照を渡します。この例では、RequireJSモジュールによって返されるオブジェクトになりますMagento_Checkout/js/view/form/element/email。これは関数である場合も、スケーラー値である場合もあります(RequireJSモジュールが返すものに応じて)。

このシステムはmixins、元のRequireJSモジュールから返されたオブジェクトがextendメソッドをサポートしている場合にmixinのような動作を作成できるため、呼び出されているように見えます。

define([], function(){
    'use strict';
    console.log("Hello");

    var mixin = {
        ourExtraMethod = function(){
            //...
        }
    };

    return function(theObjectReturnedByTheModuleWeAreHookingInto){
        console.log(theObjectReturnedByTheModuleWeAreHookingInto);
        console.log("Called");


        return theObjectReturnedByTheModuleWeAreHookingInto.extend(mixin);
    };
});

ただし、システム自体は、モジュールオブジェクトの作成にフックする方法にすぎません。

プリアンブルが終了しました-Magentoがこの機能をどのように実装したかを知っていますか?RequireJS Webサイトでは、ミックスインについて言及していないようです(ただし、GoogleはRequireJSのプラグインページが必要かもしれないと考えています)。

requirejs-config.jsファイル以外では、Magento 2のコアjavascript mixinsは3つのファイルでのみ言及しています

$ find vendor/magento/ -name '*.js' | xargs ack mixins
vendor/magento/magento2-base/lib/web/mage/apply/main.js
73:                            if (obj.mixins) {
74:                                require(obj.mixins, function () {
79:                                    delete obj.mixins;

vendor/magento/magento2-base/lib/web/mage/apply/scripts.js
39:            if (_.has(obj, 'mixins')) {
41:                data[key].mixins = data[key].mixins || [];
42:                data[key].mixins = data[key].mixins.concat(obj.mixins);
43:                delete obj.mixins;

vendor/magento/magento2-base/lib/web/mage/requirejs/mixins.js
5:define('mixins', [
24:     * Adds 'mixins!' prefix to the specified string.
30:        return 'mixins!' + name;
76:     * Iterativly calls mixins passing to them
80:     * @param {...Function} mixins
84:        var mixins = Array.prototype.slice.call(arguments, 1);
86:        mixins.forEach(function (mixin) {
96:         * Loads specified module along with its' mixins.
102:                mixins   = this.getMixins(path),
103:                deps     = [name].concat(mixins);
111:         * Retrieves list of mixins associated with a specified module.
114:         * @returns {Array} An array of paths to mixins.
118:                mixins = config[path] || {};
120:            return Object.keys(mixins).filter(function (mixin) {
121:                return mixins[mixin] !== false;
126:         * Checks if specified module has associated with it mixins.
137:         * the 'mixins!' plugin prefix if it's necessary.
172:    'mixins'
173:], function (mixins) {
237:        deps = mixins.processNames(deps, context);
252:            queueItem[1] = mixins.processNames(lastDeps, context);

mixins.jsファイルが(に基づいてプラグインRequireJSように見えます!...が、とき、それは100%はっきりしていない-この権利です?コメントで言及)main.jsまたはscripts.jsMagentoのによって呼び出される、またはどのようにカスタムmixins設定からそれを作るrequirejs-config.jsリスナー/フックシステムに上記のとおり。

「mixin」が適用される場合と適用されない理由をデバッグできるように、このシステムがどのように実装されたのか、構築されたのか、誰にも説明がありますか?

回答:


18

私はあなたの質問にまっすぐに行きたいと思います。それから、あなたが実際にmixinsプラグインで何ができるかを明確にしようとします。だから、まず最初に。

実装

ここでの主なことは、RequireJSプラグインが特定のファイルの読み込みプロセスを完全に引き継ぐ能力です。これにより、解決された依存関係として渡される前に、モジュールのエクスポート値を変更できます。

Magentoカスタムミックスインプラグインが実際に何であるかのこの大ざっぱな実装を見てみましょう。

// RequireJS config object.
// Like this one: app/code/Magento/Theme/view/base/requirejs-config.js
{
    //...

    // Every RequireJS plugin is a module and every module can
    // have it's configuration.
    config: {
        sampleMixinPlugin: {
            'path/to/the/sampleModule': ['path/to/extension']
        }
    }
}

define('sampleMixinPlugin', [
    'module'
] function (module) {
    'use strict';

    // Data that was defined in the previous step.
    var mixinsMap = module.config();

    return {
        /**
         * This method will be invoked to load a module in case it was requested
         * with a 'sampleMixinPlugin!' substring in it's path,
         * e.g 'sampleMixinPlugin!path/to/the/module'.
         */
        load: function (name, req, onLoad) {
            var mixinsForModule = [],
                moduleUrl = req.toUrl(name),
                toLoad;

            // Get a list of mixins that need to be applied to the module.
            if (name in mixinsMap) {
                mixinsForModule = mixinsMap[name];
            }

            toLoad = [moduleUrl].concat(mixinsForModule);

            // Load the original module along with mixins for it.
            req(toLoad, function (moduleExport, ...mixinFunctions) {
                // Apply mixins to the original value exported by the sampleModule.
                var modifiedExport = mixinFunctions.reduce(function (result, mixinFn) {
                        return mixinFn(result);
                }, moduleExport);

                // Tell RequireJS that this is what was actually loaded.
                onLoad(modifiedExport);
            });
        }
    }
});

最後で最も難しい部分は、「sampleMixinPlugin!」を動的に追加することです 要求されたモジュールのサブストリング。この私たちのインターセプトを行うにdefineしてrequire呼び出しを、彼らは元RequireJS負荷法によって処理される前に、依存関係のリストを変更します。少し注意がlib/web/mage/requirejs/mixins.js必要です。どのように機能するかを知りたい場合は、実装を確認することをお勧めします。

デバッグ

この手順をお勧めします。

  • 「mixins!」の構成を確認してください プラグインは実際にあります。
  • モジュールへのパスが変更されていることを確認します。つまり、からpath/to/moduleに変わりmixins!path/to/moduleます。

そして最後になりましたが、属性またはモジュールrequiresjs/mixins.jsとは何の関係もありません。これらは、属性から渡される構成のみを拡張できるからです。main.jsscript.jsdata-mage-init

<div data-mage-init='{
    "path/to/module": {
        "foo": "bar",
        "mixins": ["path/to/configuration-modifier"]
    }
}'></div>

前の2つのファイルは、モジュールによって返される値を台無しにせず、代わりにインスタンスの構成を前処理します。

使用例

まず、いわゆる「ミックスイン」(名前の間違いについては正しい)が実際にモジュールのエクスポートされた値を任意の方法で変更できるように、レコードをまっすぐに設定したいと思います。これはもっと一般的な方法だと思います。

モジュールによってエクスポートされる機能に追加機能を追加する簡単なサンプルを次に示します。

// multiply.js
define(function () {
    'use strict';

    /**
     * Multiplies two numeric values.
     */
    function multiply(a, b) {
        return a * b;
    }

    return multiply;
});

// extension.js
define(function () {
    'use strict';

    return function (multiply) {
        // Function that allows to multiply an arbitrary number of values.
        return function () {
            var args = Array.from(arguments);

            return args.reduce(function (result, value) {
                return multiply(result, value);
            }, 1);
        };
    };
});

// dependant.js
define(['multiply'], function (multiply) {
    'use strict';

    console.log(multiply(2, 3, 4)); // 24
});

モジュールによって返されるオブジェクト/関数の実際のミックスインを実装でき、extendメソッドにまったく依存する必要はありません。

コンストラクター関数の拡張:

// construnctor.js
define(function () {
    'use strict';

    function ClassA() {
        this.property = 'foo';
    }

    ClassA.prototype.method = function () {
        return this.property + 'bar';
    }

    return ClassA;
});

// mixin.js
define(function () {
    'use strict';

    return function (ClassA) {
        var originalMethod = ClassA.prototype.method;

        ClassA.prototype.method = function () {
            return originalMethod.apply(this, arguments) + 'baz';
        };

        return ClassA;
    }
});

これがあなたの質問に答えることを願っています。

よろしく。


ありがとうございました!私が探していたもの-私が持っている他の唯一の質問は- mixins構成は何をしてx-magento-initdata-mage-init構成ですか?つまり、上記の例ではpath/to/configuration-modifier、構成データを変更できるコールバックも返しますか?または、他の何か?
アランストーム

はい、正確に!構成データを変更できるコールバックを返すことになっています。
デニスルール

あなたはフロントエンドの周りのあなたの方法をかなりよく知っているようです-これらの2つの質問に関する洞察はありますか?magento.stackexchange.com/questions/147899/... magento.stackexchange.com/questions/147880/...
アラン・ストーム

4

デニス・ルルの 答えを締めくくるために。

そのため、Magentoページを見ると、Magento <script/>をロードする3つのタグがあります。

<script  type="text/javascript"  src="http://magento.example.com/pub/static/frontend/Magento/luma/en_US/requirejs/require.js"></script>
<script  type="text/javascript"  src="http://magento.example.com/pub/static/frontend/Magento/luma/en_US/mage/requirejs/mixins.js"></script>
<script  type="text/javascript"  src="http://magento.example.com/pub/static/_requirejs/frontend/Magento/luma/en_US/requirejs-config.js"></script>

これは、RequireJS自体(require.js)、mixins.jsプラグイン、およびマージされたRequireJS構成requirejs-config.js)です。

mixins.jsファイルは、RequireJSプラグインを定義します。このプラグインは、他のRequireJSモジュールのインスタンス化をリッスンするRequireJSモジュールのロードと呼び出しを行います。

このプラグインには、mixinプラグインを定義した後のrequirejsプログラム含まれています。

require([
    'mixins'
], function (mixins) {
    'use strict';
    //...

    /**
     * Overrides global 'require' method adding to it dependencies modfication.
     */
    window.require = function (deps, callback, errback, optional) {
        //...
    };

    //...

    window.define = function (name, deps, callback) {
        //...
    };

    window.requirejs = window.require;
});

この第二のプログラムは、単に定義されたロードmixins依存関係としてプラグインを、その後、再定義のグローバルrequiredefineおよびrequirejs機能を。この再定義により、「実際にはミックスインではない」システムが、通常の関数に物を戻す前にRequireJSモジュールの初期インスタンス化にフックできるようになります。

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