#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 это поощряется.