Mòduls amb Javascript

De wikijoan
Salta a la navegació Salta a la cerca

Mòduls. Introducció

$ unzip js-examples-master.zip

Anem al primer exemple:

$ cd js-examples-master/modules/basic-modules/
$ ls
index.html
main.js
modules/
    canvas.js
    square.js

Trobem els exports en els scripts de la carpeta modules/: canvas.js i square.js. Les funcions definides en aquests mòduls s'importen en el main.js, que és el fitxer principal de Javascript. El index.html és el punt d'entrada de la web/html, i fa referència al main.js com has fet moltes vegades.

Debes prestar atención a las pruebas locales — si intentas cargar el archivo HTML localmente (es decir, con una URL file:///), te encontrarás con errores de CORS debido a los requisitos de seguridad del módulo JavaScript. Necesitas hacer tus pruebas a través de un servidor.

Comprovar que el primer exemple funciona correctament (basic-modules), i comprovar que funciona la resta d'exemples.

Cas pràctic. Dibuixar un mapa amb la llibreria OpenLayers

Treballar amb llibreries

A high-performance, feature-packed library for all your mapping needs.

Donar una ullada a tots els exemples que podem fer a:

Però el hola món de com pintar un mapa és a:

En el primer exemple no utilitzem els mòduls, ho fem amb les llibreries:

script pintar_mapa.html:

<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
    <style>
      .map {
        height: 400px;
        width: 100%;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
    <title>OpenLayers example</title>
  </head>
  <body>
    <h2>My Map</h2>
    <div id="map" class="map"></div>
    <script type="text/javascript">
      var map = new ol.Map({
        target: 'map',
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          })
        ],
        view: new ol.View({
          center: ol.proj.fromLonLat([37.41, 8.82]),
          zoom: 4
        })
      });
    </script>
  </body>
</html>
  • Pintar el mapa sobre la teva ciutat amb un nivell de zoom adequat.
  • Provar una altra servidor de tiles:
source: new ol.source.Stamen({layer: 'toner'})

Ara farem aquest mateix exercici amb mòduls. Els exemples que hem vist anteriorment estan tots amb mòduls.

Treballar amb mòduls

Per treballar amb mòduls, que és la manera recomanable, hem d'anar als Tutorials, i anar al primer de tots: Building an OpenLayers Application:

$ mkdir app
$ cd app

Per crear l'aplicació i importar tots els mòduls de Openlayers, utilitzarem npm.

$ npm init

Quan et pregunta, pots deixar totes les opcions per defecte. S'ha creat el fitxer package.json.

This will create a package.json file in your working directory. Add OpenLayers as dependency to your application with

$ npm install ol

Es crea la carpeta node_modules amb totes les dependències. At this point you can ask NPM to add required development dependencies by running

$ npm install --save-dev parcel-bundler

Què és parcel?

Blazing fast, zero configuration web application bundler


Ara necessitem construir l'aplicació, amb els fitxers index.js i index.html.

script index.js:

import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import {fromLonLat} from 'ol/proj'; //línia nova
import OSM from 'ol/source/OSM';

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new OSM()
    })
  ],
  view: new View({
    //center: [0, 0],
    center: fromLonLat([1.9858, 41.9176]), //línia modificada
    zoom: 0
  })
});

script index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Using Parcel with OpenLayers</title>
    <style>
      #map {
        width: 400px;
        height: 250px;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script src="./index.js"></script>
  </body>
</html>

Modifiquem el fitxer package.json per definir com es fa el build de l'aplicació i com s'engega (start):

package.json:

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "parcel index.html",
    "build": "parcel build --public-url . index.html"
  },
  "author": "",
  "license": "ISC"
}

Finalment, per fer córrer l'aplicació, farem:

$ npm start

> app@1.0.0 start /home/joan/M06_WEC_2021/UF2/openlayers/app
> parcel index.html

Server running at http://localhost:1234 
✨  Built in 13.21s.
  • localhost:1234

Per crear un production bundle (es crea la carpeta dist/)

$ npm run build

> app@1.0.0 build /home/joan/M06_WEC_2021/UF2/openlayers/app
> parcel build --public-url . index.html

✨  Built in 21.59s.

dist/app.ef0d89f9.js.map     ⚠️  1.95 MB     248ms
dist/app.ef0d89f9.js          540.56 KB    19.16s
dist/app.bb28b584.css.map       7.18 KB       3ms
dist/app.bb28b584.css           3.96 KB     5.42s
dist/index.html                   273 B     2.06s

and copy the dist/ folder to your production server.

Aquesta carpeta dist/ conté totes les llibreries i el codi comprimit. L'objectiu és ara posar aquesta carpeta dist/ dins el teu Apache/XAMP i veure que funciona. Per tant, distingim entre l'entorn de desenvolupament, i l'entorn de desplegament en la fase de producció.

Dòlmens de Catalunya

Posar una icona sobre un mapa

Se't proporciona el codi mínim per pintar una icona sobre un mapa. En aquest cas, com a mapa escollim el render de OSM:

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Icon, Style} from 'ol/style';
import {LineString, Point} from 'ol/geom';
import {getVectorContext} from 'ol/render';
import {fromLonLat} from 'ol/proj';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import OSM from 'ol/source/OSM';

var features = new Array();
var feature = new Feature({
  'geometry': new Point(fromLonLat([1.9858, 41.9176])),
  'name': 'nom element',
});

features.push(feature)

var iconStyle = new Style({
  image: new Icon({
    anchor: [0.5,20],
    anchorXUnits: 'fraction',
    anchorYUnits: 'pixels',
    src: 'img/dolmen_16.png'
  })
});

var vectorSource = new VectorSource({
  features: features,
  wrapX: false,
});

var vector = new VectorLayer({
  source: vectorSource,
  style: iconStyle,
});

var map = new Map({
  layers: [
    new TileLayer({
      source: new OSM({
        layer: 'OSM'
      })
    }),
    vector
  ],
  target: 'map',
  view: new View({
    center: fromLonLat([1.9858, 41.9176]),
    zoom: 9
  })
});

Dibuixar tots els dòlmens. Solució

Fitxer:Dolmens.zip En el següent fitxer se't proporciona:

  • dolmens.js (llistat dels dòlmens en format json, geolocalitzats, a punt per exportar el mòdul, veure la última línea)
  • img/dolmen_16.png: és la icona que farem servir.
  • solució_v0: index_v0.html i main_v0.html. Pintem només una icona (un dolmen) sobre el mapa.
  • solució_v1: index_v1.html i main_v1.html. Pintem tots els dòlmens. En l'exercici anterior havies aconseguit pintar un marker (icona). Ara es tracta de recórrer tots els dòlmens, omplir tota la matriu, i posar una icona ben geolocalitzada per cada dolmen.
  • solució_v2: index_v2.html i main_v2.html. Volem ampliar la funcionalitat. Quan cliquem sobre el dolmen se'ns mostra una caixa de text amb el nom i el municipi del dolmen.

Feina per l'alumne

  • El primer objectiu és fer funcionar (i entendre) tots els exemples proposats
  • Partint de l'aplicatiu dels dòlmens, ara l'objectiu és pintar sobre un mapa una altra informació de nodes geolocalitzats que puguis aconseguir de OSM (consulta a Overpass Turbo). Per exemple, se't proposa el llistat de vèrtex geodèsics de Catalunya:
https://wiki.openstreetmap.org/wiki/ES:Tag:man_made%3Dsurvey_point
man_made=survey_point

O bé qualsevol altra informació que consideris d'interès (però han de ser nodes/punts, no vies). En cas de dubte, consultar el professor. Exemple real: mapa interactiu de les restes de la muralla medieval de Màlaga:

Desplegament de l'aplicatiu

Mira aquest projecte similar:

i llegeix atentament l'apartat de desplegament. Ho comentarem a classe.

Entrega al Classroom

Entregaràs al Classroom la teva solució, dins del termini previst per fer-ho.

Utilitzar mòduls a la consola. Actualitzar Node

El codi mínim i que no té interfície gràfica seria:

script square.js:

const name = 'square';

function instanciar(length, color) {
  return {
    length: length,
    color: color
  };
}

function reportArea(length) {
  console.log(length*length);
}

function reportPerimeter(length) {
    console.log(4*length);
}

export { name, instanciar, reportArea, reportPerimeter };

script main.js:

import { name, instanciar, reportArea, reportPerimeter } from './square.mjs';

let square1 = instanciar(100, 'blue');
reportArea(square1.length);
reportPerimeter(square1.length);

I si fem:

$ node main.js
import { name, instanciar, reportArea, reportPerimeter } from './square.js';
       ^

SyntaxError: Unexpected token {
    at Module._compile (internal/modules/cjs/loader.js:723:23)
...

dóna error, no sap què és aquesta sintaxi. I és que cal tenir el node ben actualitzat. Com es comenta a:

això funciona en la versió 13. Jo tinc la versió:

$ node --version
v10.19.0

i per tal de què funcioni el codi s'ha de fer:

  1. posar els scripts amb extensió .mjs en comptes de .js
  2. utilitzar l'opció --experimental-modules
$ node --experimental-modules main.mjs 
(node:5212) ExperimentalWarning: The ESM module loader is experimental.
10000
400

Actualitzar Node a la última versió

1. First, clear the npm cache:

$ npm cache clean -f

2. Install n, Node’s version manager:

$ sudo npm install -g n

3. With the n module installed, you can use it to:

$ n latest
$ sudo n latest
  installing : node-v16.1.0
       mkdir : /usr/local/n/versions/node/16.1.0
       fetch : https://nodejs.org/dist/v16.1.0/node-v16.1.0-linux-x64.tar.xz
   installed : v16.1.0 (with npm 7.11.2)

Note: the node command changed location and the old location may be remembered in your current shell.
         old : /usr/bin/node
         new : /usr/local/bin/node
To reset the command location hash either start a new shell, or execute PATH="$PATH"

Tanco la consola i n'obro una altra, i ara ja tenim la última versió:

$ node --version
v16.1.0

i podem provar el nostre codi, que ara ja funciona sense experimental:

$ node main.mjs
10000
400

ara bé, si vull utilitzar l'extensió .js, necessito un package.json:

$ node main.js
(node:7055) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/home/joan/main.js:1
import { name, instanciar, reportArea, reportPerimeter } from './square.js';
^^^^^^

SyntaxError: Cannot use import statement outside a module

creat per Joan Quintana Compte, març 2021