Magento 2는 어떻게“mixins”을 구현합니까?


16

Magento 2의 RequireJS 기반 객체 시스템에는 "mixins"라는 기능이 있습니다. Magento 2 mixin은 소프트웨어 엔지니어가 일반적으로 mixin / trait 로 생각하는 것이 아닙니다 . 대신 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메소드를 지원하는 경우 믹스 인과 유사한 작동을 작성할 수 있도록 호출 된 것으로 보입니다 .

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

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

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


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

그러나 시스템 자체는 모듈 객체 생성에 연결하는 방법 일뿐입니다.

서문 완료 - 아는 사람 않는 방법 젠토이 기능을 구현했습니다? 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리스너 / 후크 시스템으로 전술 한 바와.

"mixin"이 적용되거나 적용되지 않는 이유를 디버그 할 수 있도록이 시스템이 어떻게 구현 / 구현 / 건축되었는지에 대한 설명이 있습니까?

답변:


18

나는 당신의 질문에 바로 가고 싶습니다 . 그리고 믹스 인 플러그인으로 실제로 무엇을 할 수 있는지 분명히하려고 노력할 것 입니다. 그래서 먼저해야합니다.

이행

여기서 중요한 것은 모든 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!'을 동적으로 추가하는 것입니다. 요청 된 모듈의 하위 문자열. 이를 위해 원래 RequireJS로드 메소드로 처리되기 전에 종속성 을 차단 define하고 require호출하고 종속성 목록을 수정합니다. 약간 까다 롭고 구현 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>

이전 두 파일은 모듈이 반환 한 값을 엉망으로 만들지 않고 인스턴스 구성을 사전 처리합니다.

사용 예

우선 소위 "mixins"(오른쪽 이름 지정에 대한 것임)이라는 레코드를 원하는 방식으로 내 보낸 모듈의 값을 수정할 수 있도록 레코드를 똑바로 설정하고 싶습니다. 나는 이것이 더 일반적인 메커니즘이라고 말하고 싶다.

다음은 모듈에서 내보내는 함수에 추가 기능을 추가하는 간단한 샘플입니다.

// 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에서 구성 데이터를 수정할 수있는 콜백을 반환합니까? 또는 다른 것?
Alan Storm

그렇습니다! 구성 데이터를 수정할 수있는 콜백을 반환해야합니다.
Denis Rul

이 두 가지 질문에 대한 통찰력은 프론트 엔드를 둘러싼 길을 잘 아는 것 같습니다. magento.stackexchange.com/questions/147899/… magento.stackexchange.com/questions/147880/…
Alan Storm

4

Denis Rul의 답변 을 마무리합니다 .

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종속성으로 플러그인하고 재정의 세계 require, define그리고 requirejs기능을. 이 재정의는 "실제로 믹스 인이 아닌"시스템이 일반 기능으로 다시 전달하기 전에 RequireJS 모듈의 초기 인스턴스화에 연결될 수있게합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.