AsaAyers / js-hyperclick

A hyperclick provider that lets you jump to where variables are defined.
MIT License
127 stars 42 forks source link

Add custom resolvers to allow projects to handle things like webpack aliases #105

Closed AsaAyers closed 6 years ago

AsaAyers commented 6 years ago

One of the most popular requests in this repo has been to support Webpack Aliases and other non-standard resolution strategies. This PR is expanding the functionality of moduleRoots to allow you to write a custom resolver for your own project. If you want to require() your webpack config and read the aliases, you can do that in version 1.15.

moduleRoots

If you have configured your project to avoid ../ in your imports, you can configure js-hyperclick using moduleRoots in your package.json. The configuration belongs there and not in Atom because it is specific to your project.

For most use cases, you just need to specify the folders to search. If you want import 'foo' to resolve to src/lib/foo, just drop this in your package.json.

"moduleRoots": [ "src/lib" ],

If you're using something more advanced like module aliases you can implement your own custom resolver. Instead of pointing moduleRoots to a folder, just point it to a JavaScript file and js-hyperclick will require() and use it *.

While js-hyperclick doesn't use these kinds of features in practice, I have configured them as an example and to validate functionality.

  1. moduleRoots configuration in package.json
  2. custom-resolver.js
  3. spec/fixtures/moduleRoots.js

Custom Resolver Security

Custom resolvers run inside Atom and extend the functionality of js-hyperclick. This means there is some risk that you could checkout a project that contains a malicious custom resolver. In order to mitigate this risk, when js-hyperclick encounters a new resolver it will open it and ask if you want to trust it. Whether you trust or distrust the resolver, js-hyperclick stores that hash so you don't get prompted when switching between branches of a project, or if you have use the exact same resolver code across multiple projects.

trust-resolver

Fixes #97 Fixes #92 Fixes #78 Fixes #58 Fixes #54 Fixes #47 Fixes #46 Fixes #25

thebarty commented 6 years ago

This is really interesting. It would be cool to have a receipe on how to make this work with Meteor (Make this work with meteor? #46) Right now I am really busy and how no time to try it out myself, but if there was a cheatsheet I'd be ready to go

AsaAyers commented 6 years ago

https://github.com/AsaAyers/js-hyperclick/blob/6240dc8dd738371d380a1c875f543887ae5eb65d/spec/fixtures/moduleRoots.js#L8-L9

https://github.com/AsaAyers/js-hyperclick/blob/6240dc8dd738371d380a1c875f543887ae5eb65d/custom-resolver.js#L28-L32

boltcoder commented 5 years ago

It'd be great if you could support webpack aliases fully. Currently your code doesn't support named aliases. eg: projects usually have aliases as following

{
"myAppContainers": "./src/containers/",
"myAppComponents": "./src/components/",
}

And while importing this is how they are imported import MainAppContainer from 'myAppContainers/MainApp';

AsaAyers commented 5 years ago

I don't support reading the aliases from Webpack's config, but you can configure js-hyperclick to match your config.

On Sun, Mar 24, 2019, 7:57 AM boltcoder notifications@github.com wrote:

It'd be great if you could support webpack aliases fully. Currently your code doesn't support named aliases. eg: projects usually have aliases as following

{ "myAppContainer": "./src/containers/", "myAppComponents": "./src/components/", }

And while importing this is how they are imported import MainAppContainer from 'myAppContainer/MainApp';

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/AsaAyers/js-hyperclick/pull/105#issuecomment-475966950, or mute the thread https://github.com/notifications/unsubscribe-auth/AAT1h72m899nta0yV-VAjT0DQU3OxzCrks5vZ5JFgaJpZM4YY67w .

boltcoder commented 5 years ago

aah. I'm not sure if I can achieve js-hyperclick to match to the above use case. unless I'm missing something. Would be great if you can help me.

AsaAyers commented 5 years ago

If your prefix just matched the folder name, then you'd just need "moduleRoots": [ 'src' ] in your package.json and you'd be done. import MainAppContainer from 'myAppContainers/MainApp'; will give you src/MyAppContainers/MainApp.

But since you decided not make them match anything you need a custom resolver. In package.json

  "moduleRoots": [
    "custom-resolver.js"
  ],

I just put this together from the custom-resolver that this project has as example for building your own.

const path = require('path')
export default function customResolver({ basedir, moduleName }) {
  // You can use whatever strategy you want to convert your modules
  const [prefix, ...rest] = moduleName.split("/")
  switch (prefix) {
    case "myAppContainers": return path.join(__dirname, "./src/containers/", rest.join(path.sep))
    case "myAppComponents": return path.join(__dirname, "./src/components/", res.join(path.sep))
  }
}