如何在现代JS中禁止folder1导入folder2内容?React Native/Expo场景
针对你这种在单个Expo/React Native应用里拆分成两个独立子应用(类似Uber乘客/司机端),还要严格隔离代码、禁止互相导入的需求,我整理了几个落地性很强的方案,都能在测试脚本和CI流程里生效:
这个方案通过Monorepo清晰划分代码结构,再用ESLint做强制的导入边界校验,开发阶段就能实时拦截非法导入,CI里也能自动阻断违规代码合并。
1. 调整项目结构
先把代码拆成独立的子应用包和共享包,典型结构如下:
your-project/ ├── apps/ │ ├── passenger/ # 乘客端子应用(完整Expo项目) │ │ ├── src/ │ │ ├── app.json │ │ └── package.json │ └── driver/ # 司机端子应用(完整Expo项目) │ ├── src/ │ ├── app.json │ └── package.json ├── packages/ │ └── shared/ # 共享公共代码包 │ ├── src/ │ └── package.json └── package.json
每个子应用都是独立的Expo项目,可以单独启动、打包;shared包是两者的公共依赖,比如通用组件、工具函数、API请求封装等。
2. 配置ESLint边界规则
安装专门的Monorepo边界检查插件eslint-plugin-boundaries,然后在项目根目录的ESLint配置文件(.eslintrc.js)里添加规则:
module.exports = { plugins: ['boundaries'], rules: { 'boundaries/import': [ 'error', // 触发时直接报错,阻断CI流程 { default: 'deny', // 默认禁止所有跨包导入 groups: [ // 允许乘客端导入共享包代码 { target: 'apps/passenger/**', from: ['packages/shared/**'] }, // 允许司机端导入共享包代码 { target: 'apps/driver/**', from: ['packages/shared/**'] }, // 严格禁止乘客端导入司机端代码 { target: 'apps/passenger/**', from: ['apps/driver/**'], message: '❌ 乘客端禁止导入司机端代码' }, // 严格禁止司机端导入乘客端代码 { target: 'apps/driver/**', from: ['apps/passenger/**'], message: '❌ 司机端禁止导入乘客端代码' } ] } ] } };
3. 集成到测试与CI
在根目录的package.json里添加脚本:
{ "scripts": { "lint": "eslint apps/ packages/", "test": "npm run lint && ...(其他测试命令)" } }
CI流程里只要执行npm run test,一旦有非法导入,ESLint会直接抛出错误,终止CI流程,从根源阻止违规代码上线。
如果不想用Monorepo,也可以通过修改Expo默认的Metro打包器配置,直接阻断跨文件夹的导入请求。
1. 为每个子应用配置独立Metro文件
比如在乘客端的根目录创建metro.config.js,添加以下配置:
const path = require('path'); module.exports = { resolver: { // 阻止导入司机端的任何代码 blockList: [ new RegExp(`^${path.resolve(__dirname, '../driver')}/.*$`), // 如果有别名的话,也加上别名的拦截 new RegExp(`^@your-project/driver/.*$`) ], }, };
司机端的metro.config.js同理,把拦截路径换成乘客端的文件夹。
2. 在app.json中指定Metro配置
在每个子应用的app.json里关联对应的Metro配置:
{ "expo": { "name": "PassengerApp", "metroConfig": "metro.config.js" } }
3. 集成到测试与CI
在脚本里添加打包验证命令,比如:
{ "scripts": { "validate:passenger": "expo export --platform ios --no-build", "validate:driver": "expo export --platform ios --no-build", "test": "npm run validate:passenger && npm run validate:driver && ..." } }
CI执行这个脚本时,只要有跨应用导入,Metro打包就会直接失败,阻断流程。
如果以上方案都不适合,还可以自己写个简单的Node脚本,扫描所有代码文件的导入语句,拦截非法的跨应用导入。
1. 编写检查脚本
创建scripts/check-imports.js:
const fs = require('fs'); const path = require('path'); // 定义禁止的导入规则 const forbiddenRules = [ { sourceDir: 'apps/passenger/src', forbiddenPaths: ['../driver', '@your-project/driver'] }, { sourceDir: 'apps/driver/src', forbiddenPaths: ['../passenger', '@your-project/passenger'] } ]; // 检查单个文件的导入语句 function checkFile(filePath, forbiddenPaths) { const content = fs.readFileSync(filePath, 'utf8'); const importMatches = content.match(/import.*from ['"](.*)['"]/g) || []; for (const match of importMatches) { const importPath = match.match(/from ['"](.*)['"]/)[1]; if (forbiddenPaths.some(fp => importPath.startsWith(fp))) { console.error(`❌ 非法导入:${filePath} 尝试导入 ${importPath}`); process.exit(1); } } } // 遍历目录下的所有代码文件 function traverseDir(dir, forbiddenPaths) { const files = fs.readdirSync(dir); for (const file of files) { const fullPath = path.join(dir, file); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { traverseDir(fullPath, forbiddenPaths); } else if (['.js', '.jsx', '.ts', '.tsx'].includes(path.extname(fullPath))) { checkFile(fullPath, forbiddenPaths); } } } // 执行检查 for (const rule of forbiddenRules) { traverseDir(rule.sourceDir, rule.forbiddenPaths); } console.log('✅ 所有导入检查通过!');
2. 集成到Git Hooks与CI
用husky把脚本加到pre-commit钩子,确保提交代码前自动检查;同时在package.json里添加脚本:
{ "scripts": { "check:imports": "node scripts/check-imports.js", "test": "npm run check:imports && ..." } }
CI流程执行npm run test时,脚本会自动扫描代码,发现非法导入就终止流程。
内容的提问来源于stack exchange,提问作者Sebastien Lorber

