Best practices for incorporating and leveraging node packages with Laravel Mix

As I embark on my Laravel (v 8.x) Mix project, I am encountering challenges when it comes to incorporating JavaScript from node modules.

To kick things off, here is a snippet from my webpack.mix.js:

mix.js('node_modules/mxgraph/javascript/mxClient.min.js', 'public/js');
mix.js('resources/js/*.js', 'public/js').postCss('resources/css/app.css', 'public/css', [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer'),
]).version();

Then, within my app.js, I have the following setup:

import Canvas from './canvas';

require('mxgraph');

const canvas = new Canvas();

This script also imports canvas.js:

export default class Canvas {
    constructor() {
        this.container = document.getElementById('graphContainer');
        if (!mxClient.isBrowserSupported())
        {
            // Displays an error message if the browser is not supported.
            alert('Browser is not supported!');
        }
.
.
.
    }
}

Furthermore, in the Scripts section of my Blade layout:

<script src="{{ mix('js/mxClient.min.js') }}" defer></script>
<script src="{{ mix('js/app.js') }}" defer></script>

Upon loading the page, the console throws the following error:

Uncaught ReferenceError: mxClient is not defined
    at new Canvas (app.js:3866)
    at Module../resources/js/app.js (app.js:3813)
    at __webpack_require__ (app.js:114081)
    at app.js:114143
    at app.js:114149

The variable mxClient is indeed present in mxClient.min.js, and the reference in Canvas comes after its loading.

I've experimented with different approaches without success. Any insights or suggestions would be highly appreciated.

Answer №1

After much exploration and experimentation, I finally stumbled upon a solution that does the trick. It was inspired by my findings here:

Although my approach may seem a bit cumbersome, it gets the job done, allowing me to proceed with my mxGraph development project.

As a result, I have removed the explicit inclusion of mxgraph in webpack.mix.js, reverting back to the Laravel default setup:

mix.js('resources/js/*.js', 'public/js').postCss('resources/css/app.css', 'public/css', [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer'),
]).version();

I have also eliminated require('mxgraph'); from app.js, resulting in the following streamlined code:

import Canvas from './canvas';

const canvas = new Canvas();

My revised canvas.js now looks like this:

import mx from 'mxgraph';

const mxgraph = mx({
    mxImageBasePath: './src/images',
    mxBasePath: './src'
});

window.mxGraph = mxgraph.mxGraph;
window.mxGraphModel = mxgraph.mxGraphModel;
window.mxEvent = mxgraph.mxEvent;
window.mxEditor = mxgraph.mxEditor;
window.mxGeometry = mxgraph.mxGeometry;
window.mxRubberband = mxgraph.mxRubberband;
window.mxDefaultKeyHandler = mxgraph.mxDefaultKeyHandler;
window.mxDefaultPopupMenu = mxgraph.mxDefaultPopupMenu;
window.mxStylesheet = mxgraph.mxStylesheet;
window.mxDefaultToolbar = mxgraph.mxDefaultToolbar;

const {mxGraph, mxClient, mxEvent, mxCodec, mxUtils, mxConstants, mxPerimeter, mxRubberband} = mxgraph;

export default class Canvas {
    constructor() {
        let container = document.getElementById('graphContainer');
        if (typeof(mxClient) !== 'undefined') {
            this.draw(container);
        }
    }

    draw (container) {
        if (! mxClient.isBrowserSupported())
        {
            // Display error message for unsupported browser
            mxUtils.error('Browser is not supported!', 200, false);
        }
        else
        {
            // Disable context menu
            mxEvent.disableContextMenu(container);

            // Create graph inside container
            var graph = new mxGraph(container);

            // Enable rubberband selection
            new mxRubberband(graph);

            // Get default parent for inserting cells
            var parent = graph.getDefaultParent();

            // Add cells to model in a single step
            graph.getModel().beginUpdate();
            try
            {
                var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
                var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
                var e1 = graph.insertEdge(parent, null, '', v1, v2);
              
            }
            finally
            {
                // Update display
                graph.getModel().endUpdate();
            }
        }
    }
}

The majority of the code within the draw() method is adapted from an mxGraph "Hello World" demo ().

A big thank you to @codedge for your invaluable assistance!

Answer №2

After some experimenting, I discovered a solution.

Combine files into one

Merge mxClient.min.js and app.js into a single file using the following code:

mix.js(
    [
        "resources/js/app.js",
        "node_modules/mxgraph/javascript/mxClient.min.js",
    ],
    "public/js"
).postCss('resources/css/app.css', 'public/css', [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer'),
]).version();

Import mxGraph and Canvas

Add this to your app.js:

import "./canvas";

require("mxgraph");

const canvas = new Canvas();

Now run npm run dev without any problems.

Update

I came across an alternative option which might be simpler. Remove mxClient from your webpack.mix.js, only include your app.js.

// app.js

window.mxClient = new require("mxgraph")().mxClient;

let isBrowserSupported = mxClient.isBrowserSupported();

console.log(isBrowserSupported);

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

Searching through a JSON object on a Laravel web page using JavaScript or AJAX for live filtering purposes

After diving into AJAX and JavaScript, I find myself needing to replace some outdated Angular functionality on our Laravel site. The specific task at hand is creating a live search filter for a page with a static header search bar. The main requirement is ...

Issues with npm, node-gyp, and gulp encountered while using MAC OS X Yosemite version 10.10.5

Struggling to install npm, node-gyp, and gulp on my MAC for a Laravel project. Despite researching extensively online, I haven't found a solution that works for me yet, indicating potential issues with the paths. I have attempted: Installing node/n ...

Show the response obtained after making a POST request

In my current project, I am utilizing vanilla JavaScript to send a POST request to my Flask App. I have implemented a validation feature that checks for duplicate usernames when a user is signing up. If the username already exists, a 406 status response is ...

Utilizing AJAX to dynamically update a div's content by extracting a specific div from the retrieved data

Although I believe my code is correct, I am not very familiar with AJAX and have been struggling for hours to get it right. I've tried various approaches, including using filters, but nothing seems to work. The issue I'm facing is that the chat m ...

Adjust the color of an SVG icon depending on its 'liked' status

In my React/TypeScript app, I have implemented an Upvote component that allows users to upvote a post or remove their upvote. The icon used for the upvote is sourced from the Grommet-Icons section of the react-icons package. When a user clicks on the icon ...

Tips for asynchronously updating a model in TypeScript

I have been working on a function to hide the element for connecting to Facebook upon successful connection. I have implemented two functions, success and error, which trigger after Firebase successfully logs in the user. While I can confirm that these fun ...

What could be causing my surroundings to deteriorate? Encountering a yarn installation issue related to sha

The Challenge I'm facing an issue while attempting to replicate this particular project: https://github.com/Bounties-Network/Explorer. Upon running yarn install, everything seems to fall apart. I suspect that it could be linked to gyp, but I lack th ...

Can I restrict access to all routes except one in vue-router? Is this a safe practice? Should I explore alternative methods for achieving this?

I am looking to create an online exam consisting of 5 pages, each with a countdown timer set at 120 seconds and 4 questions on each page. Once the timer runs out, users will be automatically redirected to the next page, or they can manually click the "next ...

Is it acceptable to include the bundled main.js file in the gitignore for a HUGO project?

Is it possible to exclude the bundled main.js file from a HUGO project by adding it to .gitignore? ...

Display various child components in a React application depending on the current state

I'm currently developing a brief React quiz where each question is represented as an independent component. I aim to swap out the current question component with the next one once a question is answered. Here's the present state of my root compon ...

What causes a ReferenceError when attempting to retrieve the class name of a React component?

Take a look at my React component located in index.js: import React from 'react' import ReactDOM from 'react-dom' class App extends React.Component { render() { return ( <div className="App"> <h1>Hello, ...

Retrieve mongodb objects that fall within a specified date range

Within my collection, there is an example document structured as follows: { "_id" : ObjectId("5bbb299f06229dddbaab553b"), "phone" : "+38 (031) 231-23-21", "date_call" : "2018-10-08", "adress_delivery" : "1", "quantity_concrete" : "1", ...

Firefox won't trigger the `beforeunload` event unless I interact with the webpage by clicking on it

In my quest to handle the beforeunload event in Firefox, I've encountered a small hurdle. It seems to be working smoothly, but only if the user physically interacts with the page by clicking on it or entering text into an input field. Below is the co ...

Combining two kebab-case CSS classes within a React component

import React from 'react'; import styles from './stylesheet.moudle.css' <div className={styles['first-style']} {styles['second-style']}> some content </div> What is the correct way to include styles[&ap ...

Filtering out specific properties in an array using Angular

I am facing an issue with my Angular filter when inputting text for a specific list. initialViewModel.users = [ {user: 'Nithin',phone: 'Azus', price: 13000}, {user: 'Saritha',phone: 'MotoG1',price: 12000}, {user: ...

Attempting to transmit JavaScript information to my NodeJS server

Having some trouble sending geolocation data to NodeJS through a POST request. When I check the console log in my NodeJS code, it's just showing an empty object. I've already tested it with postman and had no issues receiving the data. The probl ...

What steps should I follow to set JSONP as the dataType for a request in an Angular $http service?

I have a good understanding of how to use jQuery's $.ajax: $.ajax({ url: //twitter endpoint, method:"GET", dataType:"jsonp", success:function() { //stuff } }); Is there a way to set the JSONP datatype for an angular $http service reque ...

Utilize an image in place of text (script type="text/javascript")

The vendor has provided me with some code: <a class="sh_lead_button" href="https://107617.17hats.com/p#/lcf/sfrnrskrvhcncwvnrtwwvhxvzkrvzhsd" onclick="shLeadFormPopup.openForm(event)">FREE Puppies</a> <script type="text/javascript" src="htt ...

Saving information to a hidden div using jStorage

Currently, I am utilizing jStorage for storing data in local storage. When I store the data using console.log() and later retrieve it using $.jStorage.get(), I found that the values are not being assigned to the hidden div. Can someone provide guidance o ...

The file link in Laravel on localhost at http://127.0.0.1:8000 is not functioning properly

Currently, I am utilizing php artisan serve to host on my local machine at . Despite successfully uploading files to the storage folder, when I attempt to create links like: public function getFeaturedImageLinkAttribute() { $file = $this- ...