Skip to content
This repository has been archived by the owner on Nov 18, 2024. It is now read-only.

Auto import fbt in babel plugin #194

Open
alexandernanberg opened this issue Feb 11, 2021 · 5 comments
Open

Auto import fbt in babel plugin #194

alexandernanberg opened this issue Feb 11, 2021 · 5 comments
Labels
enhancement New feature or request

Comments

@alexandernanberg
Copy link

🚀 Feature Proposal

Add support to auto import fbt in the babel plugin. Similar to how the new react automatic runtime feature in @babel/plugin-transform-react-jsx

Motivation

Personally I often forget to import fbt until the compilation fails, making this automatic would improve the DX for at least me.

This would also fix use with "organize imports" in VS Code, where it removed the fbt import since it can't see it's being used.

Example

// input

function App() {
  return (
    <fbt desc="lorem text">Lorem ipsum dolor</fbt>
  )
}

// output

import fbt from 'fbt'

function App() {
  return (
    <fbt desc="lorem text">Lorem ipsum dolor</fbt>
  )
}

Pitch

It makes sense for this feature to be in the core babel plugin, I guess it's possible to create a custom plugin but then you need to be careful about ordering etc

@kayhadrin kayhadrin added the enhancement New feature or request label Feb 11, 2021
@kayhadrin
Copy link
Contributor

Since we've got code to detect the lack of fbt import, it makes sense that we could try to add it automatically in the transformed JS output.

We might have to give new configuration options in babel-plugin-fbt to let people customize how to actually do that import if their setup is not standard though.

@alexandernanberg
Copy link
Author

Created a stand-alone plugin for now, if it works out well I might create a PR sometime in the future

module.exports = function fbtImportPlugin({ types: t }) {
  let root;

  return {
    visitor: {
      Program(path) {
        root = path;
      },
      JSXElement(path) {
        const hasFbtImport = !path.context.scope.getBinding('fbt');

        if (path.node.openingElement.name.name === 'fbt' && hasFbtImport) {
          const importDeclaration = t.importDeclaration(
            [t.importDefaultSpecifier(t.identifier('fbt'))],
            t.stringLiteral('fbt')
          );
          const [importPath] = root.unshiftContainer('body', importDeclaration);
          // Babel doesn't automatically update the bindings when we insert the
          // import statement, so manually update the binding here.
          root.scope.registerBinding('module', importPath);
        }
      },
    },
  };
};
// .babelrc
{
  "plugins": [
    "./babel-plugin-fbt-import", // need to be before the other fbt plugins
    "babel-plugin-fbt-runtime",
    [
      "babel-plugin-fbt",
      {
        "extraOptions": { "__self": true, "__source": true }
      }
    ]
  ]
}

@kayhadrin
Copy link
Contributor

Nice!
This makes me think we should probably make an eslint rule for this.
In general, I find that it's easier to make people import fbt explicitly in their code so that the Flow type checks work properly.

@alexandernanberg
Copy link
Author

So a rule to disallow having an <fbt /> without explicitly importing it? Don't know much about Flow, but for TS the auto import would be quite nice. It would solve the issue described here under "The nasty bit" (not needing to add eslint-disable-next-line @typescript-eslint/no-unused-expressions fbt) to every file.

@alexandernanberg
Copy link
Author

I've published the code as babel-plugin-fbt-import on npm now, and code can be found here https://github.com/alexandernanberg/babel-plugin-fbt-import

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants