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によって変換されません。
何か案は?ありがとうございました
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ファイルを使用します。
古い答え
これが適切なソリューションかどうかはわかりませんが、私のワークフローを共有します(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>
注:パーシャルを含める場合、パスはプロジェクトのルートからの相対パスでなければなりません。
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'})}
笑うかもしれませんが、HTMLWebpackPluginで提供されるデフォルトのローダーを使用すると、HTML部分ファイルで文字列を置き換えることができます。
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>
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
が必要
interpolate
でhtml-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
に値を入力することもできます。
あなたはそれを自分で作ることができます: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