如何配置 vue 应用程序(使用 vue-cli)以将 nonce 属性添加到生成的脚本标签中?

问题描述 投票:0回答:3

我有一个使用 vue-cli 编译的 vue 应用程序。我的 vue.config.js 文件如下所示:

'use strict';

module.exports = {
  publicPath: `${process.env.CDN_URL || ''}/dist/`,
  lintOnSave: true,
  transpileDependencies: [],
  outputDir: '.tmp/dist',
  pages: {
    navigator: {
      entry: 'vue/home/main.ts',
      template: 'views/home/index.ejs',
      // Will output to dist/views/home/index.ejs
      filename: 'views/home/index.ejs',
    },
  },
  chainWebpack(config) {
    // Override the default loader for html-webpack-plugin so that it does not fallback to ejs-loader.
    // ejs-loader will use ejs syntax against the template file to inject dynamic values before html-webpack-plugin runs
    config.module
      .rule('ejs')
      .test(/\.ejs$/)
      .use('html')
      .loader('html-loader');
  },
};

我想让 webpack 为它生成的每个脚本标签添加

nonce="<%= nonce %>"
。我看到 webpack 有一个
__webpack_nonce__
变量,但我尝试在 vue.config.js 文件的许多部分中设置它。我尝试将其添加到 chainWebpack() 和 configWebpack() 中。我尝试将其添加到 vue/home/main.ts 文件中。似乎什么都不起作用。如何将随机数属性添加到脚本标签中?

这是 vue 2.6.x 和 vue cli 4.5.x

javascript vue.js webpack vuejs2
3个回答
5
投票

我最终编写了自己的 webpack 插件,因为我的用例比 script-ext-html-webpack-plugin 可以支持的要复杂一些。我需要

${nonce}
作为标题标签,
<%= nonce %>
作为正文标签。我的插件代码是一个简单的并且基于 @Sphinx 提到的 script-ext-html-webpack-plugin

const HtmlWebpackPlugin = require('html-webpack-plugin');

class AddNonceToScriptTagsWebpackPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {
      const alterAssetTagGroups = compilation.hooks.htmlWebpackPluginAlterAssetTags || HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups;
      alterAssetTagGroups.tap(this.constructor.name, (data) => {
        data.head = this._addNonceAttribute(data.head || []);
        data.body = this._addNonceAttribute(data.body || []);

        return data;
      });
    });
  }

  _addNonceAttribute(tags) {
    return tags.map((tag) => {
      if (tag.tagName === 'script') {
        tag.attributes = tag.attributes || {};
        tag.attributes.nonce = '<%= nonce %>';
      } else if (tag.tagName === 'link' && tag.attributes && tag.attributes.as === 'script') {
        tag.attributes = tag.attributes || {};
        // eslint-disable-next-line no-template-curly-in-string
        tag.attributes.nonce = '${nonce}';
      }

      return tag;
    });
  }
}

更新后的 vue.config.js 文件如下所示:

'use strict';

module.exports = {
  publicPath: `${process.env.CDN_URL || ''}/dist/`,
  lintOnSave: true,
  transpileDependencies: [],
  outputDir: '.tmp/dist',
  pages: {
    navigator: {
      entry: 'vue/home/main.ts',
      template: 'views/home/index.ejs',
      // Will output to dist/views/home/index.ejs
      filename: 'views/home/index.ejs',
    },
  },
  configureWebpack: {
    plugins: [
      new AddNonceToScriptTagsWebpackPlugin(),
    ],
  },
  chainWebpack(config) {
    // Override the default loader for html-webpack-plugin so that it does not fallback to ejs-loader.
    // ejs-loader will use ejs syntax against the template file to inject dynamic values before html-webpack-plugin runs
    config.module
      .rule('ejs')
      .test(/\.ejs$/)
      .use('html')
      .loader('html-loader');
  },
};

2
投票

一种解决方案应该是将 script-ext-html-webpack-plugin 添加到

webpack.prod.conf
文件(或您自己的 webpack 配置文件)的插件列表中。

new ScriptExtHtmlWebpackPlugin({
  custom: {
    test: /\.js$/, // adjust this regex based on your demand
    attribute: 'nonce',
    value: '<%= nonce %>'
  }
}),

0
投票

3 年了,但我仍然在这里找到最好的答案

我根据@Jim Geurts 解决方案进行了一些更改和澄清

在 vue.config.js 添加

class AddNonceToScriptTagsWebpackPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {
      const alterAssetTagGroups = compilation.hooks.htmlWebpackPluginAlterAssetTags || HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups;
      alterAssetTagGroups.tap(this.constructor.name, (data) => {
        data.head = this._addNonceAttribute(data.head || []);
        data.body = this._addNonceAttribute(data.body || []);

        return data;
      });
    });
  }

  _addNonceAttribute(tags) {
    return tags.map((tag) => {
      if (tag.tagName === 'script' || tag.tagName === 'link' || tag.tagName === 'style') {
        tag.attributes = tag.attributes || {};
        tag.attributes.nonce = 'YOUR-SECRET-NONCE';
      }

      return tag;
    });
  }
}

但是 Jim Code 或我的会将 HTML 输出 (index.html) 最小化为内联(删除空格/输入)。解决方案是自定义 HtmlWebpackPlugin 配置

  configureWebpack: {
    plugins: [
      new HtmlWebpackPlugin({
        template: 'public/index.html',
        inject: 'body', // Inject scripts into body
        minify: false, // Disable minification
      }),
      new AddNonceToScriptTagsWebpackPlugin(),
    ]
  }
© www.soinside.com 2019 - 2024. All rights reserved.