Files
Edu/apps/portal-shell/next.config.js
SpecialX 9358372657 feat(portal-shell): add MSW mock layer with production bundle exclusion (P1-5)
MSW v2.7.0 fallback layer covering dashboard/users/exams/grades domains.
NEXT_PUBLIC_MSW=1 enables browser Service Worker + SSR route handler mock
responses without backend. Production build excludes all mock data via
Turbopack resolveAlias redirecting @/mocks to empty stub.

Acceptance: build bundle (client+server) verified clean of mock strings;
typecheck/lint/vitest (231 tests) all pass.
2026-07-22 14:48:30 +08:00

109 lines
3.9 KiB
JavaScript
Raw 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.
/**
* Next.js 配置v2.1 M8 + v0.2 Tailwind v4 + Next 16 Turbopack + P1-4 next-intl + P1-5 MSW
*
* 角色:插件化仪表盘宿主(单 Next.js App Router · 单 Docker
* - output:standalone单容器部署
* - transpilePackages: @edu/* workspace 包
* - 反向代理:/api/v1/* → api-gateway :8080JWT 校验 + 注入 x-user-id/x-user-role
* - GraphQL 查询走 apollo-router :3000M8 验收点,由 Apollo Client 直连)
* - next-intl无 i18n 路由模式locale 由 cookie 决定ARCHITECTURE.md §3.4 V3-A6
* - MSW 兜底层P1-5NEXT_PUBLIC_MSW!=1 时把 @/mocks 与 @/mocks/graphql-data
* 重定向到空 stub确保生产 bundle 不含 mock 数据ARCHITECTURE.md §3.4 V3-A7
*
* Next 16 默认 Turbopack
* - turbopack.resolveExtensions 处理 ESM 包 .js 后缀导入源码 TS 文件的映射
* - webpack 配置保留作为 fallback--webpack flag 时生效)
*
* 关联portal-shell ARCHITECTURE.md §3.4 V3-A6/V3-A7、spec §2、project_rules §3.2
*/
import path from "node:path";
import { fileURLToPath } from "node:url";
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// P1-5MSW 启用开关。生产构建NEXT_PUBLIC_MSW 非等于 "1")时把
// @/mocks 与 @/mocks/graphql-data 重定向到空 stub
// 确保 bundle 不含真实 mock 数据与 msw 包。
// 注意Turbopack resolveAlias 不支持 Windows 绝对路径("windows imports
// are not implemented yet"),故使用 @/mocks/empty 说明符(由 tsconfig
// paths 解析为 src/mocks/empty.ts而非绝对路径。
const MSW_ENABLED = process.env.NEXT_PUBLIC_MSW === "1";
const MOCKS_STUB_SPECIFIER = "@/mocks/empty";
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
output: "standalone",
transpilePackages: [
"@edu/ui-components",
"@edu/ui-tokens",
"@edu/hooks",
"@edu/contracts",
"@edu/shared-ts",
],
experimental: {
serverActions: { bodySizeLimit: "2mb" },
},
// Turbopack 配置Next 16 默认):处理 ESM 包 .js 后缀导入源码 .ts/.tsx 文件
turbopack: {
resolveExtensions: [
".ts",
".tsx",
".js",
".jsx",
".mjs",
".cjs",
".json",
],
// P1-5MSW 关闭时把 @/mocksMswProvider 静态 import
// @/mocks/graphql-dataroute.ts 静态 import重定向到空 stub。
// 使用 @/mocks/empty 说明符作为目标Turbopack 不支持 Windows 绝对路径)。
...(MSW_ENABLED
? {}
: {
resolveAlias: {
"@/mocks": MOCKS_STUB_SPECIFIER,
"@/mocks/graphql-data": MOCKS_STUB_SPECIFIER,
},
}),
},
// Webpack 配置fallback使用 --webpack flag 时生效)
webpack(config) {
config.resolve = config.resolve || {};
config.resolve.extensionAlias = {
...config.resolve.extensionAlias,
".js": [".ts", ".tsx", ".js"],
};
// P1-5MSW 关闭时把 @/mocks 与 @/mocks/graphql-data 重定向到空 stub。
// webpack resolve.alias 支持 exact 匹配($ 后缀)与前缀匹配,
// 这里用 exact 匹配避免误伤其他 @/mocks/xxx 路径(实际只有这两个 import 点)。
if (!MSW_ENABLED) {
config.resolve.alias = {
...config.resolve.alias,
"@/mocks$": MOCKS_STUB_SPECIFIER,
"@/mocks/graphql-data$": MOCKS_STUB_SPECIFIER,
};
}
return config;
},
async rewrites() {
const gateway =
process.env.API_GATEWAY_URL || "http://localhost:8080";
return [
{
source: "/api/v1/:path*",
destination: `${gateway}/api/v1/:path*`,
},
{
source: "/api/auth/:path*",
destination: `${gateway}/api/v1/iam/:path*`,
},
];
},
};
export default withNextIntl(nextConfig);