Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No API object for function configuration #36

Open
tilgovi opened this issue Oct 14, 2019 · 9 comments
Open

No API object for function configuration #36

tilgovi opened this issue Oct 14, 2019 · 9 comments

Comments

@tilgovi
Copy link

tilgovi commented Oct 14, 2019

If a configuration file exports a function, it is not called with any arguments.

It should be called with an API object: https://babeljs.io/docs/en/config-files#config-function-api

@tilgovi
Copy link
Author

tilgovi commented Oct 14, 2019

Since this module also does not resolve plugins and presets, a lot of the work can probably be replaced with loadPartialConfig({ configFile }) from @babel/core. It returns an object with options.

@0xdevalias
Copy link

0xdevalias commented Nov 22, 2019

I've also just hit this issue while trying to use https://github.com/tleunen/babel-plugin-module-resolver:

Error while loading rule 'module-resolver/use-alias': Cannot read property 'env' of undefined
TypeError: Error while loading rule 'module-resolver/use-alias': Cannot read property 'env' of undefined
    at module.exports.api (./babel.config.js:5:24)
    at getBabelJsConfig (./node_modules/find-babel-config/lib/index.js:21:16)
    at Function.findBabelConfigSync [as sync] (./node_modules/find-babel-config/lib/index.js:152:27)
    at Object.create (./node_modules/eslint-plugin-module-resolver/dist/rules/use-alias.js:79:49)
    at createRuleListeners (./node_modules/eslint/lib/linter.js:682:21)
    at Object.keys.forEach.ruleId (./node_modules/eslint/lib/linter.js:841:31)
    at Array.forEach (<anonymous>)
    at runRules (./node_modules/eslint/lib/linter.js:781:34)
    at Linter._verifyWithoutProcessors (./node_modules/eslint/lib/linter.js:1003:33)
    at preprocess.map.textBlock (./node_modules/eslint/lib/linter.js:1046:35)

My workaround was to mock out the aspects of api that we require (namely env), based on the docs:

// If we aren't passed an api, mock one out here..
// Ref: https://babeljs.io/docs/en/config-files#apienv
const fakedApiObject = {
  env: checkEnv => {
    const envName = process.env.NODE_ENV || 'development'

    if (typeof checkEnv === 'string') {
      return checkEnv === envName
    } else if (Array.isArray(checkEnv)) {
      return checkEnv.includes(envName)
    } else if (typeof checkEnv === 'function') {
      return checkEnv(envName)
    } else {
      return envName
    }
  }
}

module.exports = (api = fakedApiObject) => {
// ..snip..

That ends up getting further, but then is dying on this (but that is likely more related to eslint-plugin-module-resolver than this package):

TypeError: Cannot read property 'loc' of undefined
    at CallExpression (./node_modules/eslint-plugin-module-resolver/dist/rules/use-alias.js:108:36)
    at listeners.(anonymous function).forEach.listener (./node_modules/eslint/lib/util/safe-emitter.js:47:58)
    at Array.forEach (<anonymous>)
    at Object.emit (./node_modules/eslint/lib/util/safe-emitter.js:47:38)
    at NodeEventGenerator.applySelector (./node_modules/eslint/lib/util/node-event-generator.js:251:26)
    at NodeEventGenerator.applySelectors (./node_modules/eslint/lib/util/node-event-generator.js:280:22)
    at NodeEventGenerator.enterNode (./node_modules/eslint/lib/util/node-event-generator.js:294:14)
    at CodePathAnalyzer.enterNode (./node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:608:23)
    at Traverser.enter [as _enter] (./node_modules/eslint/lib/linter.js:865:28)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:132:14)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:147:30)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:144:34)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:144:34)
    at Traverser.traverse (./node_modules/eslint/lib/util/traverser.js:115:14)
    at runRules (./node_modules/eslint/lib/linter.js:862:15)
    at Linter._verifyWithoutProcessors (./node_modules/eslint/lib/linter.js:1003:33)

Super cutting down the file it's failing on, it basically looks like this:

import { makeFile } from '../../../helpers/file-helpers'

const file = makeFile()

The file-helpers exists correctly at that path, the error seems to occur regardless of whether it contains any content/exports though.

It seems it may be related to it not being able to find my module-transform config in my babel config, as I was doing it through jest's babel config override section. If I comment everything aside from the relative path import i get the following eslint error:

warning  Unable to find config for babel-plugin-module-resolver  module-resolver/use-alias

Which goes away once i add the config back in :

[
  'module-resolver',
  {
    root: ['./spec/javascripts'],
    alias: {
      'test-helpers': './helpeaaarstestfoo',
    },
  },
],

I'm not 100%.. but I think this could possibly also be solved by using loadPartialConfig from @babel/core, as I know jest makes use of similar to add it's own config changes. I expect what this rule is seeing isn't representative of the final babel config as jest/etc would see it.

Edit: Opened HeroProtagonist/eslint-plugin-module-resolver#44 RE: the 2nd part of my issue here with further details.

@HeroProtagonist
Copy link
Contributor

@0xdevalias @tilgovi

I added support for config files with these lines. No value is passed into the config when it is called, so it makes sense that this happens.

Do you guys know if babel exports this api object so we could pass it in? Or is there a better way to handle the config when it is a function?

@tilgovi
Copy link
Author

tilgovi commented Dec 4, 2019

Do you guys know if babel exports this api object so we could pass it in? Or is there a better way to handle the config when it is a function?

@babel/core may do everything you need:

> require('@babel/core').loadPartialConfig({ rootMode: 'upward-optional' })
PartialConfig {
  options: {
    rootMode: 'upward-optional',
    babelrc: false,
    configFile: false,
    passPerPreset: false,
    envName: 'development',
    cwd: '...',
    root: '...',
    filename: undefined,
    plugins: [ [ConfigItem], [ConfigItem], [ConfigItem] ],
    presets: [ [ConfigItem] ]
  },
  babelignore: undefined,
  babelrc: undefined,
  config: '.../babel.config.js'
}

@tilgovi
Copy link
Author

tilgovi commented Dec 4, 2019

Unfortunately, I suspect there are probably exotic uses of find-babel-config and babel-plugin-module-resolver and eslint-import-resolver-babel-module and places where options that may be important to pass might conflict with their meaning for this function.

I made an effort to catalogue some of the issues here: tleunen/eslint-import-resolver-babel-module#89 (comment)

My recommendation, at this point, would be to try out a branch of eslint-resolver-babel-module and babel-plugin-module-resolver that just use the core loadPartialConfig function and nothing else. Possibly a near total rewrite. If it works, it would greatly simplify the whole situation and you could bump a major version number.

@tilgovi
Copy link
Author

tilgovi commented Dec 4, 2019

My recommendation, at this point, would be to try out a branch of eslint-resolver-babel-module and babel-plugin-module-resolver that just use the core loadPartialConfig function and nothing else. Possibly a near total rewrite. If it works, it would greatly simplify the whole situation and you could bump a major version number.

I think that would look like option 4 in my comment. The babel-plugin-module-resolver would not use this package (find-babel-config) at all. It should either use the current working directory, or an explicit root, or get it from the babel configuration somehow. I don't know if Babel passes the root directory through to plugins or not, but Babel definitely knows it. If it doesn't pass it, use loadPartialConfig to find it. Then eslint-import-resolver-babel-module should not take any configuration that isn't a Babel configuration option used for finding the config, and all other options should be taken from the configuration for babel-plugin-module-resolver.

@tilgovi
Copy link
Author

tilgovi commented Dec 4, 2019

Just in case it doesn't go without saying: none of this is meant as an attack. Thank you for your work on these projects. They've been immensely helpful to me. If I can help by prototyping any of the above, please let me know what makes sense to you.

@tleunen
Copy link
Owner

tleunen commented Dec 12, 2019

@tilgovi - No worries, I don't take it personally. I've been away from these projects for a long time because I'm not an active user/consumer of these anymore. So it's hard for me to find the time and the motivation to keep improving them.

I'd like to update this library to use loadPartialConfig since Babel provides this function now.
In term of babel-plugin-module-resolver using this package or not, we can debate this in its own repo as well. If loadPartialConfig makes it super easy, I don't see a real valid use case of keeping find-babel-config honestly.

@tilgovi
Copy link
Author

tilgovi commented Dec 12, 2019

Cool. I'll let you know what I find.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants