FastGPT/projects/app/next.config.js
dreamer6680 d7a722a609
add csp and more function for markdown (#4921)
* support html

* html

* add csp

* remove unuse function

---------

Co-authored-by: dreamer6680 <146868355@qq.com>
2025-05-29 17:57:37 +08:00

163 lines
4.6 KiB
JavaScript

const { i18n } = require('./next-i18next.config.js');
const path = require('path');
const fs = require('fs');
const isDev = process.env.NODE_ENV === 'development';
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_URL,
i18n,
output: 'standalone',
reactStrictMode: isDev ? false : true,
compress: true,
headers: async () => {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const csp = `'nonce-${nonce}'`;
const scheme_source = 'data: mediastream: blob: filesystem:';
const NECESSARY_DOMAINS = [
'*.sentry.io',
'http://localhost:*',
'http://127.0.0.1:*',
'https://analytics.google.com',
'googletagmanager.com',
'*.googletagmanager.com',
'https://www.google-analytics.com',
'https://api.github.com'
].join(' ');
return [
{
source: '/chat/(.*)',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-XSS-Protection', value: '1; mode=block' },
{ key: 'Referrer-Policy', value: 'no-referrer' },
{
key: 'Content-Security-Policy',
value: [
`default-src 'self' ${scheme_source} ${NECESSARY_DOMAINS} ${csp}`,
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${csp} ${NECESSARY_DOMAINS}`,
`style-src 'self' 'unsafe-inline' ${csp} ${NECESSARY_DOMAINS}`,
`media-src 'self' http: ${scheme_source} ${NECESSARY_DOMAINS} ${csp}`,
`worker-src 'self' ${csp} ${NECESSARY_DOMAINS} ${scheme_source}`,
`img-src * data: blob:`,
`font-src 'self'`,
`connect-src 'self' wss: https: ${scheme_source} ${NECESSARY_DOMAINS} ${csp}`,
"object-src 'none'",
"form-action 'self'",
"base-uri 'self'",
"frame-src 'self' 'allow-scripts'",
'sandbox allow-scripts allow-same-origin allow-popups allow-forms',
'upgrade-insecure-requests'
].join('; ')
}
]
}
];
},
webpack(config, { isServer, nextRuntime }) {
Object.assign(config.resolve.alias, {
'@mongodb-js/zstd': false,
'@aws-sdk/credential-providers': false,
snappy: false,
aws4: false,
'mongodb-client-encryption': false,
kerberos: false,
'supports-color': false,
'bson-ext': false,
'pg-native': false
});
config.module = {
...config.module,
rules: config.module.rules.concat([
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack']
}
]),
exprContextCritical: false,
unknownContextCritical: false
};
if (!config.externals) {
config.externals = [];
}
if (isServer) {
config.externals.push('@node-rs/jieba');
if (nextRuntime === 'nodejs') {
const oldEntry = config.entry;
config = {
...config,
async entry(...args) {
const entries = await oldEntry(...args);
return {
...entries,
...getWorkerConfig(),
'worker/systemPluginRun': path.resolve(
process.cwd(),
'../../packages/plugins/runtime/worker.ts'
)
};
}
};
}
} else {
config.resolve = {
...config.resolve,
fallback: {
...config.resolve.fallback,
fs: false
}
};
}
config.experiments = {
asyncWebAssembly: true,
layers: true
};
return config;
},
// 需要转译的包
transpilePackages: ['@modelcontextprotocol/sdk', 'ahooks'],
experimental: {
// 优化 Server Components 的构建和运行,避免不必要的客户端打包。
serverComponentsExternalPackages: [
'mongoose',
'pg',
'bullmq',
'@zilliz/milvus2-sdk-node',
'tiktoken'
],
outputFileTracingRoot: path.join(__dirname, '../../'),
instrumentationHook: true
}
};
module.exports = nextConfig;
function getWorkerConfig() {
const result = fs.readdirSync(path.resolve(__dirname, '../../packages/service/worker'));
// 获取所有的目录名
const folderList = result.filter((item) => {
return fs
.statSync(path.resolve(__dirname, '../../packages/service/worker', item))
.isDirectory();
});
const workerConfig = folderList.reduce((acc, item) => {
acc[`worker/${item}`] = path.resolve(
process.cwd(),
`../../packages/service/worker/${item}/index.ts`
);
return acc;
}, {});
return workerConfig;
}