【问题标题】:How can I provide parameters for webpack html-loader interpolation?如何为 webpack html-loader 插值提供参数?
【发布时间】:2017-01-15 09:32:42
【问题描述】:

在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>

但它不起作用。我尝试将模板字符串加载器与 html-loader 混合,但它不起作用。我只能使用模板字符串加载器,但是 HTML 中的图像不会被 webpack 转换。

有什么想法吗?谢谢

【问题讨论】:

标签: webpack webpack-html-loader


【解决方案1】:

解决方案 1

我找到了另一个解决方案,使用 html-loader 和 interpolate 选项。

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>

唯一的缺点是你不能像&lt;%= htmlWebpackPlugin.options.title %&gt;这样从HtmlWebpackPlugin导入其他变量(至少我找不到导入它们的方法)但对我来说这不是问题,只需写标题在您的 html 中或使用单独的 javascript 文件处理变量。

解决方案 2

旧答案

不确定这是否适合您,但我将分享我的工作流程(在 Webpack 3 中测试)。

你可以使用这个插件github.com/bazilio91/ejs-compiled-loader,而不是html-loader:

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

将.ejs 和HtmlWebpackPlugin 中的.html 文件更改为指向右侧的.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>

注意,当您包含部分路径时,路径必须相对于项目的根目录。

【讨论】:

  • 解决方案 1 对我有用,但我必须以这种方式在 variables.js 文件中导出它:module.exports.hello = hello;否则它给了我一些绑定错误。
  • 如果您按此顺序堆叠以下加载程序(它们从右到左工作),您可以使用HtmlWebpackPlugin 变量:['ejs-loader', 'extract-loader', 'html-loader']
  • 我得出的结论是,无论在这种情况下尝试做什么,html-loader 和 copy-webpack-plugin 都会发生冲突。糟透了。如果您在尝试使用 html-loader 的同一目录中有图像,则所有战争都会爆发。
  • 非常感谢,这正是我所需要的。
  • 关于 #1,interpolate 已被删除,文档没有等效示例:github.com/webpack-contrib/html-loader/blob/…
【解决方案2】:

你可能会笑,但是使用 HTMLWebpackPlugin 提供的默认加载器,你可以对 HTML 部分文件进行字符串替换。

  1. index.html 是 ejs 模板(ejs 是 HTMLWebpackPlugin 中的默认加载器)
  2. file.html 只是一个 html 字符串(通过 html-loader 加载,HTMLWebpackPlugin 也可以默认使用,或者它可能与 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>

这是 file.html,html-loader 导出为字符串。

// file.html 

<h1>${foo}</h1>

【讨论】:

  • 这应该是公认的答案:我还用我自己的答案扩充了这个答案,因为我觉得最好在答案中解决,而不是评论,因为它添加了重要的警告
【解决方案3】:

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'})}

【讨论】:

    【解决方案4】:

    如果你部分使用来自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

    【讨论】:

      【解决方案5】:

      将html-loader 与interpolate 结合使用,您可以通过使用DefinePlugin 从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 中的值。

      【讨论】:

      • 我认为这以最简单的方式回答了这个问题。赞成:-)
      【解决方案6】:

      我觉得上面Potench'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

      【讨论】:

        【解决方案7】:

        您可以自己制作: 在 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) + ') + ';
        	}) + "};";
        
        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-22
          • 2019-08-25
          • 2017-01-22
          • 2017-11-29
          相关资源
          最近更新 更多