web-dev-qa-db-ja.com

webpack html-loader補間のパラメーターを指定するにはどうすればよいですか?

html-loader のドキュメントにこの例があります

require("html?interpolate=require!./file.ftl");

<#list list as list>
    <a href="${list.href!}" />${list.name}</a>
</#list>

<img src="${require(`./images/gallery.png`)}">
<div>${require('./components/gallery.html')}</div>

「リスト」はどこから来たのですか?補間スコープにパラメーターを提供するにはどうすればよいですか?

template-string-loader のようなことをしたい:

var template = require("html?interpolate!./file.html")({data: '123'});

そしてfile.htmlに

<div>${scope.data}</div>

しかし、それは機能しません。 template-string-loaderとhtml-loaderを混ぜてみましたが、うまくいきません。 template-string-loaderしか使用できませんでしたが、HTMLの画像はwebpackによって変換されません。

何か案は?ありがとうございました

25

解決策1

interpolateオプションを指定したhtml-loaderを使用して別の解決策を見つけました。

https://github.com/webpack-contrib/html-loader#interpolation

{ test: /\.(html)$/,
  include: path.join(__dirname, 'src/views'),
  use: {
    loader: 'html-loader',
    options: {
      interpolate: true
    }
  }
}

そして、htmlページでは、パーシャルhtmlおよびjavascript変数をインポートできます。

<!-- Importing top <head> section -->
${require('./partials/top.html')}
<title>Home</title>
</head>
<body>
  <!-- Importing navbar -->
  ${require('./partials/nav.html')}
  <!-- Importing variable from javascript file -->
  <h1>${require('../js/html-variables.js').hello}</h1>
  <!-- Importing footer -->
  ${require('./partials/footer.html')}
</body>

唯一の欠点は、HtmlWebpackPluginから他の変数をこの<%= htmlWebpackPlugin.options.title %>のようにインポートできないことです(少なくとも、インポートする方法が見つからない)が、私にとっては問題ではなく、単にHTMLのタイトル、またはハンドル変数用に別のJavaScriptファイルを使用します。

解決策2

古い答え

これが適切なソリューションかどうかはわかりませんが、私のワークフローを共有します(Webpack 3でテスト済み)。

html-loaderの代わりに、このプラグインを使用できます github.com/bazilio91/ejs-compiled-loader

{ test: /\.ejs$/, use: 'ejs-compiled-loader' }

.html.ejsファイルとHtmlWebpackPluginを変更して、正しい.ejsテンプレートを指すようにします。

new HtmlWebpackPlugin({
    template: 'src/views/index.ejs',
    filename: 'index.html',
    title: 'Home',
    chunks: ['index']
})

パーシャル、変数、アセットを.ejsファイルにインポートできます。

src/views/partials/head.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>

src/js/ejs_variables.js

const hello = 'Hello!';
const bye = 'Bye!';

export {hello, bye}

src/views/index.ejs

<% include src/views/partials/head.ejs %>
<body>    
  <h2><%= require("../js/ejs_variables.js").hello %></h2>

  <img src=<%= require("../../assets/sample_image.jpg") %> />

  <h2><%= require("../js/ejs_variables.js").bye %></h2>
</body>

注:パーシャルを含める場合、パスはプロジェクトのルートからの相対パスでなければなりません。

16
pldg

mustache-loader 私のために仕事をしました:

var html = require('mustache-loader!html-loader?interpolate!./index.html')({foo:'bar'});

次に、テンプレートで{{foo}}を使用し、他のテンプレートを挿入することもできます

<h1>{{foo}}</h1>
${require('mustache-loader!html-loader?interpolate!./partial.html')({foo2: 'bar2'})}
3

笑うかもしれませんが、HTMLWebpackPluginで提供されるデフォルトのローダーを使用すると、HTML部分ファイルで文字列を置き換えることができます。

  1. index.htmlはejsテンプレートです(ejsはHTMLWebpackPluginのデフォルトローダーです)
  2. file.htmlは単なるHTML文字列です(HTMLWebpackPluginでデフォルトで使用可能なhtml-loaderを介してロードされますが、おそらくwebpackに付属していますか?)

セットアップ

HTMLWebpackPluginで提供されるデフォルトのejsテンプレートを使用するだけです

new HtmlWebpackPlugin({
    template: 'src/views/index.ejs',
    filename: 'index.html',
    title: 'Home',
    chunks: ['index'],
    templateParameters(compilation, assets, options) {
        return {
            foo: 'bar'
        }
    }
})

これが私の最上位のejsファイルです

// index.html 

<html lang="en" dir="ltr">
    <head>
        <title><%=foo%></title>
    </head>
    <body>
        <%
            var template = require("html-loader!./file.html");
        %>
        <%= template.replace('${foo}',foo) %>
    </body>
</html>

これがhtml-loaderが文字列としてエクスポートするfile.htmlです。

// file.html 

<h1>${foo}</h1>
2
potench

htmlWebpackPluginのテンプレートエンジンを部分的に使用する場合は、次のように使用できます。

  <!-- index.html -->
  <body>
    <div id="app"></div>
    <%= require('ejs-loader!./partial.gtm.html')({ htmlWebpackPlugin }) %>
  </body>

  <!-- partial.gtm.html -->
  <% if (GTM_TOKEN) { %>
  <noscript>
    <iframe
      src="https://www.googletagmanager.com/ns.html?id=<%= GTM_TOKEN %>"
      height="0"
      width="0"
      style="display:none;visibility:hidden"
    ></iframe>
  </noscript>
  <% } %>

  // webpack.config.json
  {
    plugins: [
      new webpack.DefinePlugin({
        GTM_TOKEN: process.env.GTM_TOKEN,
      }),
    ],
  }

npm i ejs-loaderが必要

1
Nermo

interpolatehtml-loaderを使用すると、_canDefinePluginを使用してwebpack.config.jsから変数をインポートできます。

// webpack.config.js:

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/,
        loader: 'html-loader',
        options: {
          interpolate: true
        }
      }
    ],
  },
  plugins: [
    new DefinePlugin({
      VARNAME: JSON.stringify("here's a value!")
    })
  ]
};

// index.html

<body>${ VARNAME }</body>

html-loaderの補間は任意のJavaScript式を受け入れますが、これらの式が評価されるスコープには、デフォルトでは構成オプションが入力されていません。 DefinePluginは、そのグローバルスコープに値を追加します。 EnvironmentPluginを使用して、process.envに値を入力することもできます。

1
NReilingh

あなたはそれを自分で作ることができます:html-loaderプラグインフォルダ(index.js内)でこれをコードに置き換えます

/*
        MIT License http://www.opensource.org/licenses/mit-license.php
        Author Tobias Koppers @sokra
*/
var htmlMinifier = require("html-minifier");
var attrParse = require("./lib/attributesParser");
var loaderUtils = require("loader-utils");
var url = require("url");
var assign = require("object-assign");
var compile = require("es6-templates").compile;

function randomIdent() {
        return "xxxHTMLLINKxxx" + Math.random() + Math.random() + "xxx";
}

function getLoaderConfig(context) {
        var query = loaderUtils.getOptions(context) || {};
        var configKey = query.config || 'htmlLoader';
        var config = context.options && context.options.hasOwnProperty(configKey) ? context.options[configKey] : {};

        delete query.config;

        return assign(query, config);
}

module.exports = function(content) {
        this.cacheable && this.cacheable();
        var config = getLoaderConfig(this);
        var attributes = ["img:src"];
        if(config.attrs !== undefined) {
                if(typeof config.attrs === "string")
                        attributes = config.attrs.split(" ");
                else if(Array.isArray(config.attrs))
                        attributes = config.attrs;
                else if(config.attrs === false)
                        attributes = [];
                else
                        throw new Error("Invalid value to config parameter attrs");
        }
        var root = config.root;
        var links = attrParse(content, function(tag, attr) {
                var res = attributes.find(function(a) {
                        if (a.charAt(0) === ':') {
                                return attr === a.slice(1);
                        } else {
                                return (tag + ":" + attr) === a;
                        }
                });
                return !!res;
        });
        links.reverse();
        var data = {};
        content = [content];
        links.forEach(function(link) {
                if(!loaderUtils.isUrlRequest(link.value, root)) return;

                if (link.value.indexOf('mailto:') > -1 ) return;

                var uri = url.parse(link.value);
                if (uri.hash !== null && uri.hash !== undefined) {
                        uri.hash = null;
                        link.value = uri.format();
                        link.length = link.value.length;
                }

                do {
                        var ident = randomIdent();
                } while(data[ident]);
                data[ident] = link.value;
                var x = content.pop();
                content.Push(x.substr(link.start + link.length));
                content.Push(ident);
                content.Push(x.substr(0, link.start));
        });
        content.reverse();
        content = content.join("");

        if (config.interpolate === 'require'){

                var reg = /\$\{require\([^)]*\)\}/g;
                var result;
                var reqList = [];
                while(result = reg.exec(content)){
                        reqList.Push({
                                length : result[0].length,
                                start : result.index,
                                value : result[0]
                        })
                }
                reqList.reverse();
                content = [content];
                reqList.forEach(function(link) {
                        var x = content.pop();
                        do {
                                var ident = randomIdent();
                        } while(data[ident]);
                        data[ident] = link.value.substring(11,link.length - 3)
                        content.Push(x.substr(link.start + link.length));
                        content.Push(ident);
                        content.Push(x.substr(0, link.start));
                });
                content.reverse();
                content = content.join("");
        }

        if(typeof config.minimize === "boolean" ? config.minimize : this.minimize) {
                var minimizeOptions = assign({}, config);

                [
                        "removeComments",
                        "removeCommentsFromCDATA",
                        "removeCDATASectionsFromCDATA",
                        "collapseWhitespace",
                        "conservativeCollapse",
                        "removeAttributeQuotes",
                        "useShortDoctype",
                        "keepClosingSlash",
                        "minifyJS",
                        "minifyCSS",
                        "removeScriptTypeAttributes",
                        "removeStyleTypeAttributes",
                ].forEach(function(name) {
                        if(typeof minimizeOptions[name] === "undefined") {
                                minimizeOptions[name] = true;
                        }
                });

                content = htmlMinifier.minify(content, minimizeOptions);
        }
        
        

        if(config.interpolate && config.interpolate !== 'require') {
                // Double escape quotes so that they are not unescaped completely in the template string
                content = content.replace(/\\"/g, "\\\\\"");
                content = content.replace(/\\'/g, "\\\\\'");
                
                content = JSON.stringify(content);
                content = '`' + content.substring(1, content.length - 1) + '`';
                
                //content = compile('`' + content + '`').code;
        } else {
                content = JSON.stringify(content);
        }
        

    var exportsString = "module.exports = function({...data}){return ";
        if (config.exportAsDefault) {
        exportsString = "exports.default = function({...data}){return ";
        } else if (config.exportAsEs6Default) {
        exportsString = "export default function({...data}){return ";
        }

        return exportsString + content.replace(/xxxHTMLLINKxxx[0-9\.]+xxx/g, function(match) {
                if(!data[match]) return match;
                
                var urlToRequest;

                if (config.interpolate === 'require') {
                        urlToRequest = data[match];
                } else {
                        urlToRequest = loaderUtils.urlToRequest(data[match], root);
                }
                
                return ' + require(' + JSON.stringify(urlToRequest) + ') + ';
        }) + "};";

}

上記の Potench's 's answer は受け入れられるべきだと思いますが、注意が必要です:

警告:回答がhtmlWebpackPlugin.optionsデフォルトオブジェクト。置き換えではなく、拡張を提案する

function templateParametersGenerator (compilation, assets, options) {
  return {
    compilation: compilation,
    webpack: compilation.getStats().toJson(),
    webpackConfig: compilation.options,
    htmlWebpackPlugin: {
      files: assets,
      options: options,
      // your extra parameters here
    }
  };
}

ソース:1- https://github.com/jantimon/html-webpack-plugin/blob/8440e4e3af94ae5dced4901a13001c0628b9af87/index.js#L719-L729 2- https:/ /github.com/jantimon/html-webpack-plugin/issues/1004#issuecomment-411311939

0
ortonomy