Switching from the global import module pattern to ES6 modules

In recent years, my approach to JavaScript development has involved using the global import method. Typically, I work with a set of utility functions packaged and passed to a separate site module containing individual functions for each web functionality:

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

    // Sample Module
    m.example = function(){
        // Perform actions, the m.example module is automatically initialized.
};

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

In this scenario, I pass on various modules that we extend, utilities, user interface object (often aliased gsap), and other dependencies like jQuery.

However, as these projects grow in size, the process can become cumbersome and messy.

I am now considering transitioning to ES6 and using NPM. While there are numerous resources available on creating and importing modules, as well as utilizing NPM, I have yet to find detailed guidance on bringing everything together.

For instance, if I import slick-carousel via NPM and want to incorporate two distinct carousels on a single-page website - a banner carousel and a tweet carousel - how should I verify the existence of these elements and initialize the carousels separately?

In the past, using an anonymous closure, I would create auto-initialized functions individually looking up DOM elements and initializing carousels with unique options.

Edit

To illustrate my current workflow, I establish a site object with reusable static variables and shared items across the project such as animation variables, window references, and auto-updating variables for viewport properties access.

Subsequently, within a dedicated file specific to each developed website, I define the main structure where distinct 'modules' are created for each functional aspect implemented on the site. This involves employing jQuery alongside plain JavaScript plugins embedded on the page, along with utility and primary JS files.

utils.js

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


var Site = (function($) {

    // DOM caching
    var win = window;

    // Global items
    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(){
        ... logic to check cookies for a marker and display cookie notice if not present.
    }

    ... handling additional website functionalities like maps, menus, custom elements, etc.

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

Answer №1

Avoid relying on the "everything is global" mindset. The global scope in JavaScript is considered a major design flaw. For example:

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

While the global scope has its uses, they are limited. It's best to view it as the state of webpages or servers. Ideally, the global scope should not contain any code (functions). Exposing too much functionality to the global scope can lead to conflicts between scripts, resulting in difficult-to-troubleshoot bugs. Instead, your code should be self-contained and minimize its impact on the global scope. When sharing functionality between different files (e.g., menu.js and slider.js, both requiring a Button class), that functionality should be placed in a module that is then imported by both scripts. Each file should handle imports at the top and exports at the end, encapsulating itself:

import {functionality1, functionality2} from "module";

let somevariable; // Variables declared with let or const do not pollute the global scope, even though they are "global"

Do not hesitate to import the same module multiple times in different files on the same page. Modules are only loaded once, and through tree shaking (a feature in most bundlers like Webpack), only necessary chunks of a large module may be included instead of loading the entire module.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to transfer information from an axios API to a state in React

I am currently working with an API that consists of an array of objects. My goal is to pass this data into a state in order to display it within a component on a website. First Approach: // Fetches the API data const newData = axios.get(url).then( ...

Storing data with ElectronJS

I am currently working on an Electron JS and React JS offline application. One of the initial steps in my launch process involves loading a large file that is over 1 GB in size and cannot be divided. This causes a delay of approximately 50-60 seconds whi ...

React App anchor tag's external links fail to function properly on subsequent clicks when accessed through mobile devices

I have encountered an unusual issue with <a> anchors for external links in my React App on mobile viewports. Initially, clicking an external link opens a new tab just fine on mobile. However, subsequent link clicks on the same or other <a> elem ...

Embed a subcomponent within another component triggered by an onClick event in ReactJS

Watch this quick demo to see my project in action. So, here's the deal - I have a menu with different options, and when "Tickers" is selected, I want it to display the Tabs component. However, if any other menu option is chosen, I don't want the ...

What is the reason that Object.keys(window) or for(k in window) does not include the Math object?

As I work on creating a JavaScript editor autocomplete feature, my goal is to showcase all available top-level elements. So far, I've experimented with: Object.keys(window) as well as for (k in window) However, it seems like neither method include ...

The development mode of NextJS is experiencing issues, however, the build and start commands are functioning normally

Just finished creating a brand new Next app (version: 12.0.7) using Typescript and Storybook. Everything seems to be working fine - I can successfully build and start the server. However, when I try to run dev mode and make a request, I encounter the follo ...

Encountering a mess-up while running the npm update -g command

After attempting to update npm, chaos ensued: Environment check ✔ $HOME ✔ Yo ✔ Compass ✔ Ruby ✔ Git ✔ Node.js ✔ npm dist: $ npm update -g npm http GET https://registry.npmjs.org/envcheck npm http GET https://registry.npmjs.org/bower npm http ...

Guide to encapsulating a container within a map function using a condition in JSX and TypeScript

Currently, I am working with an array of objects that are being processed by a .map() function. Within this process, I have a specific condition in mind - if the index of the object is greater than 1, it should be enclosed within a div element with a parti ...

What could be the reason for the discrepancy between the values displayed in the two alerts? What is causing this difference in

Check out this JavaScript code snippet: var x = 3; var foo = { x: 2, baz: { x: 1, bar: function() { return this.x; } } } var go = foo.baz.bar; alert(go()); alert(foo.baz.bar()); When you run the two alert functions here, you&ap ...

An issue arose during the page prerendering process for "/" on Vercel | Next.js resulting in a deployment error

When attempting to deploy my website using Vercel and generating static pages, I encountered the following error in the logs: info - Generating static pages (0/6) Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/ ...

What is the process for turning off deep imports in Tslint or tsconfig?

Is there a way to prevent deep imports in tsconfig? I am looking to limit imports beyond the library path: import { * } from '@geo/map-lib'; Despite my attempts, imports like @geo/map-lib/src/... are still allowed. { "extends": &q ...

The action of POSTing to the api/signup endpoint is

Currently delving into the MEAN stack, I have successfully created a signup api. However, when testing it using POSTMAN, I encountered an unexpected error stating that it cannot POST to api/signup. Here is a snapshot of the error: Error Screenshot This ...

I am having trouble with Fullcalendar not loading my JSON data to display events

I've been experimenting with the fullcalendar JavaScript library, but I'm struggling to load data from my MySQL database onto the calendar. When I test my db-connect.php file, it does return the first entry in the table, yet the calendar remains ...

Can an action be activated when the mouse comes to a halt?

Currently, I am having trouble triggering an event when a user stops moving their mouse over a div element. The current event is set up to show and follow another element along with the mouse movement, but I want it to only display when the mouse stops mov ...

What is the best way to use an object as a key to filter an array of objects in JavaScript?

My data consists of an array of objects: let allData = [ {title:"Adams",age:24,gender:"male"}, {title:"Baker",age:24,gender:"female"}, {title:"Clark",age:23,gender:"male"}, {title:"Da ...

What is the best way to retrieve a nested element from a JSON object using AngularJS?

Take a look at this Plunkr demonstration that showcases the ng-repeat functionality with a JSON file: Plunkr The code snippet below shows how I am displaying elements from $scope.foodlist: <li ng-repeat="food in foodlist"> ...

Attempting to retrieve the value from a nested table within a table row using Jquery

<tr role="row" class="odd"> <td style="background-color:white"> <table> <tbody> <tr data-row-id="22"> <td id="pid"><input type="checkbox" class="sub_chk" value="8843" data-id="22">< ...

Visualize data retrieved from a third-party website through scraping in a chart

After attempting to extract data from a website's data.asp file (formatted in json) and display it as a chart on my site using Google Chart API or FusionCharts, I'm facing issues. Although I can retrieve the json data, it doesn't render as a ...

Avoid triggering the resizecolumn event in ExtJS while the columns are still loading

Currently, I am involved in a project using ExtJS 6.2 and facing a challenge related to performing operations when the columns in a grid are resized. It seems like the suitable event for this task is columnresize. However, the issue arises because the colu ...

Tips for incorporating dynamic parameters/variables into templates displayed using ng-bind-html or a custom directive (within ng-repeat)

EDIT: I have created a solution sample based on the initial answer. However, I am open to further suggestions and would appreciate any help in filling the gaps in my knowledge (please refer to the comments). plnkr.co/edit/mqGCaBHptlbafR0Ue17j?p=preview OR ...