使用Webpack与React开发Chrome扩展时热重载出现unsafe-eval CSP错误的解决方案
解决Chrome扩展Manifest V3 + webpack-dev-server热重载的unsafe-eval CSP错误
这个问题我之前开发Manifest V3扩展时也碰到过,核心矛盾是webpack开发模式下默认用eval生成模块代码,但Manifest V3的默认内容安全策略(CSP)严格禁止unsafe-eval,而生产构建时webpack会自动切换到不依赖eval的编译逻辑,所以生产环境能正常运行。下面给你两种实用的解决方案:
方法一:修改webpack devtool配置,避免使用eval
最简单的方式是调整webpack的devtool选项,选择不包含eval的source map类型,彻底规避CSP限制。
在你的webpack.config.ts中添加devtool配置:
module.exports = { // ... 其他已有配置 devtool: 'inline-cheap-module-source-map', // 开发阶段推荐,兼顾编译速度和调试体验 // ... };
可选的替代值还有:
source-map:生成独立的source map文件,编译速度稍慢但调试信息最完整cheap-module-source-map:比inline-cheap-module-source-map少了行内映射,编译速度更快一点
这些选项都不会生成包含eval的代码,完美适配Manifest V3的安全规则,同时保留开发所需的source map调试能力。
方法二:开发模式下临时调整Manifest的CSP(仅用于开发)
如果需要保留eval相关的devtool(比如追求极致的开发编译速度),可以在开发时给manifest临时添加允许unsafe-eval的CSP规则,但绝对不能在生产环境使用(Chrome商店会直接拒绝审核)。
我们可以通过webpack的CopyPlugin动态修改manifest.json,只在开发模式下注入宽松的CSP规则:
修改webpack.config.ts为函数形式,根据mode判断环境:
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); module.exports = (env, argv) => { const isDevelopment = argv.mode === "development"; return { entry: { index: "./extension/index.tsx", background: "./extension/background.ts", }, output: { filename: "[name].js", path: path.resolve(__dirname, "dist"), clean: true, }, module: { rules: [ { test: /\.tsx?$/, use: "ts-loader" }, { test: /\.css$/, use: ["style-loader", "css-loader", "postcss-loader"] }, ], }, plugins: [ new HtmlWebpackPlugin({ template: "./assets/index.html", filename: "index.html", chunks: ["index"], }), new CopyPlugin({ patterns: [ { from: "extension/manifest.json", to: "[name][ext]", transform(content) { if (!isDevelopment) return content; // 开发模式下添加允许unsafe-eval的CSP const manifest = JSON.parse(content.toString()); manifest.content_security_policy = { extension_pages: "script-src 'self' 'unsafe-eval'; object-src 'self';", }; return JSON.stringify(manifest, null, 2); }, }, { from: "assets/images", to: "images/" }, ], }), new ForkTsCheckerWebpackPlugin(), ], devServer: { devMiddleware: { writeToDisk: true }, }, optimization: { minimizer: [new TerserPlugin({ extractComments: false })], }, // 可选:如果用方法一,在这里添加devtool // devtool: 'inline-cheap-module-source-map', }; };
这样配置后,开发模式下生成的manifest会自动带上允许unsafe-eval的CSP,生产模式则保持原有的安全规则。
额外注意事项
- 你的
devServer中writeToDisk: true的配置是正确的,因为Chrome扩展需要读取本地磁盘上的文件,不能用webpack-dev-server的内存文件系统。 - 如果要启用模块热替换(HMR),还需要额外配置
HotModuleReplacementPlugin,但上述两种方法已经能解决基础的自动刷新热重载问题。
内容的提问来源于stack exchange,提问作者ronaldo_w
相关产品推荐
相关产品推荐

