-
-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Closed
Labels
Description
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
- modifiers/'macros' would be isolated in files with
.macros.jssuffixes - there would no real trace of them in the final bundle stripping imports of all
*.macros.js - considering they're localised and used on demand, I expect them to have little effect on build performance, so can be enabled in both dev/prod
- because there's no dependence on webpack, it should still work with other js tooling like jest, etc.
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!
Siddharth11, hamlim, vramana, dariocravero, johnbrett and 60 moreali-master and shanvlirth, hamlim, dsblv, johnbrett, roman01la and 23 more
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
threepointone commentedon Jul 6, 2017
a real world example - a theoretical, simpler port of glam would look like this -
npm install glam.macroswould compile down to
during runtime, it would render html that looks like
and add css to a stylesheet
additionally, we could also extract the css to a real
.cssfile and automatically import them (leveraging CRA's webpack css loader automatically), and all the other goodies from glam/emotion.another example would be relay.
instead of -
you'd split the two as
but it would still generate code similar/same to relay's own plugin
threepointone commentedon Jul 6, 2017
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(!)
EnoahNetzach commentedon Jul 6, 2017
Cool and super-useful!
A curious question: would this mechanism be enabled on npm module macros only?
I would kinda like to be able to write a macro in the project itself without having to publish it, although I know this potentially breaks the CRA philosophy.
kentcdodds commentedon Jul 6, 2017
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!)
suchipi commentedon Jul 6, 2017
So something with a name like
babel-plugin-macrosthat looks for imports/requires of/.*\/macros/, and when it finds them, imports a babel plugin from the macros lib (egrequire("glam.macros/plugin"), then applies it to the Program that contained the import/require?Sounds awesome
kentcdodds commentedon Jul 6, 2017
Yep, that's what I was thinking @suchipi 😄
threepointone commentedon Jul 6, 2017
Not to the whole program, but to the specific call sites.
kentcdodds commentedon Jul 6, 2017
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...
threepointone commentedon Jul 6, 2017
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
suchipi commentedon Jul 6, 2017
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?
threepointone commentedon Jul 6, 2017
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)
threepointone commentedon Jul 6, 2017
If you want wholesale babel plugins and/or loaders, the option to eject remains, and is likely a better option.
kentcdodds commentedon Jul 6, 2017
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 😀
kentcdodds commentedon Jul 6, 2017
But if course I'm just kidding 😉 if someone else wants to build this, I can't stop you 😀
suchipi commentedon Jul 6, 2017
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
@decoratorsupport would be a good idea, too?79 remaining items
threepointone commentedon Oct 2, 2018
I don’t think CRA runs their webpack config through their own babel pipeline but hahaha nice try 😆
threepointone commentedon Oct 2, 2018
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.
coodoo commentedon Oct 2, 2018
Oh snap, so is there anyway other than ejecting that could allow one to add new loaders to the webpack config? 😂
threepointone commentedon Oct 2, 2018
you could write a macro that reads the file, parses/transforms it, and inlines it at the macro site call. eg -
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
fs.writeFileSyncto a 'myfile.csv.js' file, and convert -to
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.
kentcdodds commentedon Oct 2, 2018
I suggest writing the file to
node_modules/.cache/some-namespace/path/to/file.jsthen you don't need to worry about generating spurious files :)I think that there is room for someone to make a module that makes doing this with macros very easy:
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).
satya164 commentedon Oct 3, 2018
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.
Timer commentedon Oct 3, 2018
@satya164 this problem does not exist in Create React App. There is continuous cache invalidation for files using macros.
Clearing the cache manually should be avoided.
satya164 commentedon Oct 3, 2018
@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
Add CRA note to caveats
docs: add CRA note to caveats (#83)
add experimental babel-plugin-macros support (facebook#3675)
add experimental babel-plugin-macros support (facebook#3675)