npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

shanda-react-dev-inspector

v1.0.1

Published

dev-tool for inspect react components and jump to local IDE for component code.

Downloads

7

Readme

Introduction

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.

Preview

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):

inspector-gif

Installation

npm i -D react-dev-inspector

Usage

for VSCode only, but simple without any other configuration

Works with almost all react frameworks such as Vite, Next.js, Create React App, Umi3, 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
            // you can change the url protocol if you are using in Web IDE
            window.open(`vscode://file/${absolutePath}:${lineNumber}:${columnNumber}`)
          }}
        >
      )}
    </>
  )
}

Whether you use vscode://, webstorm:// or otherwise, it solidifies in code.

sometime you want it infer which is the current local IDE you are using now.

But for generally infer current local IDE, need some server-side configuration. At this time, follow those TWO steps below:

1. Add Inspector React Component

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']}
          onHoverElement={(inspect: InspectParams) => {}}
          onClickElement={(inspect: InspectParams) => {}}
        >
      )}
    </>
  )
}

2. Set up Inspector Config

You should add:

  • an inspector babel plugin, to inject source code location info
    • react-dev-inspector/plugins/babel
  • an server api middleware, to open local IDE
    • import { launchEditorMiddleware } from 'react-dev-inspector/plugins/webpack'

to your current project development config.

Such as add babel plugin into your .babelrc or webpack babel-loader config, add api middleware into your webpack-dev-server config or other server setup.

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

raw webpack config

Support webpack v4 and v5, examples see:

// .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',
  ],
}

// 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 manully 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 create-react-app@^5 + webpack-dev-server@^4.7
     */
    setupMiddlewares: (middlewares, devServer) => {
      middlewares.unshift(launchEditorMiddleware)
      return middlewares
    },

    /**
     * react-dev-inspector - dev server config
     * for create-react-app@^4 + webpack-dev-server@^3
     */
    before: (app, server, compiler) => {
      app.use(launchEditorMiddleware)

      // ... other middlewares after
    },
  },
}

usage with Vite2

example 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(),
  ],
})

usage with Next.js

use Next.js Custom Server + Customizing Babel Config

example project see: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/nextjs

...

const {
  queryParserMiddleware,
  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
       */
      queryParserMiddleware,
      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}`)
  })
})

  "scripts": {
-    "dev": "next dev",
+    "dev": "node server.js",
    "build": "next build"
  }

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',
  ],
}

usage with create-react-app

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:

const {
  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
    },
  ),
}

usage with Umi3

example 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: [],
  },
})

usage with Umi2

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
  },
}

usage with Ice.js

// https://ice.work/docs/guide/basic/build
{
  "plugins": [
    "react-dev-inspector/plugins/ice",
  ]
}

Examples Project Code

  • vite2
    • code: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/vite2
    • preview: https://react-dev-inspector.zthxxx.me/vite2
  • next.js
    • code: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/nextjs
    • preview: https://react-dev-inspector.zthxxx.me/nextjs
  • create-react-app
    • code: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/cra
    • preview: https://react-dev-inspector.zthxxx.me/cra
  • umi3
    • code: https://github.com/zthxxx/react-dev-inspector/tree/master/examples/umi3
    • preview: https://react-dev-inspector.zthxxx.me/umi3

Configuration

<Inspector> Component Props

checkout TS definition under react-dev-inspector/es/Inspector.d.ts.

| Property | Description | Type | Default | | ------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------- | | keys | inspector hotkeyssupported keys see: https://github.com/jaywcjlove/hotkeys#supported-keys | string[] | ['control', 'shift', 'command', 'c'] | | disableLaunchEditor | disable editor launching(launch by default in dev Mode, but not in production mode) | boolean | false | | onHoverElement | triggered when mouse hover in inspector mode | (params: InspectParams) => void | - | | onClickElement | triggered when mouse hover in inspector mode | (params: InspectParams) => void | - |

// 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,
}

Inspector Babel Plugin Options

interface InspectorPluginOptions {
  /** override process.cwd() */
  cwd?: string,
  /** patterns to exclude matched files */
  excludes?: (string | RegExp)[],
}

Inspector Loader Props

// 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,
}

IDE / Editor config

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.

VSCode

  • install VSCode command line tools, see the official docs install-vscode-cli

  • set env to shell, like .bashrc or .zshrc

    export REACT_EDITOR=code

WebStorm

  • just set env with an absolute path to shell, like .bashrc or .zshrc (only MacOS)
    export REACT_EDITOR='/Applications/WebStorm.app/Contents/MacOS/webstorm'

OR

  • install WebStorm command line tools install-webstorm-cli

  • then set env to shell, like .bashrc or .zshrc

    export REACT_EDITOR=webstorm

Vim

Yes! you can also use vim if you want, just set env to shell

export REACT_EDITOR=vim

How It Works

  • Stage 1 - Compile Time

    • [babel plugin] inject source file path/line/column to JSX data attributes props
  • 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)

Analysis of Theory

License

MIT LICENSE