This package allows users to jump to local IDE code directly from browser React component by just a simple click, which is similar to Chrome inspector but more advanced.
online demo: https://react-dev-inspector.zthxxx.me
press hotkey (
ctrl⌃ + shift⇧ + commmand⌘ + c
), then click the HTML element you wish to inspect.
screen record gif (8M size):
npm i react-dev-inspector
Works with almost all react frameworks such as Vite, Next.js, Rspack, Umi4 / Umi3, Create React App, Ice.js,
or any other which use @babel/plugin-transform-react-jsx-source in builtin. Just follow the component code below:
import React from 'react' import { Inspector, InspectParams } from 'react-dev-inspector' const isDev = process.env.NODE_ENV === 'development' export const Layout = () => { // ... return ( <> <YourComponent /> {isDev && ( <Inspector // props see docs: // https://github.com/zthxxx/react-dev-inspector#inspector-component-props keys={['control', 'shift', 'command', 'c']} disableLaunchEditor={true} onClickElement={({ codeInfo }: InspectParams) => { if (!codeInfo?.absolutePath) return const { absolutePath, lineNumber, columnNumber } = codeInfo window.open(`vscode://file/${absolutePath}:${lineNumber}:${columnNumber}`) // you can change the url protocol if you are using another IDE, like for WebStorm: // window.open(`webstorm://open?file=${absolutePath}&line=${lineNumber}&column=${columnNumber}`) }} /> )} </> ) }
Whether you use vscode://
, webstorm://
, or another protocol, it's hardcoded in the code.
Sometime you want it infer which is the current local IDE you or your different team member are using now.
Sometimes, you might want it to infer the current local IDE that you or your team members are using.
To generally infer the current local IDE, server-side configuration is required. Follow the TWO steps below:
1. Add Inspector React Componentimport React from 'react' import { Inspector, InspectParams } from 'react-dev-inspector' const isDev = process.env.NODE_ENV === 'development' export const Layout = () => { // ... return ( <> <YourComponent /> {isDev && ( <Inspector // props see docs: // https://github.com/zthxxx/react-dev-inspector#inspector-component-props // keys={['control', 'shift', 'command', 'c']} // onHoverElement={(inspect: InspectParams) => {}} // onClickElement={(inspect: InspectParams) => {}} /> )} </> ) }
In server side, You need to add:
import { launchEditorMiddleware } from 'react-dev-inspector/plugins/webpack'
react-dev-inspector/plugins/babel
to your current project development config.
Such as add server middleware into your webpack-dev-server
config or other server setup, add the babel plugin (optional) into your .babelrc
or webpack babel-loader
config.
Note: The
react-dev-inspector/plugins/babel
is optional. Most React frameworks/scaffolds already integrate the @babel/plugin-transform-react-jsx-source or an equivalent inswc
to inject the absolute path for source code on React Fiber,while the
react-dev-inspector
's plugin refining to inject the relative path on DOM for brevity and clarity to debug.
There are some example ways to set up, please pick the one fit your project best.
In common cases, if you're using webpack, you can see #raw-webpack-config,
If your project happen to use vite / nextjs / create-react-app and so on, you can also try out our integrated plugins / examples with
Support webpack v4 and v5, examples see:
webpack.config.ts// webpack.config.ts import type { Configuration } from 'webpack' import { ReactInspectorPlugin } from 'react-dev-inspector/plugins/webpack' const config: Configuration = { plugins: [ /** * react-dev-inspector webpack plugin * this plugin will create * `devServer.setupMiddlewares` config for webpack5 * and `devServer.before` config for webpack4 */ new ReactInspectorPlugin(), ], }
However, if you want more manually config with webpack-dev-server
, here are some equivalent:
// webpack.config.ts import type { Configuration } from 'webpack' import { launchEditorMiddleware } from 'react-dev-inspector/plugins/webpack' const config: Configuration = { devServer: { /** * react-dev-inspector - dev server config * for webpack-dev-server@^4 */ setupMiddlewares: (middlewares, devServer) => { middlewares.unshift(launchEditorMiddleware) return middlewares }, /** * react-dev-inspector - dev server config * for webpack-dev-server@^3 */ before: (app, server, compiler) => { app.use(launchEditorMiddleware) // ... other middlewares after }, }, }.babelrc.js
// .babelrc.js module.exports = { plugins: [ /** * react-dev-inspector plugin, options docs see: * https://github.com/zthxxx/react-dev-inspector#inspector-babel-plugin-options */ 'react-dev-inspector/plugins/babel', ], }
compatible with vite@3 / vite@4.
vite.config.tsexample project see: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/vite2
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { inspectorServer } from 'react-dev-inspector/plugins/vite' export default defineConfig({ plugins: [ react(), /** * react-dev-inspector configuration * only need setup an inspector middleware */ inspectorServer(), ], })
use Next.js Custom Server + Customizing Babel Config
server.jsexample project see: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/nextjs
... const { launchEditorMiddleware, } = require('react-dev-inspector/plugins/webpack') app.prepare().then(() => { createServer((req, res) => { /** * middlewares, from top to bottom */ const middlewares = [ /** * react-dev-inspector configuration, two middlewares for nextjs */ launchEditorMiddleware, /** Next.js default app handle */ (req, res) => handle(req, res), ] const middlewarePipeline = middlewares.reduceRight( (next, middleware) => ( () => { middleware(req, res, next) } ), () => {}, ) middlewarePipeline() }).listen(PORT, (err) => { if (err) throw err console.debug(`> Ready on http://localhost:${PORT}`) }) })package.json
"scripts": { - "dev": "next dev", + "dev": "node server.js", "build": "next build" }.babelrc.js
module.exports = { plugins: [ /** * react-dev-inspector plugin, options docs see: * https://github.com/zthxxx/react-dev-inspector#inspector-babel-plugin-options */ 'react-dev-inspector/plugins/babel', ], }
import { defineConfig } from '@rspack/cli' import { launchEditorMiddleware } from 'react-dev-inspector/plugins/webpack' export default defineConfig({ devServer: { /** * react-dev-inspector server config for rspack */ setupMiddlewares(middlewares) { middlewares.unshift(launchEditorMiddleware) return middlewares }, }, })
create-react-app + react-app-rewired + customize-cra example config-overrides.js
:
example project see: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/cra
Support create-react-app v4, v5, example config see:
config-overrides.jsconst { launchEditorMiddleware, ReactInspectorPlugin, } = require('react-dev-inspector/plugins/webpack') const { override, overrideDevServer, addBabelPlugin, } = require('customize-cra') /** * origin config: * https://github.com/facebook/create-react-app/blob/v5.0.1/packages/react-scripts/config/webpack.config.js * https://github.com/facebook/create-react-app/blob/v5.0.1/packages/react-scripts/config/webpackDevServer.config.js * * customize-cra api code: https://github.com/arackaf/customize-cra */ module.exports = { webpack: override( /** react-dev-inspector - babel config */ addBabelPlugin([ // plugin options docs see: // https://github.com/zthxxx/react-dev-inspector#inspector-babel-plugin-options 'react-dev-inspector/plugins/babel', { excludes: [ /xxxx-want-to-ignore/, ], }, ]), /** * react-dev-inspector - dev server config * for create-react-app@^4 + webpack-dev-server@^3 */ addWebpackPlugin( new ReactInspectorPlugin(), ), ), /** * react-dev-inspector - dev server config * for create-react-app@^5 + webpack-dev-server@^4.7 */ devServer: overrideDevServer( serverConfig => { // https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares serverConfig.setupMiddlewares = (middlewares) => { middlewares.unshift(launchEditorMiddleware) return middlewares } return serverConfig }, ), }
.umirc.dev.tsexample project see: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/umi3
// https://umijs.org/config/ import { defineConfig } from 'umi' export default defineConfig({ plugins: [ 'react-dev-inspector/plugins/umi/react-inspector', ], inspectorConfig: { // babel plugin options docs see: // https://github.com/zthxxx/react-dev-inspector#inspector-babel-plugin-options excludes: [], }, })
import { launchEditorMiddleware } from 'react-dev-inspector/plugins/webpack' export default { // ... extraBabelPlugins: [ // plugin options docs see: // https://github.com/zthxxx/react-dev-inspector#inspector-babel-plugin-options 'react-dev-inspector/plugins/babel', ], /** * And you need to set `false` to `dll` in `umi-plugin-react`, * becase these is a umi2 bug that `dll` cannot work with `devServer.before` * * https://github.com/umijs/umi/issues/2599 * https://github.com/umijs/umi/issues/2161 */ chainWebpack(config, { webpack }) { const originBefore = config.toConfig().devServer config.devServer.before((app, server, compiler) => { app.use(launchEditorMiddleware) originBefore?.before?.(app, server, compiler) }) return config }, }
// https://ice.work/docs/guide/basic/build { "plugins": [ "react-dev-inspector/plugins/ice", ] }
<Inspector>
Component Props
checkout TS definition under react-dev-inspector/es/Inspector.d.ts
.
// import type { InspectParams } from 'react-dev-inspector' interface InspectParams { /** hover / click event target dom element */ element: HTMLElement, /** nearest named react component fiber for dom element */ fiber?: React.Fiber, /** source file line / column / path info for react component */ codeInfo?: { lineNumber: string, columnNumber: string, /** * code source file relative path to dev-server cwd(current working directory) * need use with `react-dev-inspector/plugins/babel` */ relativePath?: string, /** * code source file absolute path * just need use with `@babel/plugin-transform-react-jsx-source` which auto set by most framework */ absolutePath?: string, }, /** react component name for dom element */ name?: string, }
interface InspectorPluginOptions { /** override process.cwd() */ cwd?: string, /** patterns to exclude matched files */ excludes?: (string | RegExp)[], }
// import type { ParserPlugin, ParserOptions } from '@babel/parser' // import type { InspectorConfig } from 'react-dev-inspector/plugins/webpack' interface InspectorConfig { /** patterns to exclude matched files */ excludes?: (string | RegExp)[], /** * add extra plugins for babel parser * default is ['typescript', 'jsx', 'decorators-legacy', 'classProperties'] */ babelPlugins?: ParserPlugin[], /** extra babel parser options */ babelOptions?: ParserOptions, }
This package uses react-dev-utils
to launch your local IDE application, but, which one will be open?
In fact, it uses an environment variable named REACT_EDITOR
to specify an IDE application, but if you do not set this variable, it will try to open a common IDE that you have open or installed once it is certified.
For example, if you want it always open VSCode when inspection clicked, set export REACT_EDITOR=code
in your shell config like .bashrc
or .zshrc
, don't forget restart shell or IDE to reload the updated environment variable.
install VSCode command line tools, follow the official docs, you need to run the command: >Shell Command: Install 'code' command in PATH
set env to shell, like .bashrc
or .zshrc
.bashrc
or .zshrc
(only MacOS)
export REACT_EDITOR='/Applications/WebStorm.app/Contents/MacOS/webstorm'
OR
then set env to shell, like .bashrc
or .zshrc
export REACT_EDITOR=webstorm
Yes! you can also use vim if you want, just set env to shell
Stage 1 - Compile Time
Stage 2 - Web React Runtime
[React component] Inspector
Component in react, for listen hotkeys, and request api to dev-server for open IDE.
Specific, when you click a component DOM, the Inspector
will try to obtain its source file info (path/line/column), then request launch-editor api (in stage 3) with absolute file path.
Stage 3 - Dev-server Side
[middleware] setup launchEditorMiddleware
in webpack dev-server (or other dev-server), to open file in IDE according to the request params.
Only need in development mode,and you want to open IDE when click a component element.
Not need in prod mode, or you just want inspect dom without open IDE (set disableLaunchEditor={true}
to Inspector component props)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4