Разбор 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 если вы хотите работать в среде без браузера.

Другие вопросы по тегам