gulpjs / interpret

A dictionary of file extensions and associated module loaders.
MIT License
259 stars 47 forks source link

support multiple extensions for @babel/register hook #61

Closed wKich closed 4 years ago

wKich commented 4 years ago
import { Extension, extensions } from "interpret";

function registerCompiler(moduleDescriptor: Extension | null) {
  if (moduleDescriptor) {
    if (typeof moduleDescriptor === "string") {
      require(moduleDescriptor);
    } else if (!Array.isArray(moduleDescriptor)) {
      moduleDescriptor.register(require(moduleDescriptor.module));
    } else {
      moduleDescriptor.find(extension => {
        try {
          registerCompiler(extension);
          return true;
        } catch (e) {
          // do nothing
        }
      });
    }
  }
}

registerCompiler(extensions['.ts'])
registerCompiler(extensions['.tsx']) // <= this overwrite previous call

If project have @babel/register package, when second call overwrite the extensions option of @babel/register hook. So .ts modules can't be compiled.

phated commented 4 years ago

Seems like you are using this wrong. You probably should look at using rechoir to register extension hooks.

wKich commented 4 years ago

Why you think so? I develop ui testing tool, that allow define config in js/ts/coffee/etc, like webpack does. But also I use it to test itself. And I need to import tsx files along with config in ts. For developers, that will use my tool they should define extensions for ts and tsx explicitly, because interpret don’t work.

wKich commented 4 years ago

If I use ts-node ts and tsx files import without any error and I expect same behavior for @babel/register.

wKich commented 4 years ago

By the way, I looked code of rechior and it has same issue.


const config = require('interpret').extensions;
const rechoir = require('rechoir');
rechoir.prepare(config, './foo.ts');
rechoir.prepare(config, './bar.tsx');

console.log(require('./foo.ts')); // <= this line produce an error if @babel/register used in project
console.log(require('./bar.tsx'));
phated commented 4 years ago

@wKich interesting. I think this might be a problem with babel then. I think they might actually cache the registration so as not to "double compile"

wKich commented 4 years ago

@phated, could I fix this, by changing extenstions property for babel to ['.ts', '.tsx']? I think, it's not big deal some one call hook for '.ts' extension and '.tsx' extensions will be registred as well.

phated commented 4 years ago

After doing a bunch of research around this, I've found that the problem exists within @babel/register at https://github.com/babel/babel/blob/master/packages/babel-register/src/node.js#L98. This is de-registering the hook before a new one is registered. Generally, this keeps someone from shooting themselves in the foot, but it messes up the use-case of registering multiple extensions using interpret/rechoir.

I believe an option needs to be implemented in @babel/register that allows us to inform babel not to de-register the previous extension.

In the meantime, this can be solved by using the .ts extension exclusively and setting these options in .babel.rc:

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    [
      "@babel/preset-typescript",
      {
        "isTSX": true,
        "allExtensions": true
      }
    ]
  ]
}