-
Notifications
You must be signed in to change notification settings - Fork 208
feat: allow importing built-in glamorous components #131
Conversation
I would love it if we could also get a test in the |
As for your linter issues, I think your linter is busted unless I'm missing something. That file is fine I think. |
other/concat-exports.js
Outdated
.map(tag => { | ||
const validJsName = dashToCamelCase(tag) | ||
const capitalName = capitalize(validJsName) | ||
return `export const ${capitalName} = glamorous['${tag}']` |
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.
Let's add a semicolon here because this is our transpiled code, we should never rely on ASI.
Codecov Report
@@ Coverage Diff @@
## master #131 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 10 10
Lines 130 130
Branches 33 33
=====================================
Hits 130 130 Continue to review full report at Codecov.
|
|
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.
Looking good! Just a few comments :)
other/concat-exports.js
Outdated
return s.replace(/-([a-z])/g, ([, char]) => char.toUpperCase()) | ||
} | ||
|
||
const jsBuiltInObjectNames = [ |
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 wonder whether there's an npm package (probably by Sindre Sorhus) that has these so we don't have to hard-code them 🤔
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.
Found one :) https://github.com/jonschlinkert/reserved
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.
the reserved
package wasn't updated in 3 years and is a bit outdated. I can use node.js to generate the list.
other/concat-exports.js
Outdated
] | ||
|
||
function unCollide(name) { | ||
const prefix = 'html' |
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.
Very interesting! Makes total sense. Could you explain why (perhaps in a code comment) the prefix html
is used? Seems like a good one, just curious to know why.
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, also, this should probably be capitalized. All the others have the first letter capitalized so it's:
import {HtmlObject, Article} from 'glamorous'
Rather than:
import {htmlObject, Article} from 'glamorous'
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 chose html
because users may already be familiar with this prefix since it is used in JavaScript (htmlFor
). But since component names have to be capitalized (otherwise React/JSX treats the tag as custom element), I think postfix Tag
(ie ObjectTag
) is a nicer alternative. What do you think?
other/concat-exports.js
Outdated
@@ -0,0 +1,88 @@ | |||
const appendToFile = require('fs').appendFile |
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.
Are you getting a warning with this? I had to switch to appendFileSync
to get rid of it.
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 getting no warnings. I think async execution is not super useful here, so I can switch to sync.
|
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.
This is looking so great. Thank you again for working on it. Just a few comments. Also, I wonder if there's a way for us to verify that the tree shaking works 🤔 Maybe we could add an example to the /examples
? We could probably do that in a separate PR. @souporserious, would you be willing to work on that? It should be something really simple. Could even be with CRA and we commit the bundle.js
where you can see that it's been tree-shaken.
README.md
Outdated
@@ -131,6 +131,8 @@ If you're transpiling (and/or using the `jsnext:main`): | |||
|
|||
```javascript | |||
import glamorous, {ThemeProvider} from 'glamorous' | |||
// you can also import specific components | |||
import {Div, H2} from 'glamorous' |
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.
Could you include a line about the special case for JavaScript built-ins like Object
? Something like:
// Tags with the same name as built-in JavaScript objects are importable with a
Tag
suffix, IE:ObjectTag
.
other/concat-exports.js
Outdated
return `export const ${tagName} = glamorous['${tag}'];` | ||
}).join`\n` | ||
|
||
const toWrite = `\n${elementExports}` |
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.
It would be handy to add a comment for the first line that says:
// these exports below are generated and will be tree-shaken if you're using Webpack 2 or Rollup
|
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.
Reeeally close! Thanks for your tireless iteration on this 👍
other/concat-exports.js
Outdated
} | ||
|
||
// node version <= 7 does not support trailing commas in function calls | ||
// prettier-ignore |
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.
TIL :)
other/concat-exports.js
Outdated
return !!s && s[0] === s[0].toUpperCase() | ||
} | ||
|
||
// node version <= 7 does not support trailing commas in function calls |
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.
Normally, I'll add this at the end of files which are not transpiled:
// this is not transpiled
/*
eslint
max-len: 0,
comma-dangle: [
2,
{
arrays: 'always-multiline',
objects: 'always-multiline',
functions: 'never'
}
]
*/
other/concat-exports.js
Outdated
// node version <= 7 does not support trailing commas in function calls | ||
// prettier-ignore | ||
const jsBuiltInConstructorNames = Object.getOwnPropertyNames(global) | ||
.filter(isCapitalized) |
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 unsure whether this is really necessary 🤔
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.
It's not necessary but reduces the number of items to compare from 63 to 40 which improves performance a bit.
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 more concerned about readability/maintainability of this file than performance and would prefer to not include anything in here that's only here for performance reasons. The script is really fast as it is :)
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.
Well, I think this code is quite readable but of course less code is always a plus. I'll remove it.
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.
Yeah, it's not about how much code, it's about the fact that you need to decide why this matters, and the fact is that it doesn't ;-)
Thanks so much!
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.
We're discussing it so it kind of matters (or it's just bikeshedding) ;)
other/concat-exports.js
Outdated
const capitalName = capitalize(validJsName) | ||
// add postfix if name collides with js constructors | ||
const tagName = unCollide(capitalName) | ||
return `export const ${tagName} = glamorous['${tag}'];` |
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.
Ah! Close call, this should actually be:
return `export const ${tagName} = glamorous['${capitalName}'];`
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 was wondering what to put there. Isn't glamorous.div
equal to glamourous.Div
?
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.
It is not. Here's some terminology that should hopefully be helpful:
glamorous
is a "componentFactoryFactory"glamorous.div
is a "componentFactory" which is created by callingglamorous('div')
glamorous.Div
is a "component" which is created by calling (effectively)glamorous('div')()
(in addition to a few extra things)
We don't (and wont?) support exporting the component factories, but exporting the components themselves could be useful.
I hope that helps clarify :)
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 should've RTFM 😊 sorry
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.
Why don't we just remove componentFactory
and move its competencies onto a glamorous component? That would make things simpler.
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've considered this, and I'm not totally against it. I think that it could make things even more complex from both an API and implementation standpoint, but I'm open to talk about it in another issue if you'd like to bring it up.
README.md
Outdated
@@ -131,6 +131,12 @@ If you're transpiling (and/or using the `jsnext:main`): | |||
|
|||
```javascript | |||
import glamorous, {ThemeProvider} from 'glamorous' | |||
|
|||
// you can also import specific components |
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.
We should probably call out the fact that these are the built-in components by saying:
Please read the section below on "Built-in" components.
|
|
||
// tags with the same name as built-in JavaScript objects are importable with a Tag suffix | ||
// and tag names that contain dashes are transformed to CamelCase | ||
import {MapTag, ColorProfile} from 'glamorous' |
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.
This is perfect!
Wonderful! Thank you! |
What:
allow something like
import { Div, Span } from 'glamorous'
Why:
Convenient helpers improve user experience.
How:
Create a build script that appends exports to the es file.
Checklist:
Closes #123
Sidenote:
This is not related directly to this commit, but my liter shows an error in
dist/glamorous.es.js
:'A module cannot have multiple default exports.'
That's caused by line 1177:
exports.default = reactHtmlAttributes$2;