创建开发工具插件

了解如何创建开发工具插件以增强你的开发体验。


信息 提示: 查看 Expo 开发工具插件 获取完整示例。

你可以创建一个开发者工具插件,无论是用于检查常见框架或库的某些方面,还是用于你的自定义代码的特定功能。本指南将带你逐步创建一个开发者工具插件。

🌐 You can create a dev tools plugin, whether that's for inspecting aspects of a common framework or library or something specific to your custom code. This guide will walk you through creating a dev tools plugin.

什么是开发工具插件?

🌐 What is a dev tools plugin?

开发工具插件在本地开发环境中的 Web 浏览器中运行,并连接到你的 Expo 应用。

🌐 A dev tools plugin runs in your web browser in your local development environment and connects to your Expo app.

插件由三个关键元素组成:

🌐 A plugin consists of three key elements:

  • 用于显示开发工具 Web 用户界面的 Expo 应用。
  • 用于 Expo CLI 识别的 expo-module.config.json
  • 调用 expo/devtools API 让应用与开发工具的网页界面进行来回通信。

插件可以通过 npm 分发,也可以包含在你的应用的 monorepo 中。它们通常导出一个单独的钩子,可以在应用的根组件中使用,以在应用处于调试模式时与网页界面进行双向通信。

🌐 Plugins can be distributed on npm or included inside your app's monorepo. They typically export a single hook that can be used in your app's root component to initiate two-way communication with the web interface when your app is running in debug mode.

1

创建一个插件

🌐 Create a plugin

创建一个新的插件项目

🌐 Create a new plugin project

create-dev-plugin 将为你设置一个新的插件项目。运行以下命令来创建一个新的插件项目:

Terminal
npx create-dev-plugin@latest

create-dev-plugin 会提示你输入插件的名称、描述以及消费者将使用的钩子名称。

插件项目将包含以下目录:

🌐 The plugin project will contain the following directories:

  • src - 这个导出的是一个钩子(hook),将在使用该插件的应用中使用,以将其连接到插件。
  • webui - 这包含了插件的网页用户界面。

自定义插件功能

🌐 Customize a plugin's functionality

该模板包含一个简单示例,展示插件与应用之间发送和接收消息的过程。useDevToolsPluginClient,从 expo/devtools 导入,提供插件与应用之间发送和接收消息的功能。

🌐 The template includes a simple example of sending and receiving messages between the plugin and the app. useDevToolsPluginClient, imported from expo/devtools, provides functionality for sending and receiving messages between the plugin and the app.

useDevToolsPluginClient 返回的客户端对象包括:

🌐 The client object returned by useDevToolsPluginClient includes:

addMessageListener

监听与输入字符串匹配的消息,并使用消息数据调用回调函数。

🌐 Listens for a message matching the typed string and invokes the callback with the message data.

const client = useDevToolsPluginClient('my-devtools-plugin'); client.addMessageListener('ping', data => { alert(`Received ping from ${data.from}`); });

sendMessage

监听与输入字符串匹配的消息,并使用消息数据调用回调函数。

🌐 Listens for a message matching the typed string and invokes the callback with the message data.

const client = useDevToolsPluginClient('my-devtools-plugin'); client?.sendMessage('ping', { from: 'web' });

编辑 webui 目录中的 Expo 应用,以自定义显示应用诊断信息或触发测试场景的用户界面:

🌐 Edit the Expo app inside the webui directory to customize the user interface that displays diagnostic information from your app or triggers test scenarios:

webui/App.tsx
import { useDevToolsPluginClient, type EventSubscription } from 'expo/devtools'; import { useEffect } from 'react'; export default function App() { const client = useDevToolsPluginClient('my-devtools-plugin'); useEffect(() => { const subscriptions: EventSubscription[] = []; subscriptions.push( client?.addMessageListener('ping', data => { alert(`Received ping from ${data.from}`); }) ); return () => { for (const subscription of subscriptions) { subscription?.remove(); } }; }, [client]); }

编辑 src 目录下的钩子,以自定义发送到插件的诊断信息或应用应如何响应来自 Web 用户界面的任何消息:

🌐 Edit the hook in the src directory to customize what diagnostic information is sent to the plugin or how the app should respond to any messages from the web user interface:

src/useMyDevToolsPlugin.ts
import { useDevToolsPluginClient } from 'expo/devtools'; export function useMyDevToolsPlugin() { const client = useDevToolsPluginClient('my-devtools-plugin'); const sendPing = () => { client?.sendMessage('ping', { from: 'app' }); }; return { sendPing, }; }

如果你更新了钩子以返回由应用调用的函数,你还需要更新 src/index.ts,以便在应用未处于调试模式时导出无操作函数:

🌐 If you update the hook to return functions that will be called by the app, you will also need to update src/index.ts so it exports no-op functions when the app is not running in debug mode:

src/index.ts
if (process.env.NODE_ENV !== 'production') { useMyDevToolsPlugin = require('./useMyDevToolsPlugin').useMyDevToolsPlugin; } else { useMyDevToolsPlugin = () => ({ + sendPing: () => {}, }); }

2

测试一个插件

🌐 Test a plugin

由于插件的网页用户界面是一个 Expo 应用,你可以像测试其他 Expo 应用一样用 npx expo start 测试它,不过你只会在浏览器中运行。该模板包含一个便捷命令,用于在本地开发模式下运行插件:

🌐 Since the plugin web UI is an Expo app, you can test it just like you would any other Expo app, with npx expo start, except that you will run it in the browser only. The template includes a convenience command to run the plugin in local development mode:

Terminal
npm run web:dev

3

构建一个用于分发的插件

🌐 Build a plugin for distribution

要准备好将你的插件分发或在你的多包仓库中使用,你需要使用以下命令构建插件:

🌐 To prepare your plugin for distribution or use within your monorepo, you will need to build the plugin with the following command:

Terminal
npm run build:all

此命令将把钩子代码构建到 build 目录中,并将网页用户界面构建到 dist 目录中。

🌐 This command will build the hook code into the build directory, and the web user interface into the dist directory.

4

使用插件

🌐 Use the plugin

将插件的钩子导入到应用的根组件中,并调用它以将应用连接到插件:

🌐 Import the plugin's hook into your app's root component and call it to connect your app to the plugin:

App.js
import { useMyDevToolsPlugin } from 'my-devtools-plugin'; import { Button } from 'react-native'; export default function App() { const { sendPing } = useMyDevToolsPlugin(); return ( <View style={styles.container}> <Button title="" onPress={() => { sendPing(); }} /> </View> ); }