Разбор HTML-шаблона, как вам требуется в JavaScript
Я потратил часы на базовую конфигурацию веб-пакета, но все еще не могу заставить его работать. Моя цель - выполнить синтаксический анализ HTML-шаблона при его импорте в файл JavaScript. Это похоже на обычный вариант использования, но в моей конфигурации веб-пакета или в моем понимании должно быть что-то странное.
Я искал конфигурации html-loader
, html-webpack-plugin
, posthtml
так же как pug
и я прочитал все их документы, но ни один из них не сработал.
Согласно PostHTML Readme:
PostHTML - это инструмент для преобразования HTML/XML с помощью плагинов JS. Сам PostHTML очень маленький. Он включает в себя только анализатор HTML, API дерева узлов HTML и строковый преобразователь дерева узлов.
Итак, поскольку это было наиболее многообещающим, я сообщаю о своей попытке с помощью posthtml:
rules: [
{
test: /.html$/,
use: [
{
loader: "html-loader",
options: {
minimize: true,
interpolation: false
}
},
{
loader: "posthtml-loader"
}
]
}
]
Он не возвращает никакой ошибки, но, похоже, полностью игнорирует posthtml-loader
с момента исполнения import template from 'src/test.html'
Я получаю шаблон в виде строки (как предполагается сделать html-loader
в одиночестве).
В моем понимании, загрузчики должны компилировать / преобразовывать файлы в разных форматах и делать их доступными для JavaScript, и так как html
это самый распространенный тип во внешнем проекте, я предполагал, что это легко, но я не нахожу в интернете ничего, связанного с этим вопросом.
Я ожидаю, что у вас будет объект дерева DOM или что-то, что может быть использовано JavaScript.
Кто-нибудь может мне помочь?
РЕДАКТИРОВАТЬ: Мой вопрос о настройке и работе веб-пакета. Я знаю много решений для разбора строк HTML, но они здесь не применимы
3 ответа
Ну, преобразовать строку в html легко. Так что, если вы вернете строку для вашего шаблона, вы можете преобразовать ее в структуру DOM, как показано ниже.
/** Create a NON attached DOM element. This floats in nothing. Hello Dave */
var dave = document.createElement("div");
/** Give dave a body with the HTML string we received from "somewhere" */
dave.innerHTML = "<div class='foo'><input type='text'></div>";
/**
* dave is now <div><div class='foo'><input type='text'></div></div>
*/
dave.querySelector('input').value = "I'm sorry Dave, I'm afraid I can't do that";
/** ======================================================================
* Now render we render Dave, this isn't really needed, but will do anyways.
* We don't need the "wrapping" floating div we created so we get all of Dave's children
* And let Dave be forgotten about in the abyss of eternity.
*/
var content = dave.children;
var main = document.getElementById('main');
for(var i = 0; i < content.length; i++) {
main.appendChild(content[i]);
}
.foo {
background-color: red;
}
.foo input {
background-color: black;
color: white;
}
<body id="main">
</body>
Затем вы можете также выполнить преобразование для "детей", так же, как с обычным объектом дерева DOM.
Хотите верьте, хотите нет, но это не обычный случай, импорт html-файлов в JavaScript и их отображение звучит как обходной путь или хак в середине порта. Библиотеки JavaScript используются для динамического создания HTML-кода в браузере в ответ на ввод пользователя. Если это то, что вы хотите, вы должны использовать React, Vue, Angular, jQuery или аналогичные.
Как уже упоминали другие, решение вашей проблемы не в том, чтобы искать загрузчик, который преобразует HTML в узел DOM, это вы должны сделать это сами. DOM отсутствует, пока код не будет выполнен в браузере. Это не преобразование времени компиляции. Это преобразование во время выполнения.
import template from 'src/test.html'
const html = document.createElement('div')
html.innerHTML = template
Загрузчик просто не может делать то, что вы просите. Браузер отвечает за синтаксический анализ HTML и построение дерева DOM на основе его конкретной платформы и конкретной реализации. querySelector
или же createElement
являются методами API для доступа к этим функциям браузера. Но мы не владеем узлами DOM в нашем коде. Они созданы для нас платформой. Наш JavaScript просто потребляет его.
Есть несколько решений, таких как DOMParser
а также jsDOM
который может сделать это на сервере. Но они являются неполными реализациями DOM браузера, и их не следует вводить в интерфейсный код, предназначенный для отправки в браузер. Они предназначены для использования в таких целях, как тестирование без головы, сканирование в Интернете и другие формы использования веб-страниц на компьютере.
Если вы можете представить конкретный сценарий, в котором вы не можете проанализировать HTML-строку в браузере вместе с остальным кодом и непосредственно перед тем, как она будет использована JavaScript, непременно покажите нам, и мы представим решение. Но весьма вероятно, что вы неправильно поняли роли JavaScript, Webpack и HTML и отношения между ними.
TLDR: HTML - это строка, которая отправляется в браузер по HTTP, и браузер решает, как построить дерево DOM, основываясь на его конкретной реализации. В коде переднего конца нет никакой альтернативы, кроме как заставить браузер создать дерево DOM для вас с помощью предоставленной вами строки, а затем использовать его с DOM Api.
Мне кажется, что posthtml-loader
это прежде всего инструмент, который помогает "подготовить" ваш HTML во время сборки. Его параметры парсера позволяют вам взломать string -> PostHTML AST Tree
шаг, и его параметры плагина позволяют изменять дерево. Затем он переводит обратно в HTML.
Я не смог найти опцию в плагине webpack для возврата временного формата дерева.
Вы можете написать небольшой пользовательский загрузчик для анализа строк HTML в объектах DOM:
// custom-loader.js
module.exports = function(content) {
return `module.exports = (function() {
const parser = new DOMParser();
const doc = parser.parseFromString("${content}", "text/html");
return doc.body.children;
}())`;
};
Тогда в вашем webpack.config.js
, можете сказать вебпак сделать .html
файлы проходят этот загрузчик:
// webpack.config.js
module.exports = {
mode: 'development',
entry: './main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.bundle.js'
},
devtool: "eval-source-map",
module: {
rules: [
{
test: /\.html$/,
use: [ './custom-loader' ]
}
]
}
};
Теперь, когда вы печатаете что-то вроде const template = require('./template.html');
вы получите HTMLCollection
экземпляр, а не просто строка.
Обратите внимание, что этот загрузчик добавляет зависимость DOMParser
, который доступен только в браузере. Вы можете заменить его чем-то вроде jsdom
если вы хотите работать в среде без браузера.