Программные модули в html

Inlining ECMAScript Modules in HTML

I’ve been experimenting with new native ECMAScript module support that has recently been added to browsers. It’s pleasant to finally be able import scripts directly and cleanly from JavaScript. /example.html 🔍

  

However, this only allows me to import modules that are defined by separate external JavaScript files. I usually prefer to inline some scripts used for the initial rendering, so their requests don’t block the rest of the page. With a traditional informally-structured library, that might look like this: /inline-traditional.html 🔍

    

However, naively inlining modules files obviously won’t work, since it would remove the filename used to identify the module to other modules. HTTP/2 server push may be the canonical way to handle this situation, but it’s still not an option in all environments. Is it possible to perform an equivalent transformation with ECMAScript modules? Is there any way for a

   

Or maybe by an entirely different reference scheme, such as is used for local SVG references: /inline-id.html 🔍

  

I don’t think that homebrew non-spec compliant inline-module can be considered a good start with ES modules. Webpack/Rollup bundles are still indispensable in production — especially if you’re afraid of blocking requests. Yes, service worker looks like a viable solution — but it still should make requests in order to provide data. which can be blocking, btw.

Читайте также:  Pop last element python

@estus I was imagining using service workers to take the inlined

5 Answers 5

Hacking Together Our Own import from ‘#id’

Exports/imports between inline scripts aren’t natively supported, but it was a fun exercise to hack together an implementation for my documents. Code-golfed down to a small block, I use it like this:

    

Instead of , we need to define our script elements using a custom type like . This prevents the browser from trying to execute their contents itself, leaving them for us to handle. The script (full version below) finds all inline-module script elements in the document, and transforms them into regular script module elements with the behaviour we want.

Inline scripts can’t be directly imported from each other, so we need to give the scripts importable URLs. We generate a blob: URL for each of them, containing their code, and set the src attribute to run from that URL instead of running inline. The blob: URLs acts like normal URLs from the server, so they can be imported from other modules. Each time we see a subsequent inline-module trying to import from ‘#example’ , where example is the ID of a inline-module we’ve transformed, we modify that import to import from the blob: URL instead. This maintains the one-time execution and reference deduplication that modules are supposed to have.

  

The execution of module script elements is always deferred until after the document is parsed, so we don’t need to worry about trying to support the way that traditional script elements can modify the document while it’s still being parsed.

export <>; for (const original of document.querySelectorAll('script[type=inline-module]')) < const replacement = document.createElement('script'); // Preserve the ID so the element can be selected for import. if (original.id) < replacement.id = original.id; >replacement.type = 'module'; const transformedSource = original.textContent.replace( // Find anything that looks like an import from '#some-id'. /(from\s+|import\s+)['"](#[\w\-]+)['"]/g, (unmodified, action, selector) => < // If we can find a suitable script with that id. const refEl = document.querySelector('script[type=module][src]' + selector); return refEl ? // ..then update the import to use that script's src URL instead. `$/* $ */ '$'` : unmodified; >); // Include the updated code in the src attribute as a blob URL that can be re-imported. replacement.src = URL.createObjectURL( new Blob([transformedSource], )); // Insert the updated code inline, for debugging (it will be ignored). replacement.textContent = transformedSource; original.replaceWith(replacement); > 

Warnings: this simple implementation doesn’t handle script elements added after the initial document has been parsed, or allow script elements to import from other script elements that occur after them in the document. If you have both module and inline-module script elements in a document, their relative execution order may not be correct. The source code transformation is performed using a crude regex that won’t handle some edge cases such as periods in IDs.

Источник

Модули

Модули позволяют организовать функционал в отдельные блоки, которые затем можно использовать в других приложениях.

Отличие модулей от обычных скриптов:

  • Для загрузки модулей применяется политика CORS. Это значит, что мы не можем просто кинуть в браузер html-страницу, которая подключает модуль. Модуль загружается с использованием протокола http/https. То есть страница html, которая загружает модуль, должна располагаться на каком-нибудь веб-сервере.
  • Модули всегда выполняются в режиме strict mode .
  • Модули по умолчанию загружаются асинхронно.
  • Модули загружаются и выполняются только один раз.
  • Модули позволяют использовать выражения await верхнего уровня без определения и вызова асинхронной функции.
  • Модули могут имортировать функционал из других модулей и, в свою очередь, экспортировать свою функциональность в другие модули.
  • Модули выполняются не в глобальном контексте, а в своей собственной области видимости. То есть переменные, константы, функции, классы и т.д., определенные внутри модуля, не доступны извне, пока они не будут явным образом экспортированы. А чтобы другой модуль мог их использовать, он должен их импортировать.

Если файл содержит выражения import или export , он рассматривается как модуль. Так, Чтобы сделать из простого скрипта модуль, достаточно добавить в файл:

Определение модуля. Экспорт.

Определим простейший модуль. Для этого создадим файл message.js , в котором определим следующий код:

Здесь определена обычная функция sayHello() , которая выводит некоторое сообщение на консоль. Но она определена с ключевым словом export , а это значит, что данный файл представляет модуль, а функцию sayHello() можно импортировать в другие модули.

Подключение модуля. Импорт

Теперь подключим эту функцию в другой файл. Для этого возьмем файл main.js :

import from "./message.js"; sayHello();

Для подключения функционала из другого модуля применяется ключевое слово import , после которого идут названия подключаемых компонентов. Все подключаемые из модуля компоненты помещаются в фигурные скобки: import — в данном случае подключается функция sayHello.

Затем после оператора from указывается модуль, из которого идет импорт. В данном случае указываем «./message.js». В данном случае предполагается что оба модуля — main.js и message.js будут находиться в одной папке.

Загрузка модулей

Для загрузки модулей определим в папке со скомпилированными файлами веб-страницу index.html :

Для загрузки главного модуля приложения — main.js определяется элемент , у которого устанавливается атрибут type=»module» .

Загрузка модулей производится через AJAX, поэтому скомпилированные модули должны быть размещены на веб-сервере. То есть у нас не получится просто кинуть страницу в веб-браузер и загрузить на нее модули. Такая веб-страница должна быть размещена на веб-сервере. Поэтому прежде всего надо определиться с веб-сервером. Веб-сервер может быть любым. В данном случае воспользуемся самым простым вариантом — Node.js. Но опять же вместо node.js это может быть любая другая технология сервера — php, asp.net, python и т.д. либо какой-то определенный веб-сервер типа Apache или IIS.

Итак, создадим в папке с файлами модулей файл сервера. Пусть он будет называться server.js и будет иметь следующий код:

const http = require("http"); const fs = require("fs"); http.createServer(function(request, response) < // получаем путь после слеша let filePath = request.url.substr(1); if(filePath == "") filePath = "index.html"; fs.readFile(filePath, function(error, data)< if(error)< response.statusCode = 404; response.end("Resourse not found!"); >else < if(filePath.endsWith(".js")) response.setHeader("Content-Type", "text/javascript"); response.end(data); >>); >).listen(3000, function()< console.log("Server started at 3000"); >);

Это самый примитивный сервер, который отдает пользователю статические файлы. Для создания сервера применяется функция http.createServer() , а для считывания и отправки файлов — функция fs.readFile() . Если имя файла не указано, то отправляется файл index.html . Сервер будет запускаться по адресу http://localhost:3000/

Стоит отметить, что при отправке модулей js нам надо устанавливать mime-тип отправляемого контента в «text/javascript» :

if(filePath.endsWith(".js")) response.setHeader("Content-Type", "text/javascript");

Структура финального проекта:

Определение модулей JavaScript

Теперь запустим сервер с помощью команды

Источник

What is an HTML Module?

What exactly is HTML Modules? I understand that it might allow a developer to create HTML as a module like how ES6 Modules are to JavaScript. But, are these modules basically templates like Mustache, Handlebars and Pug? Or is it like a wrapper around a similar templating system that will allow us to import an HTML file easily into another HTML file? Will it pave a way to avoid using templating libraries utilizing the Web Components? [Update] Here is the link to where I found this — https://github.com/w3c/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md

1 Answer 1

HTML Modules are the new proposal for importing HTML files into a document.

HTML import supported a similar feature and permitted to import an HTML file (eventually containing itself JS and CSS) but it has been deprecated and JS module import has partially substituted that feature.

The point of HTML imports are to complete that part and make possible to import HTML files again instead of JavaScript files only. Today you just can’t import files that contain HTML (again, you could do that when meta rel=import href=myfile.html> which is not supported anymore). If you want to do that, you have to write HTML in JavaScript string prior to process it.

The proposal also introduces notions such as import.meta.document that refer to the internal document to be imported.

Note that is it a proposal, even though it could be inserted into the spec, it should then be implemented by browsers, and finally adopted by the community in order to remain and become a stable feature.

Currently the closest you can use is the Lego Web-Component library that allows to include HTML as a module and extends native HTML functionality:

Let’s see how the spec is going to evolve for HTML Modules in the future…

Источник

Оцените статью