feat(P01): 迁移 Taro 小程序项目代码

- 迁移前端源码 (src/)
- 迁移后端服务 (server/)
- 迁移配置文件 (package.json, tsconfig.json 等)
- 更新需求概要文档
- 更新架构设计文档
- 更新接口定义文档
- 更新环境配置文档
- 创建测试目录结构和配置

项目技术栈:
- Taro 4.1.9 (跨端框架)
- React 18
- TypeScript
- NestJS (后端)
- Tailwind CSS 4
- shadcn/ui 组件库
This commit is contained in:
Dev AI
2026-05-22 16:25:05 +08:00
parent 00ce240c01
commit fb348f3740
106 changed files with 13015 additions and 182 deletions
+9
View File
@@ -0,0 +1,9 @@
import type { UserConfigExport } from "@tarojs/cli"
export default {
mini: {
debugReact: true,
},
h5: {}
} satisfies UserConfigExport<'vite'>
+238
View File
@@ -0,0 +1,238 @@
import fs from 'node:fs';
import path from 'node:path';
import tailwindcss from '@tailwindcss/postcss';
import { UnifiedViteWeappTailwindcssPlugin } from 'weapp-tailwindcss/vite';
import { defineConfig, type UserConfigExport } from '@tarojs/cli';
import type { PluginItem } from '@tarojs/taro/types/compile/config/project';
import dotenv from 'dotenv';
import devConfig from './dev';
import prodConfig from './prod';
import pkg from '../package.json';
dotenv.config({ path: path.resolve(__dirname, '../.env.local') });
const generateTTProjectConfig = (outputRoot: string) => {
const config = {
miniprogramRoot: './',
projectname: 'coze-mini-program',
appid: process.env.TARO_APP_TT_APPID || '',
setting: {
urlCheck: false,
es6: false,
postcss: false,
minified: false,
},
};
const outputDir = path.resolve(__dirname, '..', outputRoot);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
fs.writeFileSync(
path.resolve(outputDir, 'project.config.json'),
JSON.stringify(config, null, 2),
);
};
// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
export default defineConfig<'vite'>(async (merge, _env) => {
const outputRootMap: Record<string, string> = {
weapp: 'dist',
tt: 'dist-tt',
h5: 'dist-web',
};
const defaultOutputRoot = outputRootMap[process.env.TARO_ENV || ''] || 'dist';
const outputRoot = process.env.OUTPUT_ROOT?.trim() || defaultOutputRoot;
const isH5 = process.env.TARO_ENV === 'h5';
const buildMiniCIPluginConfig = () => {
const hasWeappConfig = !!process.env.TARO_APP_WEAPP_APPID;
const hasTTConfig = !!process.env.TARO_APP_TT_EMAIL;
if (!hasWeappConfig && !hasTTConfig) {
return [];
}
const miniCIConfig: Record<string, any> = {
version: pkg.version,
desc: pkg.description,
};
if (hasWeappConfig) {
miniCIConfig.weapp = {
appid: process.env.TARO_APP_WEAPP_APPID,
privateKeyPath: 'key/private.appid.key',
};
}
if (hasTTConfig) {
miniCIConfig.tt = {
email: process.env.TARO_APP_TT_EMAIL,
password: process.env.TARO_APP_TT_PASSWORD,
setting: {
skipDomainCheck: true,
},
};
}
return [['@tarojs/plugin-mini-ci', miniCIConfig]] as PluginItem[];
};
const baseConfig: UserConfigExport<'vite'> = {
projectName: 'coze-mini-program',
date: '2026-1-13',
alias: {
'@': path.resolve(__dirname, '..', 'src'),
},
designWidth: 750,
deviceRatio: {
640: 2.34 / 2,
750: 1,
375: 2,
828: 1.81 / 2,
},
sourceRoot: 'src',
outputRoot,
plugins: ['@tarojs/plugin-generator', ...buildMiniCIPluginConfig()],
defineConstants: {
PROJECT_DOMAIN: JSON.stringify(
process.env.PROJECT_DOMAIN ||
process.env.COZE_PROJECT_DOMAIN_DEFAULT ||
'',
),
TARO_ENV: JSON.stringify(process.env.TARO_ENV),
},
copy: {
patterns: [],
options: {},
},
...(process.env.TARO_ENV === 'tt' && {
tt: {
appid: process.env.TARO_APP_TT_APPID,
projectName: 'coze-mini-program',
},
}),
jsMinimizer: 'esbuild',
framework: 'react',
compiler: {
type: 'vite',
vitePlugins: [
{
name: 'postcss-config-loader-plugin',
config(config) {
// 通过 postcss 配置注册 tailwindcss 插件
if (typeof config.css?.postcss === 'object') {
config.css?.postcss.plugins?.unshift(tailwindcss());
}
},
},
{
name: 'hmr-config-plugin',
config() {
if (!process.env.PROJECT_DOMAIN) {
return;
}
return {
server: {
hmr: {
overlay: true,
path: '/hot/vite-hmr',
port: 6000,
clientPort: 443,
timeout: 30000,
},
},
};
},
},
...(isH5
? []
: [
UnifiedViteWeappTailwindcssPlugin({
rem2rpx: true,
cssEntries: [path.resolve(__dirname, '../src/app.css')],
}),
]),
...(process.env.TARO_ENV === 'tt'
? [
{
name: 'generate-tt-project-config',
closeBundle() {
generateTTProjectConfig(outputRoot);
},
},
]
: []),
],
},
mini: {
postcss: {
pxtransform: {
enable: true,
config: {},
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
},
h5: {
publicPath: './',
staticDirectory: 'static',
router: {
mode: 'hash',
},
devServer: {
port: 5000,
host: '0.0.0.0',
open: false,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
},
},
},
miniCssExtractPluginOption: {
ignoreOrder: true,
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[chunkhash].css',
},
postcss: {
autoprefixer: {
enable: true,
config: {},
},
pxtransform: {
enable: true,
config: {
platform: 'h5',
},
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
},
rn: {
appName: 'coze-mini-program',
postcss: {
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
},
},
},
};
process.env.BROWSERSLIST_ENV = process.env.NODE_ENV;
if (process.env.NODE_ENV === 'development') {
// 本地开发构建配置(不混淆压缩)
return merge({}, baseConfig, devConfig);
}
// 生产构建配置(默认开启压缩混淆等)
return merge({}, baseConfig, prodConfig);
});
+34
View File
@@ -0,0 +1,34 @@
import type { UserConfigExport } from '@tarojs/cli';
export default {
mini: {},
h5: {
legacy: false,
/**
* WebpackChain 插件配置
* @docs https://github.com/neutrinojs/webpack-chain
*/
// webpackChain (chain) {
// /**
// * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
// * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
// */
// chain.plugin('analyzer')
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
// /**
// * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
// * @docs https://github.com/chrisvfritz/prerender-spa-plugin
// */
// const path = require('path')
// const Prerender = require('prerender-spa-plugin')
// const staticDir = path.join(__dirname, '..', 'dist')
// chain
// .plugin('prerender')
// .use(new Prerender({
// staticDir,
// routes: [ '/pages/index/index' ],
// postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
// }))
// }
},
} satisfies UserConfigExport<'vite'>;