Модуль Javascript не загружается в HTML в Chrome v91

#javascript #html #node.js #es6-modules

Вопрос:

У меня есть простой модуль javascript, содержащий классы, общие для модулей javascript на стороне браузера и ES6 сервера узлов. Код имеет одинаковое происхождение, поэтому ошибок при загрузке нет, но ни один из экспортированных объектов из модуля ES6 не доступен в сценарии браузера. Игнорируя повторное использование и учитывая только сторону браузера, это работает:
latlong.js не-модуль

 function LatLon(lat,lon) {
      this.lat = lat;
      this.lon = lon;
  }
 

test.html

 <body>
  <script  src="latlong.js"></script>
  <script>
    let test = new LatLon(1,2)
  </script>
</body>
 

Но это не использует модули и, следовательно, не может использоваться совместно с кодом сервера узлов, поэтому я хочу, чтобы следующее работало, но это не удается

latlong.js модуль, который отлично импортирует js-код на стороне сервера и работает

 export class LatLon {
    constructor(lat, lon) {
      this.lat = lat;
      this.lon = lon;
    }
  }
 

test.html с помощью импорта модулей

 <body>
  <script type="module" src="latlong.js"></script>
  <script>
    let test = new LatLon(1,2)  <=Uncaught ReferenceError: LatLon is not defined
  </script>
</body>
 

Существует много других вариантов того, как экспортировать класс/прототип из модуля или объявить класс прототипа, но все они приводят к одной и той же ошибке для меня.

Это выполняется на локальном веб-сервере, и я проверил заголовки, возвращенные в обоих случаях для загрузки latlong.js имеет приложение типа контента/javascript. Поскольку это веб-сервер ampps, я могу изменить тип mime для запросов js и mjs на text/javascript, чтобы он был более совместимым, но это не влияет на сообщение об ошибке.

Включение модуля в HTML-документ является обычным делом, так что же я делаю не так?

Ответ №1:

Модули не будут работать, если вы не import используете их там, где вы хотите их использовать. Также вы должны объявить импорт script как module единое целое.

Это сработает:

 <script type="module">
  import {LatLon} from 'latlong.js';
  let test = new LatLon(1,2)
</script>
 

Комментарии:

1. К сожалению, это все еще работает не так, как ожидалось, но спасибо @Guerric P за то, что посмотрели на это. Заранее приношу извинения за попытку показать пример кода здесь, но разрывы строк в комментариях не поддерживаются :(. Оператор «импорт» доступен только для этого <script type="module"> блока. Например, вторая ссылка снова сообщает «Ошибка ссылки: LatLon xx» <script type="module"> import {LatLon} from "./latlong.js" let test = new LatLon(1,2) </script> <script> let test2 = new LatLon(3,4) </script> . Та же ошибка возникает, если используется 2-й <тип сценария=»модуль»>.

Ответ №2:

Мне удалось добавить строку импорта в каждый блок, в котором требовалось содержимое, но мне это не нравится. Может быть, некоторые эксперты могут объяснить, почему это «лучше»?

 <script type="module">
  import {LatLon} from 'latlong.js'; //import where first used (not in <HEAD>)
  let test = new LatLon(1,2)
</script>
 

… позже на странице …

 <script type="module">
  import {LatLon} from 'latlong.js';  //required to import module again
  let test2 = new LatLon(1,2)
</script>
 

это означает, что вы импортируете/включаете один и тот же модуль на всей своей html-странице, а не один раз в верхней части файла, как это обычно практикуется. Я не знаю наверняка, лучше ли ожидать, что все включает в себя в верхней части файла, но я вполне привык к этому шаблону и никогда не ожидал, что буду просматривать код для поиска новых зависимостей.
Моя цель состояла в том, чтобы хорошо практиковать кодирование и делиться некоторыми глобальными структурами и перечислениями между клиентом и сервером. Хотя совместное использование достигается наряду с преимуществом устранения дублирующих определений в коде, эта необходимость в повторном импорте, по-видимому, является компромиссом.
Я знаю, что некоторые скажут: «просто поместите весь свой сценарий в один блок», и для меня я нахожу, что в любом случае это так в большинстве случаев. Но стандарт допускает несколько блоков по определенной причине, и когда вам это нужно, оно есть. В EJS это поощряется.