Ai
1 Star 0 Fork 1

zhangkb/example-code

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
index.js 9.95 KB
一键复制 编辑 原始数据 按行查看 历史
zhangkb 提交于 2025-06-23 14:47 +08:00 . 优化组件流程
// 打包前优化 generateSubPackageModulesConfig
// 在 uniBuild 任务之前执行
const {series, task, src, parallel, dest} = require('gulp')
const tap = require('gulp-tap')
const path = require('path')
const fs = require('fs')
const {extractRelativePaths} = require('./utils')
// 项目根目录
const rootPath = path.join(__dirname, '../')
const srcPath = path.join(rootPath, './src')
const componentsPath = path.join(rootPath, './src/components')
const pagesPath = path.join(rootPath, './src/pages')
const dependenciesJsonDistPath = path.join(__dirname, './dependencies.json')
// 组件引用根路径
const componentRootPath = '@/components' // 替换为 pages 页面中引入组件的根路径
const newComponentDir = 'componentsauto' // 迁移后的新组件目录
// 页面配置
let pages = {}
// 分包页面路径列表
let subPackagePagePathList = []
// 主包页面路径列表
let mainPackagePagePathList = []
// 组件依赖信息
let componentsMap = {}
const taskMap = {}
const changeFileMap = {}
const deleteFileMap = {}
function initData() {
// pages.json 会被之前的 gulp 流程修改,因此在执行到当前任务时再获取
pages = require('../src/pages.json')
subPackagePagePathList = pages.subPackages.map(item => item.root.replace('pages/', ''))
mainPackagePagePathList = pages.pages.map(item => {
const pathParts = item.path.split('/')
return pathParts.join(`\\${path.sep}`)
})
}
/**
* 组件信息初始化
*/
function initComponentsMap() {
// 为所有 src/components 中的组件创建信息
return src([`${srcPath}/@(components)/**/**.vue`]).pipe(
tap(file => {
let filePath = transferFilePathToComponentPath(file.path)
componentsMap[filePath] = {
refers: [], // 引用此组件的页面/组件
quotes: [], // 此组件引用的组件
referForMainPackage: false // 是否被主包引用,被主包引用时不需要 copy 到分包
}
})
)
}
/**
* 分析依赖
*/
function analyseDependencies() {
return src([`${srcPath}/@(components|pages)/**/**.vue`]).pipe(
tap(file => {
// 是否为主包页面
const isMainPackagePageByPath = checkIsMainPackagePageByPath(file.path)
// 分析页面引用了哪些组件
const componentsPaths = Object.keys(componentsMap)
const content = String(file.contents)
componentsPaths.forEach(componentPath => {
if (content.includes(componentPath)) {
// 当前页面引用了这个组件
componentsMap[componentPath].refers.push(file.path)
if (file.path.includes(componentsPath)) {
// 记录组件被引用情况
const targetComponentPath = transferFilePathToComponentPath(file.path)
componentsMap[targetComponentPath].quotes.push(componentPath)
}
// 标记组件是否被主页引用
if (isMainPackagePageByPath) {
componentsMap[componentPath].referForMainPackage = true
}
}
})
})
)
}
/**
* 分析间接引用依赖
*/
function analyseIndirectDependencies(done) {
for (const componentPath in componentsMap) {
const componentInfo = componentsMap[componentPath]
if (!componentInfo.referForMainPackage) {
const isIndirectReferComponent = checkIsIndirectReferComponent(componentPath)
if (isIndirectReferComponent) {
componentInfo.referForMainPackage = true
}
}
}
done()
}
/**
* 是否为被主页间接引用的组件
*/
function checkIsIndirectReferComponent(componentPath) {
const componentInfo = componentsMap[componentPath]
if (componentInfo.referForMainPackage) {
return true
}
for (const filePath of componentInfo.refers) {
if (filePath.includes(componentsPath)) {
const subComponentPath = transferFilePathToComponentPath(filePath)
const result = checkIsIndirectReferComponent(subComponentPath)
if (result) {
return result
}
}
}
}
/**
* 将组件路径转换为文件路径
*/
function transferComponentPathToFilePath(componentPath) {
return path.join(componentsPath, componentPath.replace(componentRootPath, '')) + '.vue'
}
/**
* 将文件路径转换为组件路径
*/
function transferFilePathToComponentPath(filePath) {
return filePath
.replace(componentsPath, componentRootPath)
.replaceAll(path.sep, '/')
.replace('.vue', '')
}
/**
* 判断页面路径是否为主包页面
*/
function checkIsMainPackagePageByPath(filePath) {
// 从 pages 文件中获取主包页面路径列表
// 正则:判断是否为主包页面
const isMainPackagePageReg = new RegExp(`(${mainPackagePagePathList.join('|')})`)
return isMainPackagePageReg.test(filePath)
}
// 保存依赖分析数据
function saveDependenciesData(done) {
fs.writeFileSync(dependenciesJsonDistPath, JSON.stringify(componentsMap, null, 4), 'utf8')
done()
}
// 分发组件
async function distributionComponents() {
for (let componentPath in componentsMap) {
const componentInfo = componentsMap[componentPath]
// 未被主包引用的组件
for (const pagePath of componentInfo.refers) {
// 将组件复制到分包
if (pagePath.includes(pagesPath)) {
// 将组件复制到页面所在分包
await copyComponent(componentPath, pagePath)
}
}
}
}
/**
* 复制组件
* @param {*} componentPath
* @param {*} targetPath
* @returns
*/
async function copyComponent(componentPath, pagePath) {
const componentInfo = componentsMap[componentPath]
// 只处理不被主页引用的组件
if (componentInfo.referForMainPackage) return
const key = `${componentPath}_${pagePath}`
// 避免重复任务
if (taskMap[key]) return
taskMap[key] = true
const subPackageRoot = getSubPackageRootByPath(pagePath)
if (!subPackageRoot) return
const componentFilePath = transferComponentPathToFilePath(componentPath)
const subPackageComponentsPath = path.join(subPackageRoot, newComponentDir)
const newComponentFilePath = path.join(subPackageComponentsPath, path.basename(componentFilePath))
const newComponentsPath = newComponentFilePath
.replace(srcPath, '@')
.replaceAll(path.sep, '/')
.replaceAll('.vue', '')
// 1. 复制组件及其资源
await copyComponentWithResources(componentFilePath, subPackageComponentsPath, componentInfo)
// 2. 递归复制引用的组件
if (componentInfo.quotes.length > 0) {
let tasks = []
componentInfo.quotes.map(quotePath => {
// 复制子组件
tasks.push(copyComponent(quotePath, pagePath))
const subComponentInfo = componentsMap[quotePath]
if (!subComponentInfo.referForMainPackage) {
// 2.1 修改组件引用的子组件路径
const newSubComponentFilePath = path.join(subPackageComponentsPath, path.basename(quotePath))
const newSubComponentsPath = newSubComponentFilePath
.replace(srcPath, '@')
.replaceAll(path.sep, '/')
.replaceAll('.vue', '')
updateChangeFileInfo(newComponentFilePath, quotePath, newSubComponentsPath)
}
})
await Promise.all(tasks)
}
// 3. 修改页面引用当前组件路径
updateChangeFileInfo(pagePath, componentPath, newComponentsPath)
// 4. 删除当前组件
updateDeleteFileInfo(componentFilePath)
}
/**
* 更新删除文件信息
* @param {*} filePath
*/
function updateDeleteFileInfo(filePath) {
deleteFileMap[filePath] = true
}
/**
* 更新修改文件内容信息
* @param {*} filePath
* @param {*} oldStr
* @param {*} newStr
*/
function updateChangeFileInfo(filePath, oldStr, newStr) {
if (!changeFileMap[filePath]) {
changeFileMap[filePath] = []
}
changeFileMap[filePath].push([oldStr, newStr])
}
/**
* 删除文件任务
*/
async function deleteFile() {
for (const filePath in deleteFileMap) {
try {
await fs.promises.unlink(filePath).catch(console.log) // 删除单个文件
// 或删除目录:await fs.rmdir('path/to/dir', { recursive: true });
} catch (err) {
console.error('删除失败:', err)
}
}
}
/**
* 复制组件及其资源
* @param {*} componentFilePath
* @param {*} destPath
*/
async function copyComponentWithResources(componentFilePath, destPath) {
// 复制主组件文件
await new Promise(resolve => {
src(componentFilePath)
.pipe(dest(destPath))
.on('end', resolve)
})
// 处理组件中的相对路径资源
const content = await fs.promises.readFile(componentFilePath, 'utf-8')
const relativePaths = extractRelativePaths(content)
await Promise.all(
relativePaths.map(async relativePath => {
const resourceSrcPath = path.join(componentFilePath, '../', relativePath)
const resourceDestPath = path.join(destPath, path.dirname(relativePath))
await new Promise(resolve => {
src(resourceSrcPath)
.pipe(dest(resourceDestPath))
.on('end', resolve)
})
})
)
}
/**
* 修改页面引用路径
*/
async function changePageResourcePath() {
for (const pagePath in changeFileMap) {
const list = changeFileMap[pagePath]
await new Promise(resolve => {
src(pagePath)
.pipe(
tap(file => {
let content = String(file.contents)
for (const [oldPath, newPath] of list) {
content = content.replaceAll(oldPath, newPath)
}
file.contents = Buffer.from(content)
})
)
.pipe(dest(path.join(pagePath, '../')))
.on('end', resolve)
})
}
}
// 获取分包根目录
function getSubPackageRootByPath(pagePath) {
for (const subPackagePagePath of subPackagePagePathList) {
const rootPath = `${path.join(pagesPath, subPackagePagePath)}`
const arr = pagePath.replace(pagesPath, '').split(path.sep)
if (arr[1] === subPackagePagePath) {
return rootPath
}
}
}
const tasks = [
initComponentsMap,
analyseDependencies,
analyseIndirectDependencies,
distributionComponents,
changePageResourcePath,
deleteFile,
saveDependenciesData
]
exports.default = done => {
initData()
return series(...tasks)(done)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhangkb/example-code.git
git@gitee.com:zhangkb/example-code.git
zhangkb
example-code
example-code
master

搜索帮助