-
Notifications
You must be signed in to change notification settings - Fork 93
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
Support for generating SVG components without .defaultProps
#129
base: master
Are you sure you want to change the base?
Conversation
…ect assign instead
Oh... btw I couldn't test (in a real project), ever since I've opened this issue we've migrated away from babel & this plugin |
src/index.js
Outdated
if (!path.scope.hasBinding('object.assign/implementation')) { | ||
const assignDeclaration = t.importDeclaration([ | ||
t.importDefaultSpecifier(t.identifier('objectAssign')), | ||
], t.stringLiteral('object.assign/implementation')); | ||
|
||
file.set('ensureObjectAssign', () => { | ||
const [newPath] = path.unshiftContainer('body', assignDeclaration); | ||
newPath.get('specifiers').forEach((specifier) => { path.scope.registerBinding('module', specifier); }); | ||
}); | ||
} else { | ||
file.set('ensureObjectAssign', () => {}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhhh i think i misunderstood :-/ we definitely can't inject a package dependency into people's code (that we don't already know is there, like react)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh well... do we have any idea on how to do it without assign? 😟
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested letting just spread in the code, for some instances babel did transform it and used helper methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure we can produce spread and rely on babel transpiling it in user codebases
src/index.js
Outdated
@@ -138,6 +158,20 @@ export default declare(({ | |||
if (typeof filename === 'undefined' && typeof opts.filename !== 'string') { | |||
throw new TypeError('the "filename" option is required when transforming code'); | |||
} | |||
|
|||
if (!path.scope.hasBinding('object.assign/implementation')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we did this, we'd want to use /polyfill
and invoke that, so that we use the native version when present and compliant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but like, I don't think we want to polyfill people envs right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course not :-) that's what "shim" does. "polyfill" is just a function that gets the best possible version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, ok, I'll change the code to use shim instead.. I went with the impl one cuz I can just call it, for shim I'll have to either somehow inject this expr:
var objectAssignShim = require('object.assign/shim');
// it probably needs to be separated for cases where we generate `import` syntax... 🤔 but if you think it is really safe to call require(...)(); I'm up for it
var objectAssign = objectAssignShim();
var Svg = function(overrides) {
var props = objectAssign({}, DEFAULTS, overrides);
// ....
}
or make it like this, which is the easy way to do it...
var objectAssignShim = require('object.assign/shim');
var Svg = function(overrides) {
var props = objectAssignShim()({}, DEFAULTS, overrides);
// ....
}
I'll make it like this ^, I don't really know the implications of that objectAssignShim()
call on every render.. but I don't think it will be simple to inject that var objectAssign = objectAssignShim()
at the top levels
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry if i was unclear; shim is the one we DONT want to use. polyfill is the one we DO want to use, because it will be the native one when possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ohhh, sorry for misunderstanding, I thought polyfill would polyfill the env 😆 (now what I read bout shim makes more sense) Ill make the changes tomorrow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
made the change to use polyfill
validateDefaultProps(result); | ||
console.log('test/fixtures/test-multiple-svg.jsx', result.code); | ||
console.log('test/fixtures/test-multiple-svg.jsx\n', result.code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we know, I've thought it was clearer to read the outputs with a \n
, but if you want I can revert this
const defaultProps = SVG_DEFAULT_PROPS_CODE | ||
? 'var props = objectAssign({}, SVG_DEFAULT_PROPS_CODE, overrides);' | ||
: ''; | ||
const PROPS_NAME = SVG_DEFAULT_PROPS_CODE ? 'overrides' : 'props'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does "overrides" come from? is that a react thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nop, thats just renamed props, I didn't want to change the body (SVG_CODE
) so I made a little rename here, the final function will be
var SVG_NAME = function SVG_NAME(overrides) {
var props = objectAssign({}, SVG_DEFAULT_PROPS_CODE, overrides);
return SVG_CODE // which will probably ref `props`, which I didn't want to mess with so overrides is just a rename
}
src/index.js
Outdated
}) => { | ||
const defaultProps = SVG_DEFAULT_PROPS_CODE | ||
? 'var props = objectAssign({}, SVG_DEFAULT_PROPS_CODE, overrides);' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, one implication of assign here is that just props
will never be a stable ref, but I don't think anything in the SVG_CODE
will ref just props
alone so it should be ok...
ignorePattern, | ||
caseSensitive, | ||
filename: providedFilename, | ||
emitDeprecatedDefaultProps = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ljharb I mentioned in the PR description, but JIC, this is a breaking change if this is default false
... especially if someone reflects on the SVG default props
I think that since react went with the warnings this is a good thing (no warnings out of the box experience), but as a lib consumer I also don't love breaking changes 😞 though IMO, just reading the change log should do it 🤷
To clarify, However, a much much simpler approach is probably to just make this a class component and keep using defaultProps, since I'm pretty sure nothing about class components here would be deprecated? |
@ljharb thats actually... a really good solution, just hope that whatever env people have supports classes 🤔 (~97% of web?) Ill explore classes in this PR then |
ah, good point. I think we can make a class component without |
@ljharb I've setup a nextjs project with babel to test this PR changes and essentially I've discovered that I can't use class components in nextjs server side Error: × You're importing a component that needs `PureComponent`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
│
│ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client Essentially, due to nextjs and SSR (and potentially any other SSR impl?) if we want to emit class components people should mark their files as client components, which is a pretty stupid requirement to be able to use inline SVGs... So I guess we should stick to the fn components idea |
@ljharb made the change to polyfill and tested it in my mentioned nextjs project About this comment I'm not really sure I want to mutate props, its unlikely that people will be relying on a props object after passing it to a component but 🤷 on top of that it will make things more complicated for me in this PR |
@Grohden class components can extend React.PureComponent though? |
@ljharb yes (actually, isn't it the "only" way to make class component?), but will cause that problem I've mentioned on next and potentially any SSR solution out there 🤔 |
No, |
This should close #126
I've changed the code to:
object.assign
to merge the prop overrides (see linked issue)emitDeprecatedDefaultProps
) that allows this package users to still keep emitting thedefaultProp
declarationsI've made the option to omit default props an opt-out, so it is a breaking change.. but up for the author to change that to a default false