Files
eSIM-Tools/webpack.config.js
Abner 404fc88332 🧹 chore(cleanup): 移除未使用的模块化版本并修复文档问题
- 删除 src/js/modules/giffgaff/ 和 src/js/modules/simyo/ 目录(未完成的重构尝试)
- 移除 webpack.config.js 中未使用的别名配置和入口文件
- 修复文档错链:移除对不存在的 DEVELOPMENT_GUIDE.md 引用
- 修复文档错链:将 CORS_SOLUTION.md 中的 simyo_proxy_server.js 更正为 server.js
- 更新 tests/CLAUDE.md 中 Jest 版本为 30.3.0
- 移除 src/simyo/MODULE_ARCHITECTURE.md 中过时的重构计划
- 精简 docs/reference/ 下的技术文档,移除与根 README 重复的内容
- 删除已弃用的 .serena/ 工具目录
- 更新根 CLAUDE.md 反映清理后的新目录结构
- 删除 3 个引用已删除模块的测试文件

所有测试通过,构建成功,质量检查和安全检查均通过。
2026-05-18 21:58:42 +08:00

232 lines
6.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { GenerateSW } = require('workbox-webpack-plugin');
const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');
// Sentry 配置(仅生产环境且配置完整时启用)
const sentryAuthToken = process.env.SENTRY_AUTH_TOKEN;
const sentryOrg = process.env.SENTRY_ORG;
const sentryProject = process.env.SENTRY_PROJECT;
const isSentryEnabled = sentryAuthToken && sentryOrg && sentryProject && process.env.NODE_ENV === 'production';
module.exports = {
entry: {
main: './src/js/main.js',
footer: './src/js/bootstrap-footer.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash].js',
clean: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}
]
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log', 'console.info', 'console.debug'], // Remove specific console methods
passes: 2 // Run compression twice for better results
},
mangle: {
safari10: true // Fix Safari 10 loop iterator bug
}
},
parallel: true,
extractComments: false // Don't create separate license files
})
],
splitChunks: {
chunks: 'all',
maxInitialRequests: 5,
maxAsyncRequests: 5,
minSize: 10000, // 10KB minimum
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true
},
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
name: 'common'
}
}
},
runtimeChunk: {
name: 'runtime' // Extract webpack runtime for better caching
},
moduleIds: 'deterministic', // Stable module IDs for better long-term caching
chunkIds: 'deterministic'
},
plugins: [
new webpack.DefinePlugin({
'process.env.ACCESS_KEY': JSON.stringify(process.env.ACCESS_KEY || ''),
'process.env.TURNSTILE_SITE_KEY': JSON.stringify(process.env.TURNSTILE_SITE_KEY || ''),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN || ''),
'process.env.SENTRY_ENVIRONMENT': JSON.stringify(process.env.SENTRY_ENVIRONMENT || 'production'),
// SENTRY_RELEASE: 优先使用环境变量,其次使用 Netlify COMMIT_REF最后使用 package.json 版本
'process.env.SENTRY_RELEASE': JSON.stringify(
process.env.SENTRY_RELEASE ||
(process.env.COMMIT_REF ? `esim-tools@${process.env.COMMIT_REF.slice(0, 7)}` : null) ||
`esim-tools@${require('./package.json').version}`
),
}),
new CompressionPlugin({
test: /\.(js|css|html|svg)$/,
algorithm: 'gzip',
threshold: 10240, // Only compress files > 10KB
minRatio: 0.8,
deleteOriginalAssets: false
}),
// Add Brotli compression for better compression ratio
new CompressionPlugin({
filename: '[path][base].br',
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
compressionOptions: {
params: {
[require('zlib').constants.BROTLI_PARAM_QUALITY]: 11
}
},
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false
}),
new GenerateSW({
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
cleanupOutdatedCaches: true,
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5MB limit
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.qrserver\.com/,
handler: 'CacheFirst',
options: {
cacheName: 'qr-cache',
expiration: {
maxEntries: 50,
maxAgeSeconds: 24 * 60 * 60 // 24 hours
},
cacheableResponse: {
statuses: [0, 200]
}
}
},
{
urlPattern: /^https:\/\/qrcode\.show/,
handler: 'CacheFirst',
options: {
cacheName: 'qr-cache',
expiration: {
maxEntries: 50,
maxAgeSeconds: 24 * 60 * 60
},
cacheableResponse: {
statuses: [0, 200]
}
}
},
{
urlPattern: /^https:\/\/api\.giffgaff\.com/,
handler: 'NetworkFirst',
options: {
cacheName: 'giffgaff-api',
expiration: {
maxEntries: 100,
maxAgeSeconds: 5 * 60 // 5 minutes
},
networkTimeoutSeconds: 10,
cacheableResponse: {
statuses: [0, 200]
}
}
},
{
urlPattern: /^https:\/\/appapi\.simyo\.nl/,
handler: 'NetworkFirst',
options: {
cacheName: 'simyo-api',
expiration: {
maxEntries: 100,
maxAgeSeconds: 5 * 60 // 5 minutes
},
networkTimeoutSeconds: 10,
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}),
// Sentry Source Maps 上传(仅生产环境且配置完整时启用)
...(isSentryEnabled ? [sentryWebpackPlugin({
authToken: sentryAuthToken,
org: sentryOrg,
project: sentryProject,
release: {
name: process.env.SENTRY_RELEASE ||
(process.env.COMMIT_REF ? `esim-tools@${process.env.COMMIT_REF.slice(0, 7)}` : null) ||
`esim-tools@${require('./package.json').version}`,
// 自动关联 Git commits需要在 Git 仓库中运行)
setCommits: {
auto: true,
ignoreMissing: true
}
},
sourcemaps: {
// 上传 dist 目录下的 source maps
assets: './dist/**/*.js.map',
// 上传后删除本地 source maps安全考虑
deleteFilesAfterUpload: './dist/**/*.js.map'
},
// 静默模式,减少构建日志
silent: false,
errorHandler: (err) => {
console.warn('[Sentry] Source maps upload failed:', err.message);
// 不阻止构建
}
})] : [])
],
resolve: {
extensions: ['.js', '.css']
},
performance: {
hints: 'warning',
maxEntrypointSize: 512000, // 500KB
maxAssetSize: 512000
},
devtool: 'source-map'
};