-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
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
RFC - babel-macros #2730
Comments
a real world example - a theoretical, simpler port of glam would look like this -
// app .js
import css from 'glam.macros'
let red = css` display: flex; color: red; `
React.render(<div className={red}>
red text!
</div>, window.app) would compile down to let red = require('glam.macros/runtime')(() =>
['.css-7asd4a { display:flex; color: red; }']
)
React.render(<div className={red}>
red text!
</div>, window.app) during runtime, it would render html that looks like <div class='css-7asd4a'>
red text!
</div> and add css to a stylesheet .css-7asd4a {
display:flex;
color: red;
} additionally, we could also extract the css to a real another example would be relay. instead of - import Relay from 'relay'
// ...
Relay.QL`...` you'd split the two as import Relay from 'relay'
import QL from 'relay.macros'
// ...
QL`...` but it would still generate code similar/same to relay's own plugin |
Another usecase - integrating @kentcdodds' preval lib https://github.com/kentcdodds/babel-plugin-preval to inline node.js code into client side code for easily inlining file contents, etc without using a custom webpack loader(!) |
Cool and super-useful! A curious question: would this mechanism be enabled on npm module macros only? |
I think the point would be that you just import the macros from anywhere and it would apply itself on the file you're importing. I can definitely see how this could be accomplished using a babel plugin with 0 configuration on the part of the end user. If there's interest in this, I'll build it (because it would be SO FUN!) |
So something with a name like Sounds awesome |
Yep, that's what I was thinking @suchipi 😄 |
Not to the whole program, but to the specific call sites. |
The plugin would be responsible for what it does I think. Most of the time it would just find the call sites. Could make a helper to make finding call sites easier, but would want the flexibility of the whole program. I'm busy tonight, but can probably start on this tomorrow... |
That constraint is important, hence the proposal. Else it's pretty unrestrained and you'll have all the problems of the babel plugin ecosystem (and why this was called macros in the first place, from lisp) This is the basic sketch https://github.com/threepointone/babel-macros/blob/master/README.md |
Ah, so it would only work for function calls, tagged template strings, and JSX, and could only modify the node where it was "called". That's an important distinction. Which "problems of the babel ecosystem" are you trying to avoid? |
2 big ones are plugin ordering, and implicit changes (you won't be able to tell what changes will happen on a source file just by looking at it) |
If you want wholesale babel plugins and/or loaders, the option to eject remains, and is likely a better option. |
Oh, now I finally understand your babel-macro thing. Makes total sense. I hope nobody works on this before I get a chance to tomorrow. My mind is racing with ideas 😀 |
But if course I'm just kidding 😉 if someone else wants to build this, I can't stop you 😀 |
Sounds a lot like OCaml extension points, which was the result of people saying "letting them change the whole parser makes things too confusing". Do you think |
Yeah I think decorators could work too. |
Sounds super cool |
(We won't support decorators for this before their proposal advances. But in theory yes.) |
As for idea itself, heh, I like it. If @kentcdodds (or somebody else) can make a proof of concept and demonstrate it is enough to get Relay and some CSS-in-JS libraries working, I‘m game. The only thing I don’t quite like is the |
Alright, I found 30 minutes and I've got something! Contributions welcome :) I even published it: babel-macros. See the tests. Ok, now I've gotta run, but this is awesome. Looking forward to some PRs! Even more test cases would be cool (just make your test an object and add |
The ideal solution would be to have separate syntax, e.g. |
I want to make sure that existing tooling will work as much as I can so I want to avoid anything too weird looking... 🤔 I don't mind macros myself, but happy to consider other names 👍 |
The thing is, it also need to be explicit enough that you wouldn’t mistake it from a regular import. Because otherwise it’ll be a debugging nightmare for the person who doesn’t know what’s going on. |
Flow has |
Should we move discussion over to babel-macros? I'd be fine with it if babylon supported it via a plugin, then people could just include a preset we make (and CRA could include it in its own config theoretically). I like:
But I'm open to pretty much anything else. FYI,
See the tests and snapshots... Oh, heck, saved you a click 😄 |
Terrific progress, eager to hack on and use this for real stuff |
* add experimental babel-plugin-macros support closes #2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](#2730 (comment)) and it worked well. * Pin the version
* add experimental babel-plugin-macros support closes #2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](#2730 (comment)) and it worked well. * Pin the version
* add experimental babel-plugin-macros support closes #2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](#2730 (comment)) and it worked well. * Pin the version
* add experimental babel-plugin-macros support closes facebook#2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](facebook#2730 (comment)) and it worked well. * Pin the version
* add experimental babel-plugin-macros support closes facebook#2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](facebook#2730 (comment)) and it worked well. * Pin the version
Summary: This PR adds support for [babel-plugin-macros](https://github.com/kentcdodds/babel-plugin-macros). Usage: ```js import graphql from 'babel-plugin-relay/macro'; // Or: // const graphql = require('babel-plugin-relay/macro'); ``` `graphql` is exported from both the `react-relay` and `relay-runtime` packages, but as I created this PR mostly in the interest of possible Create React App integration, I only added an export to `react-relay`. This PR currently only adds support for Relay Modern. I'm not sure if Compat and/or Classic should be supported? I currently only have a single basic test. I certainly could copy over the fixtures in `__tests__/fixtures-modern` and change the imports, although I'm not sure how beneficial that would be, as most of the logic is shared with `babel-plugin-relay`. Closes #1968 Related: facebook/create-react-app#2730 (comment) /cc kentcdodds Pull Request resolved: #2171 Reviewed By: jstejada Differential Revision: D6831205 Pulled By: kassens fbshipit-source-id: 704a239b45974359cc1dcecacd85efb4aeddeef5
This shipped in 2.0. |
HUGE Thank you to @threepointone for the idea 👏👏👏👏 |
Out of curiosity, is it possible to use |
@coodoo Nope, it's not possible. Macros only transform AST nodes. There're like Babel plugins. |
I don’t think CRA runs their webpack config through their own babel pipeline but hahaha nice try 😆 |
HUGEST Thank you to @kentcdodds for actually building the thing (based on a hasty gist lol) and being such a good steward! You’re the best. |
Oh snap, so is there anyway other than ejecting that could allow one to add new loaders to the webpack config? 😂 |
you could write a macro that reads the file, parses/transforms it, and inlines it at the macro site call. eg - import csvToJs from 'csvToJs.macro'
let data = csvToJs('./myfile.csv') // will inline the contents of myfile.csv as a js object here a disadvantage of this approach is that if you require it in a different file, it'll get inlined again, increasing the size of your bundle for no good reason. another approach is to write the contents of the file to another js file (ie - in the macro, you'd call let data = csvToJs('./myfile.csv') to let data = require('./myfile.csv.js') but this would mean you'd generate spurious files in your source folder (or whichever temp folder you output to). either option may work for you, depending on your constraints. |
I suggest writing the file to I think that there is room for someone to make a module that makes doing this with macros very easy: const {createMacro} = require('babel-plugin-macros')
const createTempFileForMacro = require('the-module-someone-writes-to-make-this-easy')
module.exports = createMacro(csvToJsMacro)
function csvToJsMacro({references}) {
// do stuff
createTempFileForMacro(someRelevantArguments)
// do more stuff
} I think many macros would benefit from something like this (though I don't believe it's something that belongs in the core of babel-plugin-macros). |
One problem with Babel macro reading a file is that unless the file which uses the macro changes, it won't be called again due to the Babel loader cache, which can be very annoying. |
@satya164 this problem does not exist in Create React App. There is continuous cache invalidation for files using macros. |
@Timer How does it work? I can't find anything regarding macros here: https://github.com/facebook/create-react-app/blob/736561fa8b368daf27bc26646b10b8511e9d63a9/packages/react-dev-utils/getCacheIdentifier.js Edit: found it 11737bc |
facebook/create-react-app#2730 (comment) We don't want users thinking they have to purge the cache, as this will be very detrimental to their rebuild speed.
facebook/create-react-app#2730 (comment) We don't want users thinking they have to purge the cache, as this will be very detrimental to their rebuild speed.
* add experimental babel-plugin-macros support closes facebook#2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](facebook#2730 (comment)) and it worked well. * Pin the version
* add experimental babel-plugin-macros support closes facebook#2730 This will remain undocumented until the brave have tried it in the wild. **Test Plan:** There's currently no established way to test changes to `babel-preset-react-app`. But I did create [`unmaintained-react-scripts-babel-macros`](https://www.npmjs.com/package/unmaintained-react-scripts-babel-macros) [a while back](facebook#2730 (comment)) and it worked well. * Pin the version
Code modifiers are becoming popular in the javascript ecosystem, via babel-plugins (eg - many css-in-js libs, relay, etc). This issue is to open discussion on a generic system to include them in CRA apps, but still honouring the zero-config philosophy.
The proposal here is to have a constrained form of babel-plugins, disguised to appear like regular libraries. A short writeup on what it would look like here - https://github.com/threepointone/babel-macros/blob/master/README.md
.macros.js
suffixes*.macros.js
I'm looking for feedback on the same before I start writing code for it, as well as possible first implementations (maybe a simple css-in-js lib?)
If this doesn't belong here, feel free to close the issue. Thanks!
The text was updated successfully, but these errors were encountered: