javascript 使用Webpack 5 -如何在使用服务器端模板引擎时引用html中带有[contenthash]替换的文件?

mrphzbgm  于 2023-11-15  发布在  Java
关注(0)|答案(1)|浏览(115)

使用时copy-webpack-plugin
并指定to:'images/[name].[contenthash][ext]'

如何在不使用html-webpack-pluginhandlebars-loader的情况下在模板中引用这些文件?
我用以下解决方案解决了这个问题:

/**
 * Create a new plugin class.
 */
const StoreAssetsInfoKeysPlugin = class StoreAssetsInfoKeysPlugin {
  /**
   * Define `apply` as its prototype method.
   * @param hooks
   */
  apply({ hooks }) {
    /**
     * Using the 'afterCompile' hook:
     * Use the 'assetsInfo' Map which contains the output of all asset paths,
     * construct an array containing all these paths,
     * then write an 'assets.json' file somewhere in your project.
     */
    hooks.afterCompile.tapAsync('StoreAssetsInfoKeysPlugin', ({ assetsInfo }, callback) => {
      fs.writeFileSync('/path/to/assets.json', JSON
        .stringify(Array
          .from(assetsInfo.entries())
          .map(([key]) => `/assets/${key}`)));

      callback();
    });
  }
};
/**
 * The Webpack configuration for this
 * example looks like this.
 */
export default {
  plugins: [
    new StoreAssetsInfoKeysPlugin(),
    new CopyPlugin({
      patterns: [{
        from: '/path/to/images/*',
        to: 'images/[name].[contenthash][ext]',
      }],
    }),
  ],
};
/**
 * Create a helper function which will find the
 * correct path from the 'assets.json'
 */
export const getAssetPath = function getAssetPath(directory, filename, ext) {
  return JSON
    .parse(fs.readFileSync('/path/to/assets.json'))
    .find((value) => value
      .match(`^.*?\\b${directory}\\b.*?\\b${filename}\\b.*?\\.${ext}\\b.*?$`));
};
/**
 * Then use the helper function within your
 * server-side templating engine:
 */
getAssetPath('images', 'my-image', 'svg');

这是一个合适的解决方案吗?
这是我第一个在服务器端模板中用[contenthash]替换来获取文件名的解决方案。
我是Webpack的新手,所以对这种方法的任何想法都将受到赞赏。

2skhul33

2skhul331#

我试着详细定义目标:
1.我们有一个模板文件(例如index.hbs)
1.在源模板文件中应引用source files的脚本、样式、图像和其他资源
1.在处理后的模板文件中,应该散列output filenames,其中包含contenthash
1.模板文件必须不呈现为HTML,才能通过服务器端呈现使用模板
目标是否正确?
如果是,那么你可以使用一个强大的“html-plugin-webpack-plugin”没有html-webpack-pluginhandlebars-loadercopy-webpack-plugin.
例如,下面是示例的文件结构:

src/views/index.hbs
src/scss/styles.scss
src/js/main.js
src/images/picture.png

dist/ <= output directory for processed files

字符串
有一个源模板文件src/views/index.hbs(或其他HTML文件):

<html>
<head>
  <!-- source files with path relative to the template file -->
  <link href="../scss/styles.scss" rel="stylesheet">
  <script src="../js/main.js" defer="defer"></script>
</head>
<body>
  {{> header }}
  <h1>Hello World!</h1>
  
  <!-- source image file with path relative to the template file -->
  <img src="../images/picture.png">

  {{> footer }}
</body>
</html>

  • webpack.config.js*:
const path = require('path');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist'), // output path for processed files
  },,
  plugins: [
    new HtmlBundlerPlugin({
      entry: {
        // define templates here
        // the key is output file path w/o extension, e.g.:
        index: 'src/views/index.hbs', // => dist/index.hbs
      },
      js: {
        // output filename of compiled JavaScript
        filename: 'js/[name].[contenthash:8].js',
      },
      css: {
        // output filename of extracted CSS
        filename: 'css/[name].[contenthash:8].css',
      },
      // defaults used Eta (ESJ like) template engine to render into HTML
      // if you will render .hbs to .html, then define as `handlebars`
      preprocessor: false, // <= disable rendering into HTML to keep original template content
    }),
  ],

  module: {
    rules: [
      {
        test: /\.(scss)$/,
        use: ['css-loader', 'sass-loader'],
      },
      {
        test: /\.(ico|png|jp?g|svg)/,
        type: 'asset/resource',
        generator: {
          // output filename of images
          filename: 'img/[name].[hash:8][ext]',
        },
      },
    ],
  },
};


如果您将保留原始模板内容,并且仅使用其散列输出文件名替换源资源文件,则使用preprocessor: false插件选项禁用渲染。
处理后的(未呈现为html)模板将如下所示:

<html>
<head>
  <!-- output filenames relative to the dist/ directory -->
  <link href="css/styles.0f23efdf.css" rel="stylesheet" />
  <script src="js/main.5317c1f6.js" defer="defer"></script>
</head>
<body>
  {{> header }}
  <h1>Hello World!</h1>

  <!-- output filenames relative to the dist/ directory -->
  <img src="img/picture.7b396424.png" />

  {{> footer }}
</body>
</html>


如果你要将任何模板渲染成HTML,你可以使用一个支持的模板引擎“开箱即用”:Eta,EJS,Handlebars,Nunjucks,LiquidJS。
插件的配置,以呈现HTML格式的工具栏模板:

new HtmlBundlerPlugin({
      entry: {
        // define templates here
        // the key is output file path w/o extension, e.g.:
        index: 'src/views/index.hbs', // => dist/index.html
      },
      js: {
        // output filename of compiled JavaScript
        filename: 'js/[name].[contenthash:8].js',
      },
      css: {
        // output filename of extracted CSS
        filename: 'css/[name].[contenthash:8].css',
      },
      // specify the `handlebars` template engine
      preprocessor: 'handlebars',
      // define handlebars options
      preprocessorOptions: {
        partials: ['src/views/partials'],
      },
    })


呈现的HTML:

<html>
<head>
  <!-- output filenames relative to the dist/ directory -->
  <link href="css/styles.0f23efdf.css" rel="stylesheet" />
  <script src="js/main.5317c1f6.js" defer="defer"></script>
</head>
<body>
  <div class="header">html of your header partials</div>
  <h1>Hello World!</h1>

  <!-- output filenames relative to the dist/ directory -->
  <img src="img/picture.7b396424.png" />

  <div class="footer">html of your footer partials</div>
</body>
</html>

相关问题