| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- import { spawn } from 'child_process'
- import dotenv from 'dotenv'
- import { existsSync, readFileSync, writeFileSync } from 'fs'
- import { applyEdits, modify } from 'jsonc-parser'
- import path from 'path'
- type TargetEnvironment = 'luoxin' | 'pre' | 'prod'
- interface EnvironmentConfig {
- appid: string
- baseApi: string
- envFile: string
- label: string
- viteMode: string
- viteModeValue: string
- }
- const ROOT_DIR = path.resolve(__dirname, '..')
- const MANIFEST_PATH = path.resolve(ROOT_DIR, 'src/manifest.json')
- const UNI_CLI_PATH = path.resolve(ROOT_DIR, 'node_modules/@dcloudio/vite-plugin-uni/bin/uni.js')
- const BUILD_OUTPUT_DIR = path.resolve(ROOT_DIR, 'dist/build/mp-weixin')
- const ORIGINAL_APPID = 'wxd03398e1bff2b241'
- const LUOXIN_APPID = 'wx2a5a7f417981f250'
- const ENVIRONMENTS: Record<TargetEnvironment, EnvironmentConfig> = {
- luoxin: {
- appid: LUOXIN_APPID,
- baseApi: 'https://luoxin.yaoyi.net',
- envFile: '.env.production_LUOXIN',
- label: '罗欣',
- viteMode: 'production_LUOXIN',
- viteModeValue: 'production_luoxin',
- },
- pre: {
- appid: ORIGINAL_APPID,
- baseApi: 'https://preapi.yaoyi.net',
- envFile: '.env.pre',
- label: '预发布',
- viteMode: 'pre',
- viteModeValue: 'production_pre',
- },
- prod: {
- appid: ORIGINAL_APPID,
- baseApi: 'https://api.yaoyi.net',
- envFile: '.env.production',
- label: '正式',
- viteMode: 'production',
- viteModeValue: 'production',
- },
- }
- const TARGETS: TargetEnvironment[] = ['luoxin', 'pre', 'prod']
- const fail = (message: string): never => {
- throw new Error(message)
- }
- const parseTarget = (value: string | undefined): TargetEnvironment => {
- const target = TARGETS.find((item) => item === value)
- if (!target) {
- throw new Error(`环境必须是:${TARGETS.join(' / ')}`)
- }
- return target
- }
- const loadEnvironment = (target: TargetEnvironment): NodeJS.ProcessEnv => {
- const config = ENVIRONMENTS[target]
- const envPath = path.resolve(ROOT_DIR, config.envFile)
- if (!existsSync(envPath)) {
- fail(`环境文件不存在:${config.envFile}`)
- }
- const parsedEnv = dotenv.parse(readFileSync(envPath, 'utf8'))
- const expectedValues: Record<string, string> = {
- VITE_BASE_API: config.baseApi,
- VITE_MODE: config.viteModeValue,
- VITE_WX_APPID: config.appid,
- }
- for (const [key, expectedValue] of Object.entries(expectedValues)) {
- if (parsedEnv[key] !== expectedValue) {
- fail(
- `${config.envFile} 中的 ${key} 配置错误:期望 ${expectedValue},实际 ${parsedEnv[key] || '未配置'}`
- )
- }
- }
- return {
- ...process.env,
- ...parsedEnv,
- }
- }
- const injectManifestAppid = (manifestSource: string, appid: string): string => {
- const edits = modify(manifestSource, ['mp-weixin', 'appid'], appid, {
- formattingOptions: {
- insertSpaces: true,
- tabSize: 2,
- },
- })
- return applyEdits(manifestSource, edits)
- }
- const runUniBuild = async (
- target: TargetEnvironment,
- processEnv: NodeJS.ProcessEnv
- ): Promise<void> => {
- const config = ENVIRONMENTS[target]
- await new Promise<void>((resolve, reject) => {
- const childProcess = spawn(
- process.execPath,
- [UNI_CLI_PATH, 'build', '-p', 'mp-weixin', '--mode', config.viteMode],
- {
- cwd: ROOT_DIR,
- env: processEnv,
- stdio: 'inherit',
- }
- )
- childProcess.once('error', reject)
- childProcess.once('exit', (code, signal) => {
- if (code === 0) {
- resolve()
- return
- }
- reject(
- new Error(
- signal ? `uni-app 进程被信号 ${signal} 终止` : `uni-app 进程退出,错误码:${code}`
- )
- )
- })
- })
- }
- const validateBuildOutput = (expectedAppid: string): void => {
- const projectConfigPath = path.resolve(BUILD_OUTPUT_DIR, 'project.config.json')
- if (!existsSync(projectConfigPath)) {
- fail(`构建产物不存在:${projectConfigPath}`)
- }
- const projectConfig = JSON.parse(readFileSync(projectConfigPath, 'utf8')) as {
- appid?: string
- }
- if (projectConfig.appid !== expectedAppid) {
- fail(`构建产物 AppID 校验失败:期望 ${expectedAppid},实际 ${projectConfig.appid || '未配置'}`)
- }
- }
- const main = async (): Promise<void> => {
- const target = parseTarget(process.argv[2])
- const config = ENVIRONMENTS[target]
- const processEnv = loadEnvironment(target)
- const originalManifest = readFileSync(MANIFEST_PATH, 'utf8')
- console.log(`\n[环境] ${config.label} (${target})`)
- console.log(`[接口] ${config.baseApi}`)
- console.log(`[AppID] ${config.appid}`)
- writeFileSync(MANIFEST_PATH, injectManifestAppid(originalManifest, config.appid), 'utf8')
- try {
- await runUniBuild(target, processEnv)
- validateBuildOutput(config.appid)
- console.log(`[构建] 已生成 ${BUILD_OUTPUT_DIR}`)
- } finally {
- writeFileSync(MANIFEST_PATH, originalManifest, 'utf8')
- }
- }
- void main().catch((error: unknown) => {
- const message = error instanceof Error ? error.message : String(error)
- console.error(`\n[失败] ${message}`)
- process.exitCode = 1
- })
|