5

I spent hours on a basic webpack configuration but I'm still not able to make it work. My aim is to perform the parsing of a html template as you import it in a JavaScript file. It looks like a common use-case, but there should be something odd in my webpack configuration or in my understanding.

I looked for configurations of html-loader, html-webpack-plugin, posthtml as well as pug and I've read all of their documentations, but none of them worked.

According to PostHTML Readme:

PostHTML is a tool for transforming HTML/XML with JS plugins. PostHTML itself is very small. It includes only a HTML parser, a HTML node tree API and a node tree stringifier.

So, since it was the most promising, I report my attempt with posthtml:

   rules: [
      {
        test: /.html$/,
        use: [
          {
            loader: "html-loader",
            options: {
              minimize: true,
              interpolation: false
            }
          },
          {
            loader: "posthtml-loader"
          }
        ]
      }
    ]

It doesn't return any error but it looks like is totally ignoring the posthtml-loader, since executing import template from 'src/test.html' I get the template as string (how is supposed to do html-loader alone).

In my understanding, loaders are supposed to compile/transform files with different formats and make them available to JavaScript, and since html is the most common type in a front-end project I supposed it was easy, but I'm not finding anything on the internet related to this question.

What I expect is to have a DOM tree object or, anyway, something that can be used by JavaScript.

Is anyone able to help me?

EDIT: My question is about getting a webpack configuration up and working. I know many solution for parsing HTML strings, but they're not applicable here

4

3 回答 3

2

信不信由你,这不是一个常见的用例,将 html 文件导入 JavaScript 并显示它们听起来像是一种解决方法或中间端口 hack。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 只是在消费它。

有一些解决方案可以在服务器上执行此操作DOMParserjsDOM但它们是浏览器 DOM 的不完整实现,不应将它们带入旨在发送到浏览器的前端代码中。它们旨在用于诸如无头测试、网络爬虫和其他形式的网页机器消耗之类的事情。

如果您可以提出一个特定场景,即您无法在浏览器中解析 HTML 字符串以及其余代码,并且在 JavaScript 使用它之前,请务必向我们展示,我们将提供解决方案。但是你很可能误解了 JavaScript、Webpack 和 HTML 的作用以及它们之间的关系。

TLDR:HTML 是一个通过 HTTP 发送到浏览器的字符串,浏览器根据其供应商特定的实现来决定如何构建 DOM 树。在前端代码中,除了让浏览器使用您提供的字符串为您构建 DOM 树,然后使用 DOM Api 使用它之外,别无选择。

于 2019-05-31T14:52:41.800 回答
2

好吧,将字符串转换为 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 树对象一样。

于 2019-05-31T09:13:23.297 回答
1

对我来说,它似乎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,你可以告诉 webpack 让.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如果您想在非浏览器环境中运行,您可以将其替换为类似的东西。

于 2019-05-31T14:09:53.597 回答