web-dev-qa-db-fra.com

Comment puis-je fournir des paramètres pour l'interpolation html-loader webpack?

Dans la documentation html-loader il y a cet exemple

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>

D'où vient la "liste"? Comment puis-je fournir des paramètres à l'étendue d'interpolation?

Je voudrais faire quelque chose comme template-string-loader fait:

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

puis dans file.html

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

Mais ça ne marche pas. J'ai essayé de mélanger le template-string-loader avec le html-loader mais cela ne fonctionne pas. Je n'ai pu utiliser que le template-string-loader mais les images dans le HTML ne sont pas transformées par webpack.

Des idées? Je vous remercie

25
Patrick Lafrance

Solution 1

J'ai trouvé une autre solution en utilisant html-loader avec l'option interpolate.

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

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

Et puis dans la page html, vous pouvez importer des variables partielles html et 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>

Le seul inconvénient est que vous ne pouvez pas importer d'autres variables de HtmlWebpackPlugin comme ceci <%= htmlWebpackPlugin.options.title %> (au moins je ne trouve pas de moyen de les importer) mais pour moi ce n'est pas un problème, écrivez simplement le titre dans votre html ou utilisez un fichier javascript séparé pour gérer les variables.

Solution 2

Ancienne réponse

Je ne sais pas si c'est la bonne solution pour vous, mais je vais partager mon flux de travail (testé dans Webpack 3).

Au lieu de html-loader vous pouvez utiliser ce plugin github.com/bazilio91/ejs-compiled-loader :

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

Change ton .html fichiers dans .ejs et votre HtmlWebpackPlugin pour pointer vers la droite .ejs modèle:

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

Vous pouvez importer des partiels, des variables et des actifs dans .ejs des dossiers:

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>

Remarque: lorsque vous incluez un partiel, le chemin doit être relatif à la racine de votre projet.

16
pldg

moustache-chargeur a fait le travail pour moi:

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

Ensuite, dans votre modèle, vous pouvez utiliser {{foo}}, et même insérer d'autres modèles

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

Vous pourriez rire, mais en utilisant les chargeurs par défaut fournis avec HTMLWebpackPlugin, vous pouvez effectuer un remplacement de chaîne sur le fichier HTML partiel.

  1. index.html est le modèle ejs (ejs est le chargeur par défaut dans HTMLWebpackPlugin)
  2. file.html est juste une chaîne html (chargée via html-loader également disponible par défaut avec HTMLWebpackPlugin ou peut-être vient-elle avec webpack?)

Installer

Utilisez simplement le modèle ejs par défaut fourni dans HTMLWebpackPlugin

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

Voici mon fichier ejs de niveau supérieur

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

Voici file.html, qui html-loader exporte sous forme de chaîne.

// file.html 

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

si vous utilisez le moteur de modèle de htmlWebpackPlugin en partie, vous pouvez utiliser comme ceci:

  <!-- 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,
      }),
    ],
  }

avoir besoin npm i ejs-loader

1
Nermo

En utilisant html-loader Avec interpolate, vous pouvez importer des variables depuis votre webpack.config.js En utilisant DefinePlugin.

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

Les interpolations de html-loader Acceptent toute expression JavaScript, mais la portée dans laquelle ces expressions sont évaluées n'est remplie par aucune de vos options de configuration par défaut. DefinePlugin ajoute des valeurs à cette portée globale. EnvironmentPlugin peut également être utilisé pour remplir des valeurs dans process.env.

1
NReilingh

Vous pouvez le faire vous-même: dans le dossier du plugin html-loader (dans index.js), remplacez le code par ce

/*
        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) + ') + ';
        }) + "};";

}

Je pense que Potench's 's answer ci-dessus devrait être accepté, mais il est accompagné d'une mise en garde:

Avertissement: la réponse remplace htmlWebpackPlugin.options objet par défaut. Suggérer d'augmenter, pas de remplacer

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

Source (s): 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