I'm trying to use OpenLayers (v5.3.0) in a Laravel 5.7 project, but am having a lot of trouble importing ol from node_modules.
I installed ol as follows (based on https://www.npmjs.com/package/ol):
npm install ol
I then updated my resources\js\app.js, which now contains only the following:
require('./bootstrap');
require('ol');
EDIT: I've also tried the following in resources\js\app.js, without success:
require('./bootstrap');
const ol = require('ol');
My webpack.mix.js contains the following:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js/app.js', )
.sass('resources/sass/app.scss', 'public/css');
I also have the following relevant lines in a file called map.blade.php, which is where I want to display the OpenLayers map:
<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 also run npm run dev
.
When testing in Chrome, I get "Uncaught SyntaxError: Unexpected identifier" referring to the following line in map.blade.php:
import Map from 'ol/Map';
EDIT: I've also run the following to make sure all dependencies are installed:
npm install --save-dev parcel-bundler
I didn't get any errors when running the above, but the same error in Chrome is still there.
EDIT: I've also tried shifting the javascript out of my map.blade.php into a new file (mapscript.js), and then importing that in map.blade.php (after the 'map' div) as follows:
<script src="{!! asset('js/mapscript.js') !!}" type="module"></script>
But then I get the following error instead:
Uncaught TypeError: Failed to resolve module specifier "ol/Map". Relative references must start with either "/", "./", or "../".
Following that, I tried moving the following line out of app.js and into mapscript.js:
require('ol');
And also tried the same with:
const ol = require('ol');
But the same Uncaught TypeError persists in both cases.
I've tried the solutions given to a lot of similar questions in Stack Overflow and elsewhere, and I've also tried using ol outside of npm, but I haven't found anything that resolves the issue for me. I believe using npm and Mix is the best way to build OpenLayers into my project, but I can't work out why it's not working. Would really appreciate some help.
After some trial and error I have OpenLayers 6.1 working with Laravel 6.2 using Mix, Webpack, and ES6 module imports. The trick is to write all your javascript in a separate file and bundle it up into app.js.
Install openlayers into your Laravel project using npm:
npm install ol
Create a new file in your Laravel project at resources/js/myMap.js
(alongside bootstrap.js
and app.js
) and put your OpenLayers javascript code into it.
Lets use a short code example copied from the official docs at https://openlayers.org/en/latest/doc/tutorials/bundle.html
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
})
});
We need to export this as a literal object to make it available to other code, so insert the five extra lines as shown below.
import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
var my_map = { // <-- add this line to declare the object
display: function () { // <-- add this line to declare a method
const map = new Map({
target: 'osm_map',
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});
} // <-- close the method
}; // <-- close the object
export default my_map; // <-- and export the object
Add these two lines to the end of bootstrap.js
so that it incorporates our code, and attach our object my_map to the global window object so we can reference it from the page.
import my_map from './myMap.js';
window.my_map = my_map;
Now bundle it all up by executing npm run dev
. Note that we are using Laravel's default webpack and mix configurations - we haven't needed to edit webpack.mix.js
at all.
npm run dev
copies the code in our myMap.js
file into app.js
. We need to run this each time we edit myMap.js
. ( npm run watch
can be used to automate this step ).
To get the map displayed in a blade template we need to have a div id matching the OpenLayers Map target, osm_map
in our example code above. Here's a minimal blade.
<!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:
This successfully displays an interactive OpenLayers map inside a Laravel blade template.