"添加前端模板和运行代码模块"
This commit is contained in:
211
qiming-xagi-frontend-templates/scripts/pack-template.js
Normal file
211
qiming-xagi-frontend-templates/scripts/pack-template.js
Normal file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
/**
|
||||
* 模板打包脚本
|
||||
* 用于将指定的模板项目打包成 zip 文件,排除 .gitignore 中指定的文件
|
||||
*/
|
||||
|
||||
// 获取命令行参数
|
||||
const templateName = process.argv[2]
|
||||
const isRelease = process.argv.includes('--release')
|
||||
|
||||
if (!templateName) {
|
||||
console.error('❌ 请指定模板名称')
|
||||
console.log('用法: node scripts/pack-template.js <template-name> [--release]')
|
||||
console.log('可用模板: react-vite, react-next, vue3-vite')
|
||||
console.log(' --release 生成稳定文件名(无时间戳),用于 GitHub Release')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// 模板配置
|
||||
const templates = {
|
||||
'react-vite': {
|
||||
name: 'React + Vite + TypeScript',
|
||||
dir: 'packages/react-vite',
|
||||
outputName: 'react-vite-template',
|
||||
},
|
||||
'react-next': {
|
||||
name: 'React + Next.js + TypeScript',
|
||||
dir: 'packages/react-next',
|
||||
outputName: 'react-next-template',
|
||||
},
|
||||
'vue3-vite': {
|
||||
name: 'Vue 3 + Vite + TypeScript',
|
||||
dir: 'packages/vue3-vite',
|
||||
outputName: 'vue3-vite-template',
|
||||
},
|
||||
}
|
||||
|
||||
const template = templates[templateName]
|
||||
|
||||
if (!template) {
|
||||
console.error(`❌ 未找到模板: ${templateName}`)
|
||||
console.log('可用模板:', Object.keys(templates).join(', '))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const templateDir = path.resolve(__dirname, '..', template.dir)
|
||||
const outputDir = path.resolve(__dirname, '..', 'zip')
|
||||
|
||||
// 检查模板目录是否存在
|
||||
if (!fs.existsSync(templateDir)) {
|
||||
console.error(`❌ 模板目录不存在: ${templateDir}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// 创建输出目录
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true })
|
||||
}
|
||||
|
||||
// 读取 package.json 获取版本号
|
||||
let version = null
|
||||
const packageJsonPath = path.join(templateDir, 'package.json')
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
try {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
||||
if (packageJson.version) {
|
||||
version = packageJson.version
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ 读取 package.json 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 生成时间戳:YYYY_MM_DD_HH_MM_SS
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(now.getDate()).padStart(2, '0')
|
||||
const hours = String(now.getHours()).padStart(2, '0')
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0')
|
||||
const timestamp = `${year}_${month}_${day}_${hours}_${minutes}_${seconds}`
|
||||
|
||||
let fileName
|
||||
if (isRelease) {
|
||||
if (!version) {
|
||||
console.error('❌ Release 模式需要 package.json 中有 version 字段')
|
||||
process.exit(1)
|
||||
}
|
||||
fileName = `${template.outputName}_${version}.zip`
|
||||
} else {
|
||||
fileName = version
|
||||
? `${template.outputName}_${version}_${timestamp}.zip`
|
||||
: `${template.outputName}_${timestamp}.zip`
|
||||
}
|
||||
const outputFile = path.join(outputDir, fileName)
|
||||
|
||||
// 清除之前的包(匹配该模板的所有旧文件)
|
||||
console.log(`🧹 清除之前的包...`)
|
||||
try {
|
||||
const files = fs.readdirSync(outputDir)
|
||||
// 匹配该模板的所有旧文件(可能包含版本号,也可能不包含)
|
||||
const oldFiles = files.filter(file => {
|
||||
const baseName = file.replace(/\.zip$/, '')
|
||||
// 匹配格式:templateName_* 或 templateName_version_*
|
||||
return (
|
||||
file.endsWith('.zip') &&
|
||||
(baseName === template.outputName ||
|
||||
baseName.startsWith(`${template.outputName}_`))
|
||||
)
|
||||
})
|
||||
|
||||
if (oldFiles.length > 0) {
|
||||
oldFiles.forEach(file => {
|
||||
const filePath = path.join(outputDir, file)
|
||||
fs.unlinkSync(filePath)
|
||||
console.log(` ✓ 已删除: ${file}`)
|
||||
})
|
||||
console.log(`✅ 已清除 ${oldFiles.length} 个旧文件\n`)
|
||||
} else {
|
||||
console.log(` ℹ️ 没有找到旧文件\n`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ 清除旧文件时出错: ${error.message}\n`)
|
||||
}
|
||||
|
||||
console.log(`🚀 开始打包模板: ${template.name}`)
|
||||
if (version) {
|
||||
console.log(`📌 版本号: ${version}`)
|
||||
}
|
||||
console.log(`📁 源目录: ${templateDir}`)
|
||||
console.log(`📦 输出文件: ${outputFile}`)
|
||||
|
||||
try {
|
||||
// 读取 .gitignore 文件
|
||||
const gitignorePath = path.join(templateDir, '.gitignore')
|
||||
let ignorePatterns = []
|
||||
|
||||
// 强制排除的目录和文件
|
||||
const forceExclude = [
|
||||
'node_modules',
|
||||
'dist',
|
||||
'dist-ssr',
|
||||
'build',
|
||||
'.next',
|
||||
'.nuxt',
|
||||
'.cache',
|
||||
'.parcel-cache',
|
||||
'coverage',
|
||||
'.nyc_output',
|
||||
'*.log',
|
||||
'.DS_Store',
|
||||
'Thumbs.db',
|
||||
'playground',
|
||||
]
|
||||
|
||||
if (fs.existsSync(gitignorePath)) {
|
||||
const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8')
|
||||
ignorePatterns = gitignoreContent
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#'))
|
||||
.map(pattern => {
|
||||
// 处理 .gitignore 模式
|
||||
if (pattern.endsWith('/')) {
|
||||
return pattern.slice(0, -1) // 移除末尾的 /
|
||||
}
|
||||
return pattern
|
||||
})
|
||||
}
|
||||
|
||||
// 合并强制排除和 .gitignore 中的模式
|
||||
ignorePatterns = [...new Set([...forceExclude, ...ignorePatterns])]
|
||||
|
||||
// 构建 zip 命令 - 使用更可靠的排除方式
|
||||
let zipCommand = `cd "${templateDir}" && zip -r "${outputFile}" .`
|
||||
|
||||
// 添加排除模式 - 使用多个 -x 参数,确保正确排除
|
||||
if (ignorePatterns.length > 0) {
|
||||
ignorePatterns.forEach(pattern => {
|
||||
zipCommand += ` -x "${pattern}/*" -x "${pattern}"`
|
||||
})
|
||||
}
|
||||
|
||||
console.log('📋 排除模式:', ignorePatterns.length > 0 ? ignorePatterns.join(', ') : '无')
|
||||
|
||||
// 执行打包命令
|
||||
console.log('⏳ 正在打包...')
|
||||
execSync(zipCommand, { stdio: 'inherit' })
|
||||
|
||||
// 检查输出文件
|
||||
if (fs.existsSync(outputFile)) {
|
||||
const stats = fs.statSync(outputFile)
|
||||
const fileSizeInMB = (stats.size / (1024 * 1024)).toFixed(2)
|
||||
|
||||
console.log('✅ 打包完成!')
|
||||
console.log(`📦 输出文件: ${outputFile}`)
|
||||
console.log(`📊 文件大小: ${fileSizeInMB} MB`)
|
||||
} else {
|
||||
console.error('❌ 打包失败: 输出文件未生成')
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 打包过程中发生错误:', error.message)
|
||||
process.exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user