使用HTMLWebpackPlugin与EJS文件

11

我想使用HTMLWebpackPlugin来获取我的index.ejs模板文件,插入我的打包资源,并输出一个最终的index.ejs文件。

这个例子中有一个EJS变量<%= API_URL %>,但是webpack正在解释它。

我如何阻止webpack替换这个变量?

开始 "template":

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Monitor</title>
    <script>
      window.config = {
        API_URL: "<%= API_URL %>"
      }
    </script>
  </head>
  <body>
    <div class="container"></div>
  </body>
</html>

当你尝试运行webpack时:

ERROR in Template execution failed: ReferenceError: API_URL is not defined

期望的index.ejs结果:(已捆绑资产和EJS变量)

Monitor window.config = { API_URL: "<%= API_URL %>" }

webpack.config.js

var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: {
    bundle: './src/index.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
    {
      test: /\.js$/,
      use: 'babel-loader',
      exclude: /node_modules/
    },
    {
      // CSS is imported in app.js.
      test: /\.scss$/,
      use: ExtractTextPlugin.extract({
        fallbackLoader: 'style-loader',
        loader: ["css-loader", "sass-loader"]
      })
    }]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(process.env.NODE_ENV),
        'API_URL': JSON.stringify(process.env.API_URL)
      }
    }),
    new HtmlWebpackPlugin({
      template: 'src/index.ejs',
      inject: true
    }),
    new ExtractTextPlugin("styles.css")
  ],
};
5个回答

6

这是一个非常糟糕的hacky解决方案,我希望有人能够给出真正的答案/理解如何做到这一点。

在您的模板文件(index.ejs)中,可以这样做:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Monitor</title>
    <script>
      window.config = {
        API_URL: "<%= htmlWebpackPlugin.options.API_URL_TEMPLATE_VAR %>"
      }
    </script>
  </head>
  <body>
    <div class="container"></div>
  </body>
</html>

在你的Webpack配置中,做如下更改(相关部分是新的HtmlWebpackPlugin,在其中定义一个变量):
plugins: [
    // Define environment variables that are accessible inside of app javascript.
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }
    }),
    // Adds bundled file links to the index.html
    new HtmlWebpackPlugin({
      // The input file name
      template: 'src/index.prod.ejs',
      // Injects scripts into the <body>
      inject: true,
      // This is so hacky. I inject a string so the built .ejs file has this template var. Lets us set api_url when server is started instead of at bundle time.
      API_URL_TEMPLATE_VAR: '<%= process.env.API_URL %>',
      // The output file name
      filename: 'index.ejs'
    }),
    new ExtractTextPlugin("styles.css")
  ],

因为我定义了API_URL_TEMPLATE_VAR,当html-webpack-plugin对其进行评估时,它会将<%= process.env.API_URL %>打印到最终模板中。
有些取巧,但是可行的方法。不接受我自己的答案/等待更好的答案。

1
点赞,因为虽然有些hacky,但似乎是唯一能回答这个问题并解决问题的解决方案。我搜索了很多,这是我找到的唯一答案。 - MadOgre
这样做可以,但是ejs中的if怎么办?你将不得不将所有的逻辑放在webpack.config.js中... - gilamran
对我来说,我所需要的只是 filename: 'index.ejs',然后使用 raw-loader 加载它,这会导致 Webpack 将文件按原样加载。 - ihodonald

0

我遇到了相同的问题,将变量定义加上引号(")解决了它:

在你的情况下:

new webpack.DefinePlugin({
  'process.env': {
    'NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    'API_URL': '"' + JSON.stringify(process.env.API_URL) + '"'
  }
})
...

0
HTMLWebpackPlugin使用lodash.template来实现这一点,虽然不是很容易,但可以更改默认分隔符为<?,以便您可以在前端使用<%分隔符。但是,如果您在前端使用ejs包,那么更改分隔符会更容易,并保持webpack的正常分隔符。 ejs:
<div>
  <%=SOME_WEBPACK_VAR%>
  <br />
  <?=SOME_EJS_VAR%>
</div>

javascript:

ejs.render(yourHtml, {SOME_EJS_VAR: 'foo'}, {delimiter: '?'});

0
据我理解EJS,你的问题可以通过使用<%%=来解决,如EJS文档所述,因此将你的代码替换为:API_URL: "<%%= API_URL %>"

-1
如果你想让Webpack在构建时忽略你的文件,你可以在文件路径前面加上raw-loader
new HtmlWebpackPlugin({
    inject: true,
    filename: "index.ejs",
    template: "!!raw-loader!" + 'src/index.ejs',
}),

如果您想直接从 Webpack 将变量注入模板中,您可以使用名为 react-dev-utils 的依赖项,它具有非常方便的插件:

new InterpolateHtmlPlugin(HtmlWebpackPlugin, {
   PUBLIC_URL: publicUrl,
  // You can pass any key-value pairs, this was just an example.
  // WHATEVER: 42 will replace %WHATEVER% with 42 in index.html.
}),

我自己没有尝试过使用ejs模板,但我认为它应该可以工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接