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

Add support for using this as a global Babel plugin #247

Closed
mxstbr opened this issue Dec 9, 2020 · 9 comments
Closed

Add support for using this as a global Babel plugin #247

mxstbr opened this issue Dec 9, 2020 · 9 comments

Comments

@mxstbr
Copy link

mxstbr commented Dec 9, 2020

It would be really awesome to be able to add this to the Babel configuration (if we can control it) globally as a plugin. That would allow one to use e.g. the tw prop on JSX Element without having to import "twin.macro" everywhere 👍

Not sure how hard that would be to abstract so feel free to close this if a macro is very different from a plugin.

@ben-rogerson
Copy link
Owner

ben-rogerson commented Dec 9, 2020

The way I understand it, babel-plugins visit the entire document while babel-plugin-macros visit specific nodes.

At the moment the tw prop part of twin already functions like a babel-plugin within the babel-macro so I'd probably need to adjust that function to allow interop with an external babel-plugin-twin.

I'll have a better look into this and report back.

@ben-rogerson
Copy link
Owner

After taking a look into this I found that I'd need to split twin.macro across two packages.
Usually, babel-plugin-macros are created to extend an existing babel-plugin (like styled-components has done) but in twins case, I'd need to move the majority of the code into a babel-plugin while leaving the macro features in place.
This would be a significant restructuring project which afterwards, would require all users to add (and setup) the extra package to use the current features they currently get from the single package.

@ben-rogerson
Copy link
Owner

Perhaps this could happen in the future, but right now I'm pretty happy with keeping twin as a single package. I'll keep it in mind though 👍

@euvs
Copy link

euvs commented Feb 19, 2021

This is actually a nice idea to have a global babel plugin. I keep forgetting to add import "twin.macro" all the time, and then spend time figuring out why it's not working.

While I was reading your comments, an idea occurred to me to write a very simple plugin that would inject import "twin.macro" to every single file in my project by default.

I wrote a tiny plugin as a proof on concept like so:

/// my-babel-plugin-inject-twinmacro.js

import template from '@babel/template';

// template
const buildImport = template(`
  import 'twin.macro';
`);

// plugin
export default function importTwinMarcoPlugin(babel) {
    const importDeclaration = buildImport();
    return {
        visitor: {
            Program(path) {
                console.log('Imported twin macro');
                path.unshiftContainer('body', importDeclaration);
            },
        },
    };
}

Added it to babel config

module.exports = {
    //...
    plugins: [
        //....
        "my-babel-plugin-inject-twinmacro",
        "babel-plugin-macros"
    ],
};

Big disclaimer, I've never written babel plugins before. I don't really now if I'm doing it correctly or not :).

It seems working with a couple of gotchas.

Gotcha 1:
The plugin need needs to go before babel-plugin-macros in the babel config file.

Gotcha 2:
This looks like a problem in twin.macro. If a file already has import 'twin.macro', it stops working.
As a test, I disabled my plugin and tried to import twin.macro twice in the same file, it also stops working.
It seems twin.macro don't like being imported twice in the same file. Could you confirm this?

At this point, the double import problem (Gotcha 2) is a bit of a show stopper for me.

You may have already explored this idea and rejected it, idk. Just my 2c :)

@mxstbr
Copy link
Author

mxstbr commented Feb 19, 2021

That's a fantastically simple workaround @euvs, love it!! 🚀

In terms of the double import problem, it's possible to check whether an import for twin.macro already exists and simply not insert it a second time from your plugin?

@euvs
Copy link

euvs commented Feb 19, 2021

@mxstbr
Yes. After I wrote that comment above, I spent some time and found a way how to check for existing twin.macro imports.

Please this gist https://gist.github.com/euvs/a72552c6377ddc379dcde9e269eefb6a

I wrapped it into a sub package in my monorepo project. Works well for me :)

Someone could probably take it, improve and publish as a proper babel plugin.

@ben-rogerson
Copy link
Owner

Nice one - excellent work here.

When I was investigating this I had a similar approach but was getting errors when I tried unshifting the import like this:

function addTwinImport({ state, t }) {
  const program = state.file.path;
  const uid = program.scope.generateUidIdentifier("twinImport");

  const twinImport = t.importDeclaration(
    [t.importDefaultSpecifier(uid)],
    t.stringLiteral("twin.macro")
  );
  program.unshiftContainer("body", twinImport);
}

Looks like @babel/template gets around that issue nicely!

I'm thinking I'll jump in and add this on npm under babel-plugin-twin.

Is that okay with you @euvs ?

@euvs
Copy link

euvs commented Feb 19, 2021

@ben-rogerson
Absolutely ok with me. That would be awesome if you publish it as a plugin.

@ben-rogerson
Copy link
Owner

ben-rogerson commented Feb 19, 2021

The plugin is now up on npm 🎉
Thanks for all the work on this.

Read more at babel-plugin-twin →

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

3 participants