当前位置: 首页 > news >正文

vue路径大小写引入检查与修复;配置git大小写敏感

问题:window下文件的路径的大小写是不敏感的,而linux下文件的路径名称需要区分大小写,在用linux打包文vue项目的时候会出现路径错误。要在linux 下完成打包,需修改文件中路径引用严格区分大小写。

自动校验和修复效果:

文章目录

  • 一、问题
    • 1、问题截图:
    • 2、问题原因:
  • 二、检查大小写及修复脚本
    • 1、创建路径大小写检查修复脚本
    • 脚本特点
    • 2、使用说明
      • 2.1、 基本使用
      • 2.2、自动修复
      • 2.3、 添加执行脚本到 package.json
    • 2.3、预防性配置
      • 在 vite.config.js 中添加路径别名检查
    • 3、 其他配置(暂未验证,可以不配置)
  • 三、配置git大小写敏感
    • 3.1、检查git是否校验大小写敏感
    • 3.2配置大小写敏感


一、问题

1、问题截图:

在这里插入图片描述

问题解释:在src/plugins/components.js文件内找不到xxxx/src/components/MyUpload/index.vue
因为实际的文件是xxxx/src/components/Myupload/index.vue

2、问题原因:

windows下路径大小写不敏感,如/page/index.js== Page/index.js,但是在Linux环境下大小写敏感
·/page!=/Page 它们表示两个不同的文件夹,所以在我们开发时应该遵守规范,严格按照大小写引入。
还有个一原因,写路由的时候,会省略index.vue文件,比如/page/login/index.vue 写成page/login,打包的时候也会报错.

二、检查大小写及修复脚本

知道路径大小写问题后,如果一个个文件去查找是非常麻烦且会有遗漏;此时可通过以下脚本自动查找和修复:这个脚本会扫描项目文件,找出不匹配的路径引用并提供修复选项。

1、创建路径大小写检查修复脚本

在项目的根目录下,创建 fix-path-case.js 文件:

脚本特点

  1. 全面扫描:支持 Vue、JS、TS 等文件类型
  2. 智能修复:自动找到正确的大小写路径
  3. 安全可靠:默认只报告不修改,需明确指定 --fix
  4. 详细报告:显示文件名、行号、原路径和建议路径
  5. 忽略无关目录:自动跳过 node_modules 等目录
#!/usr/bin/env node// 检查文件大小写引入问题:
// node fix-path-case.js
// 自动修复:
// node fix-path-case.js --fiximport fs from "fs" // 文件系统模块,用于读写文件
import path from "path" // 路径处理模块
import { promisify } from "util"const readdir = promisify(fs.readdir)
const stat = promisify(fs.stat)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
// const exists = promisify(fs.exists);class PathCaseChecker {constructor(options = {}) {this.rootDir = options.rootDir || process.cwd()this.srcDir = path.join(this.rootDir, "src")this.extensions = options.extensions || [".vue", ".js", ".ts", ".jsx", ".tsx"]this.ignoreDirs = options.ignoreDirs || ["node_modules", ".git", "dist", "build"]this.autoFix = options.autoFix || falsethis.issues = []// 存储所有文件的真实路径映射(小写 -> 实际大小写)this.filePathMap = new Map()this.aliasMap = {"@": this.srcDir,"~": this.srcDir}}// 递归收集所有文件的实际路径async collectAllFiles(dir, relativePath = "") {try {const files = await readdir(dir)for (const file of files) {const fullPath = path.join(dir, file)const fileRelativePath = path.join(relativePath, file)const fileStat = await stat(fullPath)if (fileStat.isDirectory()) {if (!this.ignoreDirs.includes(file)) {await this.collectAllFiles(fullPath, fileRelativePath)}} else {const ext = path.extname(file)if (this.extensions.includes(ext)) {// 存储小写路径到实际路径的映射const lowerPath = fileRelativePath.toLowerCase().replace(/\\/g, "/")this.filePathMap.set(lowerPath, fileRelativePath.replace(/\\/g, "/"))}}}} catch (error) {console.error(`收集文件失败: ${dir}`, error.message)}}// 解析别名路径为实际路径resolveAliasPath(importPath) {if (importPath.startsWith("@/") || importPath.startsWith("~/")) {const alias = importPath.startsWith("@/") ? "@" : "~"const relativePath = importPath.slice(2) // 去掉 '@/' 或 '~/'return path.join(this.aliasMap[alias], relativePath)}return importPath}// 检查导入路径是否存在大小写问题async checkImportPath(importPath, currentFile) {// 跳过非项目路径if (!importPath.startsWith("@/") && !importPath.startsWith("~/") && !importPath.startsWith(".")) {return null}let actualFilePath = importPath// 处理别名路径if (importPath.startsWith("@/") || importPath.startsWith("~/")) {actualFilePath = this.resolveAliasPath(importPath)} else if (importPath.startsWith(".")) {// 处理相对路径const currentDir = path.dirname(currentFile)actualFilePath = path.resolve(currentDir, importPath)}// 转换为相对于 src 目录的路径let relativeToSrc = path.relative(this.srcDir, actualFilePath)if (relativeToSrc.startsWith("..")) {// 如果不在 src 目录内,使用相对于项目根目录的路径relativeToSrc = path.relative(this.rootDir, actualFilePath)}const normalizedRelativePath = relativeToSrc.replace(/\\/g, "/")const lowerPath = normalizedRelativePath.toLowerCase()// 检查是否存在大小写不匹配const actualCasePath = this.filePathMap.get(lowerPath)if (actualCasePath && actualCasePath !== normalizedRelativePath) {// 计算正确的导入路径let correctImportPathif (importPath.startsWith("@/") || importPath.startsWith("~/")) {const alias = importPath.startsWith("@/") ? "@" : "~"correctImportPath = `${alias}/${actualCasePath}`} else {// 相对路径需要重新计算const currentDir = path.dirname(currentFile)const absoluteCorrectPath = path.join(this.srcDir, actualCasePath)correctImportPath = path.relative(currentDir, absoluteCorrectPath).replace(/\\/g, "/")if (!correctImportPath.startsWith(".")) {correctImportPath = "./" + correctImportPath}}return {original: importPath,correct: correctImportPath,actualFile: path.join(this.srcDir, actualCasePath)}}return null}// 提取文件中的所有导入语句(改进版)extractImports(content, filePath) {const imports = []// 匹配各种导入模式const patterns = [// import ... from 'path'/from\s+['"]([^'"]+)['"]/g,// import 'path'/import\s+['"]([^'"]+)['"]/g,// require('path')/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,// 动态 import()/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g]patterns.forEach(pattern => {let matchwhile ((match = pattern.exec(content)) !== null) {const importPath = match[1]// 过滤掉明显不是文件导入的路径if (this.isFileImport(importPath, filePath)) {imports.push({path: importPath,start: match.index,end: match.index + match[0].length,original: match[0]})}}})return imports}// 判断是否为文件导入路径isFileImport(importPath, currentFile) {// 跳过明显的包导入if (!importPath.startsWith(".") && !importPath.startsWith("@/") && !importPath.startsWith("~/")) {return false}// 检查是否有文件扩展名或看起来像文件路径const ext = path.extname(importPath)if (ext && this.extensions.includes(ext)) {return true}// 对于目录导入,检查是否存在对应的文件return this.looksLikeFilePath(importPath, currentFile)}// 判断路径是否像文件路径looksLikeFilePath(importPath, currentFile) {// 包含目录分隔符或常见目录名if (importPath.includes("/") && !importPath.includes("node_modules")) {// 尝试解析路径并检查是否存在对应文件let resolvedPathif (importPath.startsWith("@/") || importPath.startsWith("~/")) {resolvedPath = this.resolveAliasPath(importPath)} else {resolvedPath = path.resolve(path.dirname(currentFile), importPath)}// 检查是否存在对应的文件(任何扩展名)return this.extensions.some(ext => {const filePath = resolvedPath + extreturn (fs.existsSync(filePath) || fs.existsSync(path.join(resolvedPath, "index" + ext)) || fs.existsSync(path.join(resolvedPath, "index.js")) || fs.existsSync(path.join(resolvedPath, "index.vue")))})}return false}// 检查单个文件async checkFile(filePath) {try {const content = await readFile(filePath, "utf8")const imports = this.extractImports(content, filePath)let newContent = contentlet hasChanges = falseconst replacements = []// 收集所有需要替换的位置for (const imp of imports) {const result = await this.checkImportPath(imp.path, filePath)if (result) {replacements.push({original: imp.original,replacement: imp.original.replace(imp.path, result.correct),start: imp.start,end: imp.end,issue: {file: filePath,originalPath: imp.path,correctPath: result.correct,actualFile: result.actualFile}})}}// 从后往前替换,避免位置偏移replacements.sort((a, b) => b.start - a.start)for (const replacement of replacements) {const before = newContent.substring(0, replacement.start)const after = newContent.substring(replacement.end)newContent = before + replacement.replacement + afterthis.issues.push(replacement.issue)hasChanges = true}if (hasChanges && this.autoFix) {await writeFile(filePath, newContent, "utf8")console.log(`✅ 已修复: ${filePath}`)}return hasChanges} catch (error) {console.error(`❌ 检查文件失败: ${filePath}`, error.message)return false}}// 递归扫描目录async scanDirectory(dirPath) {try {const files = await readdir(dirPath)for (const file of files) {const fullPath = path.join(dirPath, file)const fileStat = await stat(fullPath)if (fileStat.isDirectory()) {if (!this.ignoreDirs.includes(file)) {await this.scanDirectory(fullPath)}} else {const ext = path.extname(file)if (this.extensions.includes(ext)) {await this.checkFile(fullPath)}}}} catch (error) {console.error(`❌ 扫描目录失败: ${dirPath}`, error.message)}}// 生成详细报告generateReport() {if (this.issues.length === 0) {console.log("\n🎉 没有发现路径大小写问题!")return}console.log(`\n📊 发现 ${this.issues.length} 个路径大小写问题,统计如下:\n`)const groupedIssues = this.issues.reduce((groups, issue) => {const key = issue.fileif (!groups[key]) groups[key] = []groups[key].push(issue)return groups}, {})Object.entries(groupedIssues).forEach(([file, issues]) => {console.log(`📁 ${file}:`)issues.forEach((issue, index) => {console.log(`   ${index + 1}. 引入路径: ${issue.originalPath}`)console.log(`      正确路径: ${issue.correctPath}`)console.log(`      实际文件: ${issue.actualFile}`)})console.log("")})if (!this.autoFix) {console.log(`\n   ❌存在 ${this.issues.length} 个路径大小写问题:`)console.log('   💡建议运行 "node fix-path-case.js --fix" 自动修复这些问题')}if (this.autoFix && this.issues.length > 0) {console.log(`\n   ✅已修复路径大小写问题`)}}// 主执行函数async run() {console.log("🔍 开始收集项目文件信息...")await this.collectAllFiles(this.srcDir)console.log("📁 扫描路径大小写问题...")console.log(`项目根目录: ${this.rootDir}`)console.log(`源码目录: ${this.srcDir}`)await this.scanDirectory(this.srcDir)this.generateReport()if (this.issues.length > 0 && !this.autoFix) {// console.log('\n❌ 发现路径大小写问题,请运行修复命令');// process.exit(1) // 如果有问题且未修复,退出码为1}}
}// CLI 参数解析
const args = process.argv.slice(2)
const options = {autoFix: args.includes("--fix") || args.includes("-f"),rootDir: process.cwd()
}// 处理自定义目录
const dirIndex = args.findIndex(arg => arg === "--dir" || arg === "-d")
if (dirIndex !== -1 && args[dirIndex + 1]) {options.rootDir = path.resolve(args[dirIndex + 1])
}// 运行检查器
const checker = new PathCaseChecker(options)
checker.run().catch(error => {console.error("❌ 执行失败:", error)process.exit(1)
})

2、使用说明

2.1、 基本使用

# 将脚本放在项目根目录,然后运行:
node fix-path-case.js

这会扫描项目并报告所有路径大小写问题,但不会自动修改。

2.2、自动修复

# 自动修复所有发现的问题
node fix-path-case.js --fix

2.3、 添加执行脚本到 package.json

package.json 中添加脚本:

{"scripts": {"dev": "pnpm fix:paths && vite --mode beta --host","lint:paths": "node fix-path-case.js","fix:paths": "node fix-path-case.js --fix"}
}

然后运行:

pnpm lint:paths    # 检查问题
pnpm fix:paths     # 自动修复
pnpm dev  #启动项目时候自动校验和修复

pnpm lint:paths检查问题效果截图:
在这里插入图片描述

pnpm fix:paths自动修复效果截图:
在这里插入图片描述

pnpm dev启动项目时候自动校验和修复:
在这里插入图片描述

2.3、预防性配置

在 vite.config.js 中添加路径别名检查

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';export default defineConfig({plugins: [vue()],resolve: {alias: {'@': resolve(__dirname, 'src'),// 确保所有别名都使用正确的大小写},},
});

3、 其他配置(暂未验证,可以不配置)

3.1 配套的 ESLint 配置

创建 .eslintrc-path-case.js 文件来增强路径检查:

module.exports = {rules: {'import/no-unresolved': ['error', { caseSensitive: true }],},overrides: [{files: ['*.vue'],rules: {'vue/component-name-in-template-casing': ['error', 'PascalCase'],}}]
};

3.2 创建路径检查的 Git Hook

.husky/pre-commit 中添加:

#!/bin/bash
node fix-path-case.js --dry-run
if [ $? -ne 0 ]; thenecho "发现路径大小写问题,请运行 'npm run fix:paths' 修复"exit 1
fi

三、配置git大小写敏感

3.1、检查git是否校验大小写敏感

git在提交代码时,会忽略文件名称大小写,导致本地代码与远程代码不一致,此时可在项目根目录的终端指令来检查下
如果返回值为true,则表示Git会将文件名大小写视为不敏感;如果返回值为false,则表示Git会将文件名大小写视为敏感

# 查看全局设置
git config --global --get core.ignorecase# 查看特定项目设置(需要进入项目根目录)
git config --get core.ignorecase

3.2配置大小写敏感

# 设置全局设置
git config --global core.ignorecase false# 设置特定项目设置(需要进入项目根目录)
git config core.ignorecase false
http://www.dtcms.com/a/545996.html

相关文章:

  • 赣州网站开发公司网站开发的重难点
  • dvadmin开发文档(第一版)
  • 设计网站视频教程长沙网站推广优化
  • 淘宝电子面单API集成中的常见技术难点与解决方案
  • 高端网站制作要多少钱河北网站开发公司
  • 电脑制作网站的软件免费发布信息平台网
  • 西宁网站seo价格永康企业网站建设公司
  • 做视频特技的网站网站字体排版技巧
  • Rust 的零成本抽象:深入理解 Option 与 Result 的设计哲学
  • rust:什么是所有权
  • 模版网站好吗搜索引擎最新排名
  • 【js逆向案例二】瑞数6 深圳大学某医院
  • 网站编辑怎么样东莞网站建设网站推广价钱
  • TypeScript声明合并详解一
  • 网站后台登录域名注册公司需要注册资金吗
  • 蓝牙钥匙技术详解:从基础原理到未来趋势 大纲
  • 基于SVM与HOG特征的交通标志检测与识别
  • 如何做能上传视频网站网页设计教程
  • 做网盟的网站必须备案wordpress发表的文章点不开
  • nextjs路由[[...slug]]与[...slug]的区别
  • 全国药品招标、投标常用数据渠道及数据库<很全>
  • 附录:glibc-2.4 pthread 源码简要(了解)
  • 网站注册费用济南网站优化哪里做的好
  • 晋中住房与城乡建设厅网站湖南手机版建站系统哪家好
  • 记类成员变量 vs 方法中的变量
  • 企业网站模板建站建网站浩森宇特
  • 项目(四)
  • 徐州 商城网站设计wordpress变为中文
  • Rust Feature Flags:编译期配置的艺术与工程实践
  • 贵金属网站建设阿里云域名备案查询