webpack引入fontawesome.js触发CSP违规解决方案咨询
问题场景
项目通过webpack集成Font Awesome时出现CSP违规报错:
- 已在
app.js中添加引入import '@fortawesome/fontawesome-free/js/fontawesome.js',同时在main.css中添加@import '@fortawesome/fontawesome-free/scss/fontawesome'; - 浏览器加载应用时抛出错误:
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-ixVUGs3ai0rMA0pgIVBN0KVlYbQip7/5SGmnUwJPNqE='), or a nonce ('nonce-...') is required to enable inline execution.
- 报错定位到fontawesome.js中动态插入内联样式的逻辑:
function insertCss(css) { if (!css || !IS_DOM) { return; } var style = DOCUMENT.createElement('style'); style.setAttribute('type', 'text/css'); style.innerHTML = css; var headChildren = DOCUMENT.head.childNodes; var beforeChild = null; for (var i = headChildren.length - 1; i > -1; i--) { var child = headChildren[i]; var tagName = (child.tagName || '').toUpperCase(); if (['STYLE', 'LINK'].indexOf(tagName) > -1) { beforeChild = child; } } DOCUMENT.head.insertBefore(style, beforeChild); return css; }
- 约束条件:不能在CSP中添加
unsafe-inline规则,也不能硬编码哈希值,现有webpack配置如下:
const TerserPlugin = require("terser-webpack-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = { context: __dirname + '/src', resolve: { extensions: ['.js'] }, entry: { app: './js/app.js', 'app.min': './js/app.js' }, output: { path: __dirname + '/../dist/bank', filename: './js/[name].js', publicPath: '' }, optimization: { minimize: true, minimizer: [ new TerserPlugin({ include: /\.min\.js$/ }), new CssMinimizerPlugin({ include: /\.min\.css$/ }) ], }, plugins: [ new MiniCssExtractPlugin({ filename: './css/[name].css', }), ], module: { rules: [ { test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] }, { test: /\.(png|jp(e*)g|eot|svg|ttf|woff|woff2)$/, use: [{ loader: 'url-loader', options: { esModule: false } }] }, { test: /\.(html)$/, use: [{ loader: 'html-loader', options: { minimize: true } }] } ] }, };
根本原因
- 引入方式冲突:同时引入Font Awesome的JS运行时和SCSS样式,JS运行时默认会在客户端动态创建内联
<style>标签注入样式,直接触发CSP内联样式拦截。 - webpack配置缺陷:样式规则的匹配正则为
/\.css$/i,仅能识别.css后缀文件,无法处理.scss后缀的Font Awesome样式文件,导致样式没有被提取为独立外部CSS文件。
解决方案
按以下步骤调整即可,全程不需要修改CSP规则:
- 移除冲突的JS引入
删除app.js中的import '@fortawesome/fontawesome-free/js/fontawesome.js',这行代码是触发动态插入内联样式的直接来源。 - 补全SCSS引入内容
在全局样式入口中补全对应图标集的引入,确保所有图标样式都通过SCSS入口导入:
// 核心基础样式 @import '@fortawesome/fontawesome-free/scss/fontawesome'; // 按需引入使用到的图标集,常用的有实心、常规、品牌图标三类 @import '@fortawesome/fontawesome-free/scss/solid'; @import '@fortawesome/fontawesome-free/scss/regular'; @import '@fortawesome/fontawesome-free/scss/brands';
- 修正webpack样式loader匹配规则
将样式规则的test正则修改为/\.s?css$/i,同时匹配.css和.scss后缀文件,保证SCSS文件能被正常编译、通过MiniCssExtractPlugin提取为独立的外部CSS文件,最终通过<link>标签加载,完全符合style-src 'self'的CSP要求:
{ test: /\.s?css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] }
- (可选,需要使用Font Awesome JS能力时配置)
如果需要用到JS驱动的图标特性(比如动态图标替换、自动渲染),不要引入全量的fontawesome.js,改为引入SVG核心模块并关闭自动注入CSS的配置:
import { dom, config } from '@fortawesome/fontawesome-svg-core'; // 关闭自动插入内联CSS逻辑 config.autoAddCss = false; // 引入需要使用的图标集 import '@fortawesome/free-solid-svg-icons'; import '@fortawesome/free-regular-svg-icons'; import '@fortawesome/free-brands-svg-icons'; // 启动图标自动渲染 dom.watch();
该配置下所有样式仍然通过SCSS入口编译提取为外部CSS,不会产生内联样式,同样满足CSP约束。
内容的提问来源于stack exchange,提问作者Chamila Wijayarathna
相关产品推荐
相关产品推荐

