Разбор HTML-шаблона, как вам требуется в JavaScript - PullRequest
4 голосов
/ 29 мая 2019

Я потратил часы на базовую конфигурацию веб-пакета, но все еще не могу заставить его работать. Моя цель - выполнить синтаксический анализ 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 ]

2 голосов

Хотите верьте, хотите нет, но это не обычный случай, импорт 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.

1 голос
/ 31 мая 2019

Мне кажется, что 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, если хотите работать в среде без браузера.

1 голос
/ 31 мая 2019

Ну, преобразовать строку в 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.

...