Webpack - 如何使用热重载将 .html 片段包含到 index.html 中?

3

在PHP中,您可以包含文件片段以实现易于重用。在下面的示例中,我可以包含header.phpfooter.php。这非常方便,因为当我更新header.php时,使用它的所有页面都会显示更改:

<html>
<body>

    <?php include 'header.php';?>

    <p>Some text.</p>
    <p>Some more text.</p>

    <?php include 'footer.php';?>

</body>
</html>

我已经成功地尝试了这个答案中所提到的方法,使用了html-webpack-plugin,但是有一个问题。请见下方的配置:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const fs = require("fs");

module.exports = () => ({
    // ... lots of Webpack boilerplage

    module: {
        rules: [
            // ... js, sass, json, etc loaders
        ]
    },
    plugins: [

        //... 

        new HtmlWebpackPlugin({
            inject: false,
            hash: true,
            template: "./static/index.html",
            header: fs.readFileSync(htmlPath + "/header.html"),
            footer: fs.readFileSync(htmlPath + "/footer.html"),
            filename: "index.html",
        }),
    ]
});

这使我能够像这样包含我的.html文件:
<html>
<body>

    <%= htmlWebpackPlugin.options.header %>

    <p>Some text.</p>
    <p>Some more text.</p>

    <%= htmlWebpackPlugin.options.footer %>

</body>
</html>

乍一看,它的工作表现符合预期,但是包含的 header.htmlfooter.html 文件会被“锁定”在初始状态,如果我修改它们,我仍然会得到原始文件,而不是更新后的版本。我必须关闭 Webpack 开发服务器,然后重新运行才能使更改生效。我猜测这是因为 fs.readFileSync() 仅在初始化 Webpack 时执行,但在检测到文件更改后并不会再次执行。我该怎么做才能更新这些文件呢?

如果你不一定要使用webpack,我建议使用express和pug模板代替。模板每次请求URL时都会从磁盘读取,所以只需在浏览器中按下F5,你就能看到变化。 - user5734311
1
@ChrisG 啊,谢谢你的建议,但这是一个已经有4个开发人员的现有项目,没有人喜欢那个来改变整个框架的家伙 :) 我必须继续使用Webpack。 - undefined
2个回答

3
解决方案是将 fs.readFileSync() 调用从 webpack.config 文件中移动到 index.html 文件中,因为配置文件只在启动 dev server 时执行一次。
这是我的新 webpack.config:
// Get path to folder that contains HTML fragments
const folderPath = path.resolve(__dirname, "./src/static/");

module.exports = () => ({
    // ... lots of Webpack boilerplate

    plugins: [
        //... 
        new HtmlWebpackPlugin({
            inject: false,
            hash: true,
            template: "./static/index.html",
            filename: "index.html",
            HTML_PATH: folderPath // <- Now I only pass the folder path
        }),
    ]
});

然后我在HTML中使用readFileSync()读取文件:

<html>
<body>

    <%= require("fs").readFileSync(htmlWebpackPlugin.options.HTML_PATH + "/header.html") %>

    <p>Some text.</p>
    <p>Some more text.</p>

    <%= require("fs").readFileSync(htmlWebpackPlugin.options.HTML_PATH + "/footer.html") %>

</body>
</html>

瞧!HTML片段的热重载!


1

感谢您提供使用readFileSync()的解决方案。对我来说,这非常有帮助。

鉴于此,我考虑通过在webpack.config文件中同时使用getterreadFileSync()来进行一些改进。这将简化将其插入HTML的过程,消除了重复输入require('fs').readFileSync()的需要。而只需要<%= htmlWebpackPlugin.options.fragment.mainHeader %>就可以了。

我的webpack.config:

const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/**
 * Automatically load HTML snippet files
 */
function getFragmentContentList() {
  const fragmentFolderPath = path.resolve(__dirname, 'src/fragment');
  const fragmentFiles = fs.readdirSync(fragmentFolderPath).filter(item => {
    const itemPath = path.join(fragmentFolderPath, item);

    return fs.statSync(itemPath).isFile();
  });

  const fileContentList = {};

  fragmentFiles.forEach((filename) => {
    const fileFullPath = path.resolve(__dirname, pageFragmentPath, filename);
    const key = filename.split('.').shift();

    // use getter
    Object.defineProperty(fileContentList, key, {
      get() {
        return fs.readFileSync(fileFullPath, 'utf-8');
      },
    });
  });

  return fileContentList;
}

module.exports = () => ({
  // ...

  plugins: [
    // ... 
    new HtmlWebpackPlugin({
      filename: "index.html",
      fragment: getFragmentContenteList(), // <- Now
    }),
  ],
});

那么

<html>
<body>
  <header>
    <%= htmlWebpackPlugin.options.fragment.mainHeader %>
  </header>

  <p>Lorem</p>

  <footer>
    <%= htmlWebpackPlugin.options.fragment.mainFooter %>
  </footer>
</body>
</html>

使用的库版本:
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"html-webpack-plugin": "^5.5.3",

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接