Преобразование глобального шаблона модуля импорта в модули ES6

Последние несколько лет я работаю с методом глобального импорта JavaScript. Обычно работает с набором служебных функций, упакованных и переданных в другой модуль сайта, который содержит отдельную функцию для каждой части веб-функции:

(function(m, u, ui, w, a, $){

    // Example Module
    m.example = function(){
        // Do stuff, the m.example module gets auto initialized.
};

})(Site.modules = Site.modules || {}, Site.utils, Site.ui, Site.w, Site.anim, jQuery);

В этом примере я передаю модули, которые мы добавляем, утилиты, объект пользовательского интерфейса (в основном с псевдонимом gsap) и другие вещи, такие как jQuery.

Как видите, он может стать большим и беспорядочным, особенно на больших сайтах с большим количеством функций.

Я хотел бы перейти на ES6 и NPM, и хотя я видел десятки статей и примеров о том, как сделать модуль, как импортировать модуль, добавить модули с помощью NPM, я не могу найти ни одного примера или статьи о на самом деле собирая все это вместе.

Для простого примера. Я импортирую slick-carousel с помощью NPM. У меня есть одностраничный веб-сайт с каруселью баннеров и каруселью твитов. Как мне проверить существование этих элементов и инициализировать 2 отдельные карусели?

Используя анонимное закрытие, я бы просто имел отдельную автоматически инициируемую функцию, которая ищет элемент DOM, а затем инициализирует карусель с различными параметрами.

Изменить

В качестве примера моего текущего рабочего процесса я определяю объект сайта, который имеет несколько повторно используемых статических переменных и некоторые элементы, повторно используемые на сайте, такие как переменные анимации, ссылка на окно, переменные автоматического обновления для доступа к свойствам области просмотра и т. д.

Затем в отдельном файле, уникальном для каждого созданного веб-сайта, у меня есть основной файл, в котором я создаю отдельные «модули» для каждой части реализованной функциональности на сайте. Использование плагинов jQuery и простого JavaScript, включенных на страницу вместе с утилитами и основными файлами js.

utils.js

jQuery(document).ready(function($) {
    Site.init();
});


var Site = (function($) {

    // DOM caching
    var win = window;

    // Globals
    var w = {
        width:  win.innerWidth,
        height: win.innerHeight,
        scroll: win.pageYOffset
    };

    var ui = {
        fast: 0.2,
        slow: 0.4,
        step: 0.03,
        easeout: Power4.easeOut,
        easein: Power4.easeIn
    };

    function updateGlobals(){
        w.width  = win.innerWidth;
        w.height = win.innerHeight;
        w.scroll = win.pageYOffset;
    }

    win.addEventListener('resize', updateGlobals, true);
    win.addEventListener('scroll', updateGlobals, true);
    win.addEventListener('load', updateGlobals, true);

    return {
        init: function(){

            for (var prop in this.modules) {
                if ( this.modules.hasOwnProperty(prop) ) {
                    this.modules[prop]();
                }
            }

            for (var props in this.autoInits) {
                if ( this.autoInits.hasOwnProperty(props) ) {
                    var $selector = $(props);

                    if ($selector.length) {
                        this.autoInits[props]($selector);
                    }
                }
            }
        },
        ui: ui,
        w: w
    };

})(jQuery);

main.js

(function(m, $){

    m.homepageCarousel = function(){
        var element = $('.js-homepage-carouel');
        
        $(element).slick({
            dots: true,
            speed: 500,
            arrows: false
        });
    };

    m.productsCarousel = function(){
        var element = $('.js-products-carouel');
        
        $(element).slick({
            dots: false,
            speed: 500,
            arrows: true
        });
    };

    m.showcookieNotice = function(){
        ... example check cookies for marker and show cookie notice if not present.
    }

    ... rest of the websites js, maps, menus, custom reused items etc

})(Site.modules = Site.modules || {}, jQuery);

person Chris Morris    schedule 29.11.2017    source источник


Ответы (1)


Не думайте, что все глобально. Глобальная область действия — одна из самых больших ошибок дизайна js. Например.:

    var name = 1;
    console.log(name + 1); // 2, right? No, try it ...

Я не думаю, что глобальная область видимости совершенно бесполезна, но возможности ее использования очень ограничены. Вы должны думать об этом как о состоянии веб-страниц / серверов. Это означает, что в лучшем случае он не должен содержать кода (= функций). Чем больше функций (кода) вы предоставляете глобальной области видимости, тем больше вероятность того, что у вас будет плохой вывод между двумя сценариями, и эти ошибки действительно трудно обнаружить. Вместо этого ваш код должен инкапсулировать себя. Он должен выставлять и изменять как можно меньше в глобальной области видимости. Это означает, что если вы хотите разделить определенную функциональность между двумя разными файлами вашей страницы (например, menu.js и slider.js, для обоих требуется Кнопка class), то эта функциональность должна быть включена в модуль, который затем импортируется обоими сценариями. Таким образом, каждый отдельный файл должен иметь импорт вверху и экспорт в конце и должен инкапсулировать себя:

import {functionality1, functionality2} from "module";

let somevariable; // variables declared with let or const do not appear on the global scope, although they are "global"

Не бойтесь импортировать один и тот же модуль несколько раз в разные файлы на одной странице. Модули загружаются только один раз, и при встряхивании дерева (что делают большинство сборщиков, таких как Webpack), простое включение нескольких функций из большого модуля может даже не загрузить весь большой модуль, а только несколько его фрагментов.

person Jonas Wilms    schedule 29.11.2017
comment
Чтобы уточнить, что «движок JS оптимизирует его»: когда вы импортируете модуль в первый раз, код внутри этого модуля запускается, а экспорт кэшируется. Последующие импорты из того же модуля используют эти кэшированные объекты вместо повторного запуска кода. Это относится как к модулям ES2015, так и к модулям CommonJS, поддерживаемым Node.js. - person Joe Clay; 29.11.2017
comment
Итак, вы бы сказали, что сохранение моего текущего метода (или чего-то подобного с одним уровнем инкапсуляции автозагрузки), но повторный импорт моих функций был бы лучшим методом? Я предположил, что, учитывая акцент на разделении кода, будет некоторый толчок к разделению каждой части функциональности, скажем, на отдельный файл или что-то в этом роде. - person Chris Morris; 29.11.2017
comment
@chris нет, ваши IIFE импортируют и экспортируют код (!) в глобальную область и из нее. Плохо. Одна группа функций (например, Элементы) должна быть одним файлом/модулем. Перенос каждой отдельной функции в другой файл не сделает его более читабельным, так что это контрпродуктивно. - person Jonas Wilms; 29.11.2017
comment
@ДжонасВ. Я понимаю, что отдельные фрагменты функциональности должны быть разделены на модули. На самом деле моя проблема заключается только в реализации этих модулей для статической веб-страницы. Лучшая структура корневого файла JS - person Chris Morris; 29.11.2017
comment
@chris нет корня. Вот структура. - person Jonas Wilms; 29.11.2017
comment
@ДжонасВ. У вас есть пример того, что вы имеете в виду? Это моя главная проблема, я еще не нашел ни одного фактического примера, который не был бы просто фрагментом кода, превозносящим величие ES6 и модулей. - person Chris Morris; 29.11.2017
comment
@chris, не могли бы вы дать код, который я могу украсить для вас? - person Jonas Wilms; 29.11.2017
comment
@ДжонасВ. Спасибо, я обновил свой вопрос примером моего текущего рабочего процесса и урезанным примером моих утилит и основных файлов js, которые запускают все. - person Chris Morris; 29.11.2017