tape: `tape` runner does not support ESM files

Reading https://github.com/substack/tape/issues/414 — which I realize is about writing Tape with ES modules, not testing ES modules — I found this suggestion:

https://github.com/substack/tape/issues/414#issuecomment-433579912

In case someone stumbles upon this, passing --experimental-modules to tape works fine on windows (nix not available or I’d test). Even in a context such as this: npx tape --experimental-modules test/**/.mjs.

Testing now, in node.js v12.9.1 and macOS, I’m getting a silent failure when trying to use that. For example:

import test from 'tape';
// import * as test from 'tape';
// import { test } from 'tape';

test('test', function (t) {
  t.equal( 'test', 'test', 'it is a test' );
  t.end();
});
tape --experimental-modules my-test.js

Should this be supported? It may be worth noting that I also get no output running tape -v or tape -h. I’m not sure if that indicates a problem with my environment.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 33

Most upvoted comments

This is fixed by #547.

Thanks for the validation 😃 And yeah, that’s why I thought I’d make a quick and separate module. Basically, just scratching my own itch but happy if it ends up scratching anyone else’s too. 🐾

Nah, it wouldn’t and shouldn’t be user configurable - it’d be:

  1. does this node version support ESM? if not, CJS.
  2. is this file’s extension “.cjs” or “.json”? CJS.
  3. is this file’s extension “.mjs”? ESM.
  4. is this file’s extension “.js”? if within a package.json with type module, ESM, else, CJS.
  5. CJS.

In other words, node, not users, determine what kind of file it is (based on how the user has named it and the user’s package.json).

The ES module imported by my actual project was in a dependency, so changing the file extensions or import syntax would have been tricky for sure. Instead, I was able to get this working well with the esm package:

require = require('esm')(module);

const test = require('tape');
const foo = require('foo'); // 'foo' package contains references to ES modules

test('test', function(t) {
  // ...
});

With that, the usual syntax works fine:

tape my-test.js

It seems to have some limitations with .mjs files and type: "module", but I’d rather avoid both of those things, so this is fine.

Thanks for looking into this! Feel free to close the issue; I don’t think any fixes are necessary here except perhaps a tip in the docs?

That’s roughly the same technique #547 will use; however, tape supports many node and browser versions beyond the ones that have async/await, or even Promises.

Yes - also, tape takes a glob, but node takes a single file.

Absolutely not, it’s syntax, not a function.

@Raynos there’s no way to conditionally use import() and still support pre-ESM node without eval.