Incorporating node_modules into Laravel using MixTechniques

I'm facing challenges while trying to incorporate OpenLayers (v5.3.0) into a Laravel 5.7 project, particularly with importing ol from node_modules.

Following the instructions on https://www.npmjs.com/package/ol, I installed ol using the command:

npm install ol

Next, I made modifications to my resources\js\app.js file, which now looks like this:

require('./bootstrap');
require('ol');

UPDATE: I also attempted the following in resources\js\app.js, but without success:

require('./bootstrap');
const ol = require('ol');

The webpack.mix.js file includes the following configuration:

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js/app.js')
   .sass('resources/sass/app.scss', 'public/css');

In addition, I have included relevant lines of code in map.blade.php for displaying the OpenLayers map as intended:

<script src="{!! mix('js/app.js') !!}"></script>
...
<div id='map' style='z-index: 1; width: 100%; height:calc(100% - 56px);'>
    <script>
        import Map from 'ol/Map';
        import View from 'ol/View';
        import TileLayer from 'ol/layer/Tile';
        import XYZ from 'ol/source/XYZ';

        new Map({
            target: 'map',
            layers: [
                new TileLayer({
                    source: new XYZ({
                        url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'
                    })
                })
            ],
            view: new View({
                center: [0, 0],
                zoom: 2
            })
        });
    </script>
</div>

I have executed the npm run dev command.

However, when testing in Chrome, an error "Uncaught SyntaxError: Unexpected identifier" is triggered, pointing to the line in map.blade.php:

import Map from 'ol/Map';

UPDATE: I also tried installing all dependencies by running the command:

npm install --save-dev parcel-bundler

No errors were encountered during the installation process, but the same Chrome error persists.

UPDATE: To address the issue, I attempted moving the JavaScript code out of map.blade.php into a new file (mapscript.js), and then importing it in map.blade.php as follows:

<script src="{!! asset('js/mapscript.js') !!}" type="module"></script>

Nevertheless, a new error emerged:

Uncaught TypeError: Failed to resolve module specifier "ol/Map". Relative references must start with either "/", "./", or "../".

Following that, I experimented with transferring certain lines of code from app.js to mapscript.js, both with the require('ol'); and const ol = require('ol'); statements, but the error continues to persist.

Despite exploring numerous potential solutions on platforms such as Stack Overflow, and considering alternatives like utilizing ol outside of npm, I am still unable to resolve this issue. While I acknowledge that incorporating OpenLayers through npm and Mix is the preferred method, I am currently stuck trying to identify the cause of this problem. Any assistance provided would be greatly appreciated.

Answer №1

After experimenting and refining my approach, I managed to integrate OpenLayers 6.1 with Laravel 6.2 using Mix, Webpack, and ES6 module imports. The key is to organize all your JavaScript code into a separate file and bundle it into app.js.

To add OpenLayers to your Laravel project, simply run npm:

npm install ol

Create a new file in your Laravel project at resources/js/myMap.js (next to bootstrap.js and app.js) and input your OpenLayers JavaScript code there.

Here's a condensed example from the official documentation at

import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const map = new Map({
    target: 'osm_map',
    layers: [
        new TileLayer({
            source: new OSM()
        })
    ],
    view: new View({
        center: [0, 0],
        zoom: 0
    })
});

In order to make this accessible to other parts of the code, we must export it as a literal object. Add the following lines to accomplish this:

import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

var my_map = {                       
    display: function () {           

        const map = new Map({
            target: 'osm_map',
            layers: [
                new TileLayer({
                    source: new OSM()
                })
            ],
            view: new View({
                center: [0, 0],
                zoom: 0
            })
        });

    }                                
};                                   
export default my_map;               

Add these two lines to the end of bootstrap.js to incorporate our code and attach the object my_map to the global window object for easy reference on the page.

import my_map from './myMap.js';
window.my_map = my_map;

Bundle everything together by running npm run dev. It's important to note that the default webpack and mix settings of Laravel are used - no manual editing of webpack.mix.js is required. npm run dev copies the content from myMap.js into app.js. Remember to do this after any changes to myMap.js, or automate the process with npm run watch.

To showcase the map in a blade template, ensure you have a div id matching the OpenLayers Map target, such as osm_map in our example above. Below is a basic blade template:

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <style>
        #osm_map {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>

<div id="app">
    <div id="osm_map"></div>
</div>

<script src="{{ asset('js/app.js') }}" ></script>

<script type="text/javascript">
    window.my_map.display();
</script>

</body>
</html>

Note:

  1. The div id="osm_map" corresponds to the openlayers target.
  2. The OpenLayers CSS is included and styled here.
  3. The map displays when calling the my_map.display() method.

With these steps, you can smoothly embed an interactive OpenLayers map within a Laravel blade template.

Answer №2

How to set up the ol package :

npm install ol

Create a file named map.js inside the resources directory in js folder(where bootstrap.js and app.js exists)

resources/js/map.js

Add your Openlayer code in map.js(such as example code provided below):

import 'ol/ol.css';
import {Map,View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const map = new Map({
target: 'map',
layers: [
    new TileLayer({
        source: new OSM()
    })
],
view: new View({
    center: [0, 0],
    zoom: 0
             })
});

Next, locate the webpack.mix.js, generally found at the end.

Append

.js('resources/js/map.js', 'public/js')
at the end of the file

Your webpack.mix.js should resemble the following:

const mix = require('laravel-mix');
/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.js('resources/js/map.js', 'public/js');

Now, run npm run dev in the terminal

Your *.blade.php code should be similar to this example code:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>Using Webpack with OpenLayers</title>
    <style>
        #map {
            height: 100%;
            width: 100%;
            left: 0;
            top: 0;
            overflow: hidden;
            position: fixed;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script type="text/javascript" src="{{ asset('/js/map.js') }}"></script>
</body>
</html>

Importing node modules directly from the public folder is not allowed. Modules must be imported within the project and utilized using webpack in the public folder.

For production: Run npm run production in the terminal

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

Generating a new object using an existing one in Typescript

I received a service response containing the following object: let contentArray = { "errorMessages":[ ], "output":[ { "id":1, "excecuteDate":"2022-02-04T13:34:20" ...

How can I obtain the true client IP address using Nginx?

I have a straightforward express app that has been containerized using Docker. You can find the repository here. In this setup, I utilized nginx as a reverse proxy. When accessing http://45.33.97.232:3000, it displays the actual server IP. However, if I v ...

The CSS hamburger menu halves in size when being closed

I have successfully created a CSS/JS hamburger menu with a transforming icon upon clicking. However, I encountered a bug where, upon clicking the 'close' button on the hamburger, the navigation menu cuts behind the header, resulting in a messy ap ...

Importing a JS class within a Vue.js script tag

I'm attempting to incorporate a JS file into the Vuejs script but for some reason, it's not working as expected. JS file class Errors { constructor() { this.errors = {}; } get(field) { if (_.has(this.errors, 'errors.' + ...

Issue with background overlapping

I am currently creating a questionnaire that consists of 10 questions and calculates a score called total. If the total < 10, I want the screen to turn red. However, this required me to remove the previous wallpaper that was set: /*body{ backgr ...

What is the best way to extend a class in NestJS from another class?

I've encountered an issue while attempting to extend a class service from another class service in NestJS and utilize DI to load it in a third service. The error message I'm receiving from Nest is: Error: Nest can't resolve dependencies of ...

Having to reinstall node modules is a repetitive task that must be done after each build of an Angular

Formulating this question has been quite challenging for me. I really hope it is clear. Despite my extensive searches, both on this platform and beyond, I have not been able to find any reference to the behavior I am experiencing. For the past few ...

Verifying if every item in an array exists within multiple arrays

I am struggling to find a solution to this problem. Imagine there are 6 sets of colors with varying amounts of colors in each, and colors may be repeated: ['white', 'blue'] ['green', 'yellow'] ['black'] [ ...

What could be causing the promises in Promise.all to remain in a pending state?

After restructuring my code to correctly utilize promises, I encountered a challenge with ensuring that the lastStep function can access both the HTML and URL of each page. To overcome this issue, I'm attempting to return an object in nextStep(). Alt ...

When attempting to perform $save() on $resource, a TypeError is thrown indicating that Object #<g> does not contain the method 'push'

Resource factory: .factory('WorkerRepository', function($resource){ return $resource('workers/:id', {id:'@id'}); }) Controller: .controller('ListController', function($scope, WorkerRepository){ var workers ...

Determine the width of invisible images using JavaScript/jQuery

Please take a look at the jsFiddle Every time I run it, I am trying to retrieve the width of the images, but the values I get are as follows (check in the JS console) 400 0 575 533 0 ... Some values are zero, and I can't figure out why. It seem ...

Switching between javascript objects within the redux store and the application

I am working with a set of JavaScript objects that are retrieved from an external API library. My goal is to save these objects in my React application using Redux. These objects are ES2015 classes that include two useful methods called fromJSON and toJSO ...

Displaying Keystonejs list items on every page

Is there a more effective method to efficiently load the content of a Keystone's list on every page, rather than calling it individually in each view? Could this be achieved through middleware.js? The objective is to create a dropdown for the navigat ...

Concealing a vessel, refreshing the innerHTML content, and then revealing it once more

Is it possible to conceal a container, modify the innerHTML of said container, and then reveal the container again? It appears that accomplishing both actions simultaneously is proving to be tricky... For a visual example, check out this JSFiddle - https: ...

Pass a jQuery variable to the current file and retrieve it using PHP

Is there a way to send jQuery data and receive it on the same file without including it in the URL as a variable (e.g. test.php?data=xxx)? For instance, here is the response.data that can be seen in the console log: function (response) { ...

Avoiding HTML in JavaScript: Tips and Tricks

My application generates numerous elements dynamically based on server data in JSON format. This process involves embedding a significant amount of HTML directly within my JavaScript code, leading to pollution and making it increasingly challenging and l ...

Only the test cases that passed were documented in Mochaweasome

Currently, I am utilizing the mochawesome report to document my cypress execution. The test case is displaying a simple pass without providing details about the steps taken or the assertions made in the report. Sample snapshot (Apologies for the excessive ...

Performing a MongoDB aggregate operation to swap out a set of IDs with their corresponding objects from an array located within the same document

In my collection, I have a variety of documents that look like this: [{ id: 1, name: 'My document 1', allItems: [{ id: 'item1', name: 'My item 1' }, { id: 'item2', name ...

Switch up the gradient background when hovering over MorphSVG

I am interested in creating a morph animation using the MorphSVG library. Two gradients have been defined: <linearGradient id="lgrad" x1="0%" y1="100%" x2="100%" y2="0%" > <stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" /> ...

Leveraging the power of JavaScript templates within ASP.NET

Throughout my career, I have encountered a recurring issue that has yet to be resolved with an elegant solution. Picture this: You have a basic page with a repeater that is populated on the server side through data binding. Everything works smoothly and ef ...