Magento 2 เรียกสิ่งนี้ว่า“ มิกซ์อิน” ได้อย่างไร?


16

ระบบวัตถุที่ใช้ RequireJS ของ Magento 2 นั้นมีคุณสมบัติที่เรียกว่า "มิกซ์อิน" วีโอไอพี 2 mixin ไม่ใช่สิ่งที่วิศวกรซอฟต์แวร์มักจะคิดว่าเป็นmixin / ลักษณะ Magento 2 mixin ช่วยให้คุณสามารถปรับเปลี่ยนวัตถุ / ค่าที่ส่งคืนโดยโมดูล RequireJS ก่อนที่โปรแกรมหลักจะใช้วัตถุ / ค่านั้น คุณกำหนดค่า mixento 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(หรือโมดูลใดก็ตามที่คุณต้องการกำหนดค่า JJ)

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

ส่งคืนฟังก์ชัน Magento จะเรียกใช้ฟังก์ชันนี้ผ่านการอ้างอิงถึง "โมดูล" ที่คุณต้องการแก้ไข Magento_Checkout/js/view/form/element/emailในตัวอย่างของเรานี้จะถูกวัตถุที่ส่งกลับโดยโมดูล RequireJS นี่อาจเป็นฟังก์ชั่นหรือแม้กระทั่งมูลค่าของเครื่องทำ Scaler

ระบบนี้ดูเหมือนจะถูกเรียกmixinsเพราะช่วยให้คุณสามารถสร้างมิกซ์อินอย่างเช่นพฤติกรรมถ้าวัตถุที่ส่งคืนโดยโมดูล RequireJS ดั้งเดิมรองรับextendวิธีการ

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 ดูเหมือนจะไม่พูดถึงมิกซ์อิน(แม้ว่า Google คิดว่าคุณอาจต้องการหน้าปลั๊กอินของ RequireJS )

นอกเหนือจากrequirejs-config.jsไฟล์แล้วจาวาสคริปต์หลักของ Magento 2 กล่าวถึงmixinsในสามไฟล์เท่านั้น

$ 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.jsจะเรียกโดยวีโอไอพีหรือวิธีการที่กำหนดเองmixinsการกำหนดค่าทำจากrequirejs-config.jsเข้าฟังระบบ / เบ็ด อธิบายไว้ข้างต้น.

ใครบ้างมีคำอธิบายสำหรับวิธีการที่ระบบนี้ / ถูกนำไปใช้ / architected ด้วยตาต่อความสามารถในการแก้ปัญหาทำไม "mixin" อาจหรือไม่อาจนำไปใช้?

คำตอบ:


18

ฉันอยากจะตอบคำถามของคุณแล้วฉันจะพยายามทำให้ชัดเจนว่าคุณสามารถทำอะไรได้บ้างกับปลั๊กอินมิกซ์อิน ดังนั้นสิ่งแรกก่อน

การดำเนินงาน

สิ่งสำคัญที่นี่คือความสามารถของปลั๊กอิน RequireJS ใด ๆ ที่จะเข้าสู่กระบวนการโหลดไฟล์บางไฟล์อย่างสมบูรณ์ สิ่งนี้อนุญาตให้แก้ไขค่าการส่งออกของโมดูลก่อนที่มันจะถูกส่งผ่านเป็นการพึ่งพาที่ได้รับการแก้ไข

ดูการใช้งานร่างนี้ของปลั๊กอินmixinsแบบกำหนดเองที่วีโอไอพีคืออะไร:

// 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/modulemixins!path/to/module

และสุดท้าย แต่ไม่ท้ายสุดrequiresjs/mixins.jsไม่มีส่วนเกี่ยวข้องกับmain.jsหรือscript.jsโมดูลเนื่องจากสามารถขยายการกำหนดค่าที่ส่งผ่านจากdata-mage-initแอ็ตทริบิวต์:

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

ฉันหมายถึงว่าไฟล์สองไฟล์ในอดีตไม่ได้ยุ่งกับค่าที่ส่งคืนโดยโมดูล แต่จะแทนที่การกำหนดค่าล่วงหน้าของอินสแตนซ์

ตัวอย่างการใช้งาน

ในการเริ่มต้นด้วยฉันต้องการตั้งค่าบันทึกตรงที่เรียกว่า "มิกซ์อิน" (คุณพูดถูกผิด) อนุญาตให้แก้ไขค่าที่ส่งออกของโมดูลในแบบที่คุณต้องการ ฉันจะบอกว่านี่เป็นกลไกทั่วไปมากขึ้น

นี่คือตัวอย่างด่วนของการเพิ่มฟังก์ชั่นพิเศษให้กับฟังก์ชั่นการส่งออกโดยโมดูล:

// 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-initและdata-mage-initการกำหนดค่า? ie - ในตัวอย่างข้างต้นคุณจะpath/to/configuration-modifierส่งคืนการเรียกกลับที่สามารถแก้ไขข้อมูลการกำหนดค่าได้หรือไม่ หรืออย่างอื่น?
Alan Storm

ใช่แน่นอน! คุณควรส่งคืนการติดต่อกลับซึ่งคุณสามารถแก้ไขข้อมูลการกำหนดค่าได้
เดนิส Rul

คุณดูเหมือนจะรู้วิธีการของคุณในส่วนหน้าสิ่งที่ค่อนข้างดี - ข้อมูลเชิงลึกเกี่ยวกับคำถามสองข้อนี้? magento.stackexchange.com/questions/147899/... magento.stackexchange.com/questions/147880/...
อลันพายุ

4

ออกรอบDenis RUL ของ คำตอบ

ดังนั้นถ้าคุณดูหน้า Magento นี่คือสาม<script/>แท็กที่โหลด Magento

<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 อื่น ๆ

ปลั๊กอินนี้ยังมีโปรแกรม requirejs หลังจากที่กำหนดปลั๊กอิน mixin

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ปลั๊กอินเป็นการอ้างอิงแล้วนิยามใหม่ของโลกrequire, defineและrequirejsฟังก์ชั่น การนิยามใหม่นี้เป็นสิ่งที่ช่วยให้ระบบ "ไม่ใช่ระบบผสมจริง ๆ " สามารถเชื่อมต่อเข้ากับการเริ่มต้นของโมดูล RequireJS ก่อนส่งสิ่งต่าง ๆ กลับไปที่ฟังก์ชั่นปกติ

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