You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo Android自定义插件使用import报错,如何保留TypeScript优势?

解决Expo自定义插件无法使用ES模块语法的问题

问题背景

开发Expo Android自定义插件时,使用官方示例的import/export语法会触发SyntaxError: Cannot use import statement outside a module错误,改用require虽能运行,但会丢失TypeScript类型支持,降低开发体验。

核心原因

Node.js默认以CommonJS(CJS)模块系统加载文件,import/export属于ES模块(ESM)语法,直接运行会被Node判定为非模块文件,从而抛出语法错误。

解决方案

方案1:用TypeScript编写并编译为CommonJS(推荐)

这是兼顾TypeScript优势和Expo兼容性的最优方案:

  1. 初始化插件的TypeScript环境
    在插件目录执行:
    npm init -y
    npm install typescript @types/node @expo/config-plugins --save-dev
    npx tsc --init
    
  2. 修改tsconfig.json关键配置:
    {
      "compilerOptions": {
        "module": "CommonJS",
        "target": "ES2018",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules", "dist"]
    }
    
  3. 在src目录编写TS插件(示例:修改MainActivity):
    import { ConfigPlugin, withDangerousMod } from '@expo/config-plugins';
    import fs from 'fs';
    import path from 'path';
    
    const withCustomMainActivity: ConfigPlugin = (config) => {
      return withDangerousMod(config, [
        'android',
        async (config) => {
          // 替换为你的MainActivity路径
          const mainActivityPath = path.join(
            config.modRequest.platformProjectRoot,
            'app',
            'src',
            'main',
            'java',
            'com',
            'yourcompany',
            'yourapp',
            'MainActivity.java'
          );
    
          let content = fs.readFileSync(mainActivityPath, 'utf8');
          // 示例:插入自定义代码
          if (!content.includes('// Custom injected code')) {
            content = content.replace(
              'super.onCreate(savedInstanceState);',
              'super.onCreate(savedInstanceState);\n        // Custom injected code'
            );
            fs.writeFileSync(mainActivityPath, content);
          }
          return config;
        },
      ]);
    };
    
    export default withCustomMainActivity;
    
  4. 在插件的package.json添加编译脚本:
    {
      "scripts": {
        "build": "tsc"
      }
    }
    
  5. 执行npm run build编译,在Expo项目的app.json中引用编译后的文件:
    {
      "expo": {
        "plugins": ["./path-to-your-plugin/dist/index.js"]
      }
    }
    

方案2:将插件标记为ES模块

无需编译,直接让Node识别插件为ES模块:

  1. 在插件目录的package.json中添加:
    {
      "type": "module"
    }
    
  2. 注意:所有文件必须统一使用ESM语法,不能混合require;若需引用CommonJS模块,需用createRequire转换:
    import { createRequire } from 'module';
    const require = createRequire(import.meta.url);
    // 引用CommonJS模块示例
    const cjsModule = require('some-cjs-package');
    
  3. 配合TypeScript时,需将tsconfig.json的module设为ESNext,编译后输出ESM格式。

方案3:使用.mjs扩展名

将插件文件重命名为.mjs(TS文件用.mts),Node会自动将其当作ES模块处理,无需修改package.json。该方式适合小型单文件插件,大型插件管理效率不如TS编译方案。

内容的提问来源于stack exchange,提问作者Vivere

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:23:09