Yarn Monorepo中如何在Expo应用里导入TypeScript函数
问题描述
用Yarn Workspaces搭建了monorepo,其中包含一个TypeScript编写的组件及工具函数包ui-base,希望在裸Expo应用中直接导入使用,但系统会尝试从node_modules导入该包,同时报TypeScript语法解析错误,需要调整配置实现直接从项目源码导入。
错误信息
ERROR in ../../node_modules/ui-base/src/utils/sizeHelper.ts 3:17 Module parse failed: Unexpected token (3:17) File was processed with these loaders: * ../../node_modules/source-map-loader/dist/cjs.js You may need an additional loader to handle the result of these loaders. | import { Dimensions } from "react-native"; | > const vh = (value: number) => (Dimensions.get("window").height / 100) * value; | | const vw = (value: number) => (Dimensions.get("window").width / 100) * value; web compiled with 6 errors
现有配置文件
根目录 package.json
{ "name": "omnijs", "version": "0.1.0", "private": true, "workspaces": [ "apps/*", "packages/*" ], "packageManager": "yarn@3.5.0" }
根目录 tsconfig.json
{ "compilerOptions": { "strictNullChecks": true, "noUncheckedIndexedAccess": true, "paths": { "ui-base/*": ["./packages/ui-base/*"] } }, "extends": "expo/tsconfig.base" }
ui-base 包的 package.json
{ "name": "ui-base", "version": "1.0.0", "description": "", "main": "./src/index.ts", "keywords": [], "author": "", "license": "ISC", "dependencies": { "@tsconfig/recommended": "^1.0.1", "babel-preset-expo": "~9.5.0", "prettier": "3.0.0", "react": "18.2.0", "react-native": "0.72.3", "react-native-reanimated": "^3.4.1", "styled-components": "5.3.11", "tsup": "^7.2.0" } }
Expo应用的 tsconfig.json
{ "extends": "../../tsconfig" }
Expo应用的 package.json
{ "name": "@omnijs/flix", "version": "1.0.0", "main": "index.js", "scripts": { "start": "expo start --dev-client", "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web" }, "dependencies": { "@tanstack/react-query": "^4.32.6", "@tanstack/router": "^0.0.1-beta.53", "axios": "^1.4.0", "expo": "~49.0.5", "expo-splash-screen": "~0.20.4", "expo-status-bar": "~1.6.0", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.72.3", "react-native-web": "~0.19.6", "ui-base": "*", "zustand": "^4.4.1" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-typescript": "^7.22.5", "@expo/webpack-config": "^18.1.2", "@types/expo": "^33.0.1", "@types/react": "^18.2.18", "@types/react-native": "^0.72.2", "prettier": "^3.0.1", "typescript": "^5.1.6" }, "private": true }
Expo应用的 metro.config.js
// Learn more https://docs.expo.dev/guides/monorepos // Learn more https://docs.expo.io/guides/customizing-metro /** * @type {import('expo/metro-config')} */ const {getDefaultConfig} = require('expo/metro-config'); const path = require('path'); // Find the project and workspace directories const projectRoot = __dirname; // This can be replaced with `find-yarn-workspace-root` const workspaceRoot = path.resolve(projectRoot, '../..'); const config = getDefaultConfig(projectRoot); // 1. Watch all files within the monorepo config.watchFolders = [workspaceRoot]; // 2. Let Metro know where to resolve packages and in what order config.resolver.nodeModulesPaths = [ path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules'), ]; // 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths` config.resolver.disableHierarchicalLookup = true; module.exports = config;
解决方案
问题核心是Expo Web使用的Webpack未将ui-base识别为需要编译的源码,而是从node_modules加载了未转译的TypeScript文件,导致解析失败。需通过以下配置调整解决:
1. 配置Webpack编译本地包源码
在Expo项目根目录创建webpack.config.js,让Webpack处理ui-base的TypeScript文件:
const createExpoWebpackConfigAsync = require('@expo/webpack-config'); module.exports = async function (env, argv) { const config = await createExpoWebpackConfigAsync(env, argv); // 添加规则,编译ui-base的TS/TSX文件 config.module.rules.push({ test: /\.(ts|tsx)$/, include: /packages\/ui-base/, use: [ { loader: 'babel-loader', options: { presets: ['babel-preset-expo'], }, }, 'ts-loader', ], }); // 让Webpack直接解析ui-base的源码目录,跳过node_modules config.resolve.alias['ui-base'] = require('path').resolve(__dirname, '../../packages/ui-base/src'); return config; };
2. 完善ui-base包的配置
- 在
ui-base的package.json中添加类型定义字段:"types": "./src/index.ts", - 创建
packages/ui-base/tsconfig.json,规范TypeScript编译配置:{ "extends": "@tsconfig/recommended/tsconfig.json", "compilerOptions": { "jsx": "react-native", "module": "ESNext", "target": "ESNext", "moduleResolution": "node", "esModuleInterop": true, "skipLibCheck": true, "strict": true, "outDir": "./dist" }, "include": ["src/**/*"], "exclude": ["node_modules"] }
3. 优化Metro配置(适配Native端)
在现有metro.config.js中添加TS/TSX文件扩展名支持:
// 在module.exports前添加 config.resolver.sourceExts.push('ts', 'tsx');
4. 重启服务并验证
执行以下命令重新安装依赖并清除缓存启动服务:
yarn install yarn start --web --clear
内容的提问来源于stack exchange,提问作者Thiago Lino Gomes
相关产品推荐
相关产品推荐

