Issue
I have a more than 800 lines single JS file using OpenLayers to create web map. It's definitely too much! The file is written in vanilla JavaScript.
It is simply structured as follow:
const function1 = (featurePassedFromFlask) {
do stuff
return someVectorLayers;
}
const function2 = (otherFeaturePassedFromFlask) {
do stuff
return aPoint;
}
const map = (vectorLayers, myPoint) => {
do stuff to build the map, no returned value.
}
vectorLayers = function1(featurePassedFromFlask);
myPoint = function2(otherFeaturePassedFromFlask);
map(vectorLayers, myPoint);
As you can see, I have three main functions in there, so I decided to split it in three files, one for each function after reading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export:
File function1.js
:
const function1 = (featurePassedFromFlask) {
do stuff
return someVectorLayers;
}
export { function1 };
File function2.js
:
const function2 = (otherFeaturePassedFromFlask) {
do stuff
return aPoint;
}
export { function2 };
and file map.js
with the remaining code + these two new lines at the top:
import { function1 } from './function1.js';
import { function2 } from './function2.js';
The "problem" is that in my Flask template map.html
(jinja2) I only load the map.js
file as:
<!-- Pass first result object from Python to JS here -->
{% if resultsObjectFromRoute1 %}
<script type="text/javascript">
var featurePassedFromFlask = {{ resultsObjectFromRoute1|tojson }};
</script>
{% endif %}
<!-- Pass second result object from Python to JS here -->
{% if resultsObjectFromRoute2 %}
<script type="text/javascript">
var otherFeaturePassedFromFlask = {{ resultsObjectFromRoute2|tojson }};
</script>
{% endif %}
<script src="{{ url_for('static', filename='js/ol.js') }}" type="application/javascript"></script>
<script src="{{ url_for('static', filename='js/map.js') }}" type="application/javascript"></script>
The browser first complained: Uncaught SyntaxError: import declarations may only appear at top level of a module
so I browse a little to figure out I have to change the last line to:
<script src="{{ url_for('static', filename='js/map.js') }}" type="module"></script>
It doesn't complain anymore but not the page is not properly working:
Uncaught ReferenceError: assignment to undeclared variable geom
I also tried to import my two functions files in map.html
without any changes to the previous error message:
<script src="{{ url_for('static', filename='js/function1.js') }}" type="module"></script>
<script src="{{ url_for('static', filename='js/function2.js') }}" type="module"></script>
<script src="{{ url_for('static', filename='js/map.js') }}" type="module"></script>
Maybe it would have worked if the function 1 and 2 didn't had to processed an argument, so I know I broke something related to that, because now those files "function1.js" and "function2.js" are no longer aware of the existence of the object they have to take into account as argument to the function defined in there. So how could I bring up that link again, just like when all was encapsulated in a single file?
ps: sorry for the probably bad - to very bad - wording, I'm not an expert in JS (that's also probably why I didn't succeed to find some helpful material).
Solution
I finally figure it out.
There are two possibilities.
1. as classical "type=application/javascript" imports within the HTML
Like @Kajbo suggested in the comments above, removing all export/import syntax and loading all the JS files in one by one in the HTML, with the main one (map.js
) being loaded last in the template does work:
<script src="{{ url_for('static', filename='js/function1.js') }}" type="application/javascript"></script>
<script src="{{ url_for('static', filename='js/function2.js') }}" type="application/javascript"></script>
<script src="{{ url_for('static', filename='js/map.js') }}" type="application/javascript"></script>
but it doesn't work if they are loaded as "module", as I initially did.
The main disadvantage of this way of doing is that if you end up having 180 JS files, it meas 180 imports in your HTML. I was not very enthusiastic.
2. as modern "type=module" imports within the HTML
In fact, I noticed that the error I had on geom
was due to this line in my code:
geom = new ol.format.GeoJSON();
If this lazy way of declaring a variable worked before when loading the JS file with "type=application/javascript", it doesn't work when you load them as "type=module". Indeed, modules seem to be more ticklish and you really have to declare your variables properly now:
let geom = new ol.format.GeoJSON();
I've had many other similar mistakes, so I cleaned up my code with proper declarations and that's it! It's working now with the export/import ES6 logic, hence you can keep your HTML clean by only importing the main JS file (all JS logic stays in the JS files; that's much cleaner)!
Answered By - s.k
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.