Coder Social home page Coder Social logo

component-inspector's Introduction

NPM version Build Status

Component inspector

Example for React

General purpose of tool is showing components boundaries and its DOM fragment with some details. It could be extended by features like source fragment locating and opening file in editor. See Additional features section for details.

Generally it's an adoptation of basis.js tool for other component frameworks and libraries. Here is ready to use builds:

You also could setup custom API for your own component solution.

Install

npm install component-inspector --save-dev

Usage

There are 3 options to use Component Inspector:

  • use one of ready-to-use build for certain framework or library
  • use API free build and init inspector with custom API
  • make you own build as ready-to-use solution (PRs are welcome)

Ready to use builds

In case you use one of ready-to-use editions (i.e. React or Backbone) there is no any public API. Just include apropriate script and here you are.

React

React example

You should include component-inspector script before React script.

<script src="node_modules/component-inspector/dist/react.js"></script>
<script src="react.js"></script>

Backbone

Backbone example

You should include component-inspector script right after Backbone script.

<script src="backbone.js"></script>
<script src="node_modules/component-inspector/dist/backbone.js"></script>

API free build

In case you want to use inspector with your own API adapter you should use dist/base.js script. When script included into html only one public function available โ€“ initComponentInspector(api). This function could be invoked just once. It takes API methods that override defaults.

<script src="node_modules/component-inspector/dist/base.js"></script>
<script>
  initComponentInspector({
    isComponentRootNode: function(node){
      return Boolean(node && node.__view);
    },
    getInstanceByNode: function(node){
      if (node) {
        return node.__view;
      }
    },
    getInstanceRootNode: function(instance){
      if (instance) {
        return instance.rootNode;
      }
    }
  });
</script>

All methods are optional. Most important method is isComponentRootNode that checks DOM node is component root node. Also getInstanceByNode and getInstanceRootNode could be used to resolve DOM fragment owner (component instance) and owners root element. Other methods could provide additional information.

isComponentRootNode(node)

Returns true if DOM node is root node of some component. Uses to determine component boundaries.

getComponentNameByNode(node)

Returns component name if possible. This name using in component short details.

getInstanceByNode(node)

Function to resolve component owner by DOM node if any. Usually it's some kind of view instance.

getInstanceRootNode(instance)

Should return instance's root DOM node. It's vice versa function of getInstanceByNode(node). Using on DOM mutations to determine actual DOM node to inspect, as root DOM node could be changed on component re-render.

getInstanceClass(instance)

Should returns reference to instance class. Returns instance.constructor by default.

getInstanceLocation(instance)

Returns instance source location if possible. Normally no need to override it, as it returns api.getLocation(instance) by default.

getInstanceRenderLocation(instance)

By default it returns source location of instance.render method. You can override it if needed.

getNodeLocation(node)

If there is source location where DOM node was created this function should returns it. Uses in DOM viewer when hover nodes.

viewAttributeFilter(attribute)

Allow to filter output attributes in DOM viewer. For example, React adds data-reactid attribute to every element, but we don't want to show it. In this case, method could be:

viewAttributeFilter: function(attr){
  return attr.name !== 'data-reactid';
}

showDefaultInfo()

Show default info block or not. True by default.

getAdditionalInstanceInfo(instance, helpers)

Allow provide additional info for related objects. Should provide array of objects (configs for sections) or nothing. See more details in Custom info sections.

getLocation(value)

Should returns source location, where value was defined. By default return loc value from getDevInfo()

getDevInfo(value[, property])

Function provides dev info attached to value. It should returns info as is if no property argument and property value otherwise.

getDevInfo(value);
// { "loc": "file.js:1:2:3:4", ... }

getDevInfo(value, 'loc');
// "file.js:1:2:3:4"

buildComponentInfo(instance, node)

Customize component info object build. Default behaviour:

api.buildComponentInfo = function(instance, node){
  return {
    instance: instance,
    node: node
  };
};

logComponentInfo(info)

Defines actions on component info logging. Default actions:

api.logComponentInfo = function(info){
  window.$component = info;
  console.log(info);
};

isOpenFileSupported()

Returns true if open file in editor is supported. In this case click by source location links will call openFile method.

openFile(filename)

Should make some action to open specified filename in editor.

Custom info sections

There several ways to create custom info sections for inspectors sidebar. For all cases you should define getAdditionalInstanceInfo() method. You are free to use any framework or library to create a section.

NOTE: If you don't want to output default section with instance info use override showDefaultInfo API method to function(){ return false; }.

Location links

Most simple way is specify links list for some nested object. Here is example for model attached to instance:

api.getAdditionalInstanceInfo = function(instance){
  if (instance && instance.model) {
    return [{
      name: 'Model',
      locations: [
        { type: 'instance', loc: this.getLocation(instance.model) },
        { type: 'class', loc: this.getLocation(instance.model.constructor) }
      ]
    }];
  }
};

HTML view

If view should be created by some HTML markup, you can use section.html(name, html) helper:

api.getAdditionalInstanceInfo = function(instance, section){
  return [
    section.html('Custom section', '<h1>Hello world</h1>')
  ];
};

Pass empty string or null if you don't want to output a header of section.

DOM view

Any DOM node may to be specified as section. Use section.dom(name, nodeOrElement) helper in this case:

var view = document.createElement('h1');
view.appendChild(document.createTextNode('Hello world!'));

api.getAdditionalInstanceInfo = function(instance, section){
  return [
    section.dom('Custom section', view)
  ];
};

If DOM node attach approach is using (e.g. React), function should be passed to section.dom() helper:

api.getAdditionalInstanceInfo = function(instance, section){
  return [
    section.dom('Custom section', function(container){
      container.innerHTML = '<h1>Hello world!</h1>';
      container.onclick = function(){
        alert('Example!');
      };
    }),
    section.dom(null, function(container){
      React.render(<h1>Hello world!</h1>, container);
    })
  ];
};

Pass empty string or null if you don't want to output a header of section.

Links to source

To make a reference to source location add data-loc attribute to an element. You can use getLocation() method to fetch location for an object.

api.getAdditionalInstanceInfo = function(instance, section){
  return [
    section.html(null, 'This is a <span data-loc="' + this.getLocation(instance) + '">link</span>')
  ];
};

In this case the <span> becomes clickable (if open in editor feature is set up) and popup with source fragment will be shown on hover.

Make your own build

You can make your own ready-to-use edition, see React or Backbone as examples.

Implementation

First of all, you should include basis.js core (as inspector was originaly implemented using it) in your base html file and specify path to your implementation module.

<script src="node_modules/component-inspector/node_modules/basisjs/src/basis.js" basis-config="
  noConflict: true,    // prevents export names to global scope
  devpanel: false,
  modules: {
    myapi: {           // your implementation module
      autoload: true,
      filename: 'path/to/implementation.js'
    }
  }
"></script>

Example of implementation.js:

var initInspector = require('./inspector/index.js');

initInspector({
  isComponentRootNode: function(node){
    // ..
  },
  getInstanceByNode: function(node){
    // ..
  },
  getInstanceRootNode: function(instance){
    // ..
  }
});

Build

Install basisjs-tools

npm install basisjs-tools --save-dev

Run build with --single-file option.

node node_modules/basisjs-tools/bin/basis --file path/to/myinspector.html --single-file --pack --same-filenames

As result you'll get single JavaScript file (myinspector.js in this example) that contains everything. Include this script in your application page.

Additional features

Component inspector shows component bounds and its DOM fragment only. More details could be shown if some sort of meta-data (like source code location) is available.

There is example of default view for React component:

Component inspector w/o instrumenting

Compare it to the same view but with meta-data available:

Component inspector with instrumenting

You can use ready-to-use plugin for babel babel-plugin-source-wrapper to instrument your code with necessary API included. You free to use your own implementation. See documentation for details.

By default interface to get meta-data should be called $devinfo with at least single method get(). Inspector expects get method returns an object or falsy value if no data.

window.$devinfo = {
  get: function(ref){
    // return some information for `ref`
  }
};

If API has name other than $devinfo, it should be defined via global variable DEVINFO_API_NAME.

window.DEVINFO_API_NAME = 'customApiName';

Locating component's source

When meta-data is available for inspecting value, inspector expects location is storing in loc property as string filename:startLine:startColumn:endLine:endColumn.

window.$devinfo.get(obj);
// > { "loc": "app.js:...", ... }

If value definition source location is found some additional features became available: fetching source fragments and opening file in editor.

Fetching source fragments

Component inspector includes solution for retrieving original source code and highlight it. It's all possible if value location provided.

How does it work:

  • retrieve source code by request to server for original filename (or get it from cache if basisjs-tools server is used)
  • extract original source code with aware of source maps
  • cache the result
  • highligh code
  • get required source fragment and show it in popup

Since original files are fetching by request to server, make sure those files are available for downloading by your server.

NOTE: Inspector can show outdated source fragments due to cache. Page refresh should solve the problem.

Opening file in editor

Ready-to-use solutions to provide opening in editor feature on server:

In case dev-server supports opening in editor feature, all location references become active links. A click on any of those opens a file in editor with cursor set at the start of the code fragment. You'll see a hint if feature is supported.

One possible way to provide this feature is set global variable OPEN_FILE_URL.

window.OPEN_FILE_URL = '/open-in-editor';

When location link is clicked inspector sends request to server (see implementation for details):

GET /open-in-editor?file=/path/to/file.js:1:2:3:4

NOTE: Take in account if source file was changed since downloaded by browser, inspector could "open" file on wrong (outdated) position. Page refresh should solve the problem.

License

MIT

component-inspector's People

Contributors

flpvsk avatar lahmatiy avatar mavrin avatar mshustov avatar sergey-lapin avatar smacker avatar tenorok avatar vslinko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

component-inspector's Issues

Improve description about `open file in editor` feature

Current state:

One possible way to provide this feature is some url that does the job. This url could be set via global variable OPEN_FILE_URL.

window.OPEN_FILE_URL = '/open-in-editor';

More info and examples on how to implement this would be helpful.

Build non-minification bundles

I'm playing around with component-inspector and react, but I can't make it works with my project.
I see that "ready" callback was called, but there no component-inspector panel.
I tried to debug it, but with minified source it very hard.
Maybe you could build dist/react.js and dist/react.min.js? It will be much easer to debug without installing all basis staff.

Online Demo please?

This is a cool tool - would like to add to react.rocks to get more exposure...

Alternative for basisjs-tools to open file in editor feature

Ok, now I can see locations of my files, due to #3

Next step is open file in editor.
As I understand your basis server injects some API to the page.
I can't use basis server, but I want to use express middleware.
Could you tell me more about that API?

"open in editor" doesn't work on windows

Hello, lahmatiy, nice inspector, but i don't know how to resolve problem with "open in editor".
I can't see link.

Code:

<script>window.OPEN_FILE_URL = '/open-in-editor';</script>
<script src="node_modules/component-inspector/dist/react.js"></script>
<script src="dist/bundle.js"></script>

Also the message "Open file in editor` is not supported" (or other messages) don't show in the console.

Links to component class

Now component-inspector shows me only component instance location:
Alt text

How to enable all features from this gif?

`Open file in editor` is not supported

I have managed to get all features working except opening in sublime by click. I guess I need basisjs-tools for that also, but not sure.
BTW, thanks for sharing this!

How to make file locations visible?

I'm using component-inspector with react but without basis server.
As I see, transpiled source contains references to the file locations but those locations doesn't visible in the inspector popup.
I try to find a reason inside your source code but it's too hard for me and I need your help.

Hope be much frendly to setup custom API

It's hard to setup custom with current package, because the is no development model , such as code watch , debugger env and any auxiliary tools, and did not even report an error (
Maybe the method I tried has a problem ).

For example, if I want to setup custom API base on match the React 16 , I will feel that I can't start.

So, I am curious about how you setup custom API base React 15 ?

Add support React 16.*

  • Use prop-types from separate package
  • Use strategy for different React versions in react/create-api.js instead if else hell

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.