Ava: Allow CJS ava.config.js

Created on 30 May 2018  Â·  26Comments  Â·  Source: avajs/ava

Description

I noticed that #1761 landed requiring ava.config.js to use ESM (export default rather than module.exports =). I read through the thread, and I guess I can understand wanting to support ESM, but what was the motivation for making it a requirement?

Most other libraries only support CJS configs, and I don't know of any that _only_ allow ESM. It seems odd to require AVA's config to be written differently than all other config files in a typical repo.

question

Most helpful comment

Looking at the esm options we could enable the cjs.vars option. That would expose __dirname, __filename and require to the ava.config.js file

Let's go with this.

All 26 comments

It's an aversion from having too many ways of specifying config. Though perhaps odd at first, hopefully it's actually fine in practice. Let's use this issue to see if there are any problems and then we can add support for module.exports = {}.

It's an aversion from having too many ways of specifying config.

I have the same aversion, but from the perspective of a user using multiple tools in projects. I try to write my config files similarly to each other, so that they're easy to write, read, and modify. This becomes difficult when tools have divergent config formats.

So, from my perspective, ESM _is_ a different way of specifying config, in that it's different from other tools, e.g. webpack, Babel, postcss, ESLint, stylelint, husky.

(That's why I'm a big fan of cosmiconfig, which is already used by many of the above -- by default, it supports a well-known, conventional set of formats which strike a good balance between user flexibility and complexity. It also reduces the burden on module authors to implement config lookup/loading, and provides consistent lookup/loading behavior _between_ tools.)

I understand the tradeoff on simplicity, and I know that @sindresorhus has a strong preference for it. But if AVA is determined to support a single format, would you consider only supporting CJS? I'd think this would be the expected behavior at least until ESM is widely embraced in node (whether via esm, .mjs, or something else). Until then, this doesn't seem like a useful divergence.

Thanks for the discussion, by the way -- thrilled to be getting file-based config in any case.

I don't really see the problem here. AVA has had built-in ESM support for years, so AVA users are used to using it. Extending it to the config makes sense in that way.

on a possibly related note ... i nearly had had to downgrade my package.json's 'esm' configuration from { mode: "strict" } to "auto" because

  • (at least according to the documentation I have read) there is no ava --config <CONFIG-FILE> CLI option,
  • the file must be named 'ava.config.js'
  • "strict" enforces an '.mjs' extension on files which use ESM syntax

if a CSJ export was supported, this wouldn't be an issue. fortunately i have the fallback to use the { ava } configuration option in package.json -- and that allows me to keep "strict"

on a related but tangential note, i have (so far) had no success in telling ava to glob for 'test/ava/*.mjs'

[x] Couldn't find any files to test

i have just started to integrate ava, so i could be making foolish mistakes / not RTFM properly

@cantremember thanks for the report. I suspect this is an issue with esm itself. I've opened https://github.com/standard-things/esm/issues/501.

I'm trying to use require.resolve in the config and getting require is not defined. Is this related, and is there a workaround?

@vjpr I imagine it is, yea.

What are you hoping to achieve?

esm does expose an import.meta object I believe.

I need to require.resolve a babel plugin, because its trying to resolve from the project root, and I want it to resolve in a monorepo subpackage.

It's not ideal but perhaps you could use https://www.npmjs.com/package/resolve-from?

Or maybe it's possible to provide a relative path to the plugin? Assuming this goes into AVA's Babel pipeline, I'd expect it to be resolved relative to the project directory, so you should be able to reference the subpackage.

I'll try resolve-from. Why is require.resolve not available though?

@vjpr I reckon esm (which we use to load the ava.config.js files) masks it.

I'm still having a lot of trouble with this. I have an es5 library in my codebase that needs to run in the ava.config.js file, but it seems its not possible.

Why do we not allow cjs features when using esm to load the config?

@vjpr What is the exact problem/error?

SyntaxError: The requested module 'file:///xxx/bar.js' does not provide an export named 'attempt'

_ava.config.js_

export {default} from './foo.js'

_foo.js_

import {attempt} from './bar'
export default 1

_bar.js_

exports.attempt = 1

I agree that should work, @vjpr.

It's an interesting problem. Our default Babel pipeline supports importing from CJS, with __esModule interoperability. But, we don't want to apply that to loading the config file, especially if Babel is disabled through that file.

Between ESM, CJS and interoperability there's a lot of ways a config file could be written. At least ESM is more forward looking, and we can use the esm module to load the file without any other precompilation.

Currently esm is configured to only allow ESM modules. That way we don't introduce any non-standard behavior or rely on esm implementation details. It's great if you're already using esm in the rest of your codebase but of course that's not necessarily the case.

Looking at the esm options we could enable the cjs.vars option. That would expose __dirname, __filename and require to the ava.config.js file and other imported ESM modules. That'll allow you to use require() to load CJS modules.

Would this work for you?

Another option is to run esm in full compatibility mode, or just inherit the esm settings in your project. The downside is that it really couples us to esm's behavior.

@sindresorhus what do you think?

I'd like full compat but vars might help too.

Currently the behavior is very limiting. Use case: u have a shared CJS
config file which you want to require your a a config from. It's not
possible unless your codebase is entirely ESM.

On Sun 27. Jan 2019 at 15:06, Mark Wubben notifications@github.com wrote:

I agree that should work, @vjpr https://github.com/vjpr.

It's an interesting problem. Our default Babel pipeline supports importing
from CJS, with __esModule interoperability. But, we don't want to apply
that to loading the config file, especially if Babel is disabled through
that file.

Between ESM, CJS and interoperability there's a lot of ways a config file
could be written. At least ESM is more forward looking, and we can use the
esm module to load the file without any other precompilation.

Currently esm is configured to only allow ESM modules. That way we don't
introduce any non-standard behavior or rely on esm implementation
details. It's great if you're already using esm in the rest of your
codebase but of course that's not necessarily the case.

Looking at the esm options https://www.npmjs.com/package/esm#options we
could enable the cjs.vars option. That would expose __dirname, __filename
and require to the ava.config.js file and other imported ESM modules.
That'll allow you to use require() to load CJS modules.

Would this work for you?

Another option is to run esm in full compatibility mode, or just inherit
the esm settings in your project. The downside is that it really couples
us to esm's behavior.

@sindresorhus https://github.com/sindresorhus what do you think?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/avajs/ava/issues/1820#issuecomment-457920740, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AARLRQDhnKRXVWddu55HayrsYJ92RFvYks5vHbJbgaJpZM4UTf-Y
.

I don't understand the advantages of using ESM. I was looking at the docs and it just looks like syntactic sugar. Am I missing something?

Looking at the esm options we could enable the cjs.vars option. That would expose __dirname, __filename and require to the ava.config.js file

Let's go with this.

@novemberborn Could you make the change and then publish an alpha. I will test it on my setup.

@novemberborn
Let's use this issue to see if there are any problems and then we can add support for module.exports = {}.

I am running into the following problem related to not being able to use module.exports:

I need to use an ava.config.js. It has some logic in it, i.e. I cannot use an ava property in package.json instead. My codebase is written with CJS. This leads me to run ESLint on my repositories JavaScript files with the sourceType option set to script (not module).

This results in the following problem: ava.config.js cannot be parsed by ESLint because it's written with ES modules while the other files are using CJS. My current workaround is to fire ESLint twice with different options, but this is not great and complicates my setup quite a bit when coupled with files watching.

Allowing the full compatibility mode of esm would solve this problem.

My current workaround is to fire ESLint twice with different options, but this is not great and complicates my setup quite a bit when coupled with files watching.

You can use overrides to switch the source type:

{
  'overrides': [
    {
      'files': ['ava.config.js'],
      'parserOptions': {
        'sourceType': 'module',
      },
    },
}

Thanks! This works.

Just tried this out and it didn't solve all my problems.

When reading the config, it seems to be enforcing strict mode which is breaking my usage of the caller-id package.

TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

It also doesn't seem to work with the module-alias plugin.

const moduleAlias = require('module-alias')
moduleAlias.addAlias('+config', join(getRepoRoot(), 'packages/config'))

...

require('+config/foo')
Error while loading config - Cannot find module '+config/foo'

@novemberborn Can you take a look?

@vjpr could you share fuller samples of your config files?

As per https://github.com/avajs/ava/issues/2293 we'll be adding support for ava.config.js files.

Was this page helpful?
0 / 5 - 0 ratings