-
Notifications
You must be signed in to change notification settings - Fork 487
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
Create a yeoman generator for React+Typescript components #1548
Conversation
63e59fc
to
b1b8927
Compare
"compile": "tsc", | ||
"prepublish": "npm run compile", | ||
"start": "webpack-dev-server --mode development", | ||
"test": "jest" |
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 build a ".d.ts" file as well (something like I am doing here in my test side-project).
|
||
## Contribute | ||
|
||
We'd love to get contributions from you! Please, check our [Contributing Guidelines](CONTRIBUTING.md) to see how you can help us improve. |
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 can update the CONTRIBUTING.md link.
We'd love to get contributions from you! Please, check our [Contributing Guidelines](CONTRIBUTING.md) to see how you can help us improve. | |
We'd love to get contributions from you! Please, check our [Contributing Guidelines](https://github.com/liferay/clay/blob/master/CONTRIBUTING.md) to see how you can help us improve. |
b1b8927
to
abce730
Compare
I updated the structure a bit and moved some of the dependencies around. I couldn't find any great examples of this sort of monorepo that both the benefits of a monorepo and also the individual autonomy of the package. So I moved the testing infrastructure up to the root of the project and then also provided shared configs at the root. @wincent I didn't fully copy your example you provided because I thought it required too much interdependency between packages for building. Reason I avoided that is because packages could technically be independent of other packages in this repo. Such as Feel free to test it out by using the generator from the root of the repo. I'm open to more suggestions in changing this around though. I'm not totally satisfied with this solution yet. |
Decided to make additional changes... I wasn't quite happy with the last change. Changes:
This way each module is autonomous in development, but also can be developed in parallel to other components with lerna. IMO this is the way that seems to make most sense to me. Let me know if you guys have any concerns or thoughts |
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 really great @bryceosterhaus. I left a few comments because I think it is important to get this as close to perfect as possible before we open the floodgates and start generating packages with it, but this looks pretty darn close to ready.
|
||
let path = require('path'); | ||
let assert = require('yeoman-generator').assert; | ||
let helpers = require('yeoman-generator').test; |
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.
These let
look like they should all be const
.
); | ||
assert.fileContent('src/MyComponent.tsx', /export default MyComponent/); | ||
}); | ||
}); |
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.
Just as style feedback, I think in tests we should favor arrow functions over function () {}
for brevity, and value of this
is irrelevant here.
]); | ||
}); | ||
|
||
it('content of MyComponent.tsx', function() { |
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 should read grammatically as an assertion; instead of "it content of MyComponent.tsx" it should be something like: "it produces MyComponent.tsx with templated content" (for example).
it('content of MyComponent.tsx', function() { | |
it('produces MyComponent.tsx with templated content', function() { |
let _ = require('lodash'); | ||
let chalk = require('chalk'); | ||
let yeoman = require('yeoman-generator'); | ||
let yosay = require('yosay'); |
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.
More let
to const
here, I think.
let yosay = require('yosay'); | ||
|
||
module.exports = yeoman.generators.Base.extend({ | ||
initializing: function() { |
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.
Can we assume this will be running in the context of a recent enough Node version that we can use ES6 object concise methods? ie.
module.exports = yeoman.generators.Base.extend({
initializing() {
// etc...
"webpack-cli": "^3.1.2", | ||
"webpack-dev-server": "^3.1.10", | ||
"webpack": "^4.29.0" | ||
}, |
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.
Pretty much all dev dependencies can and I would argue should be hoisted up to the repo root. The node modules resolution algorithm means that require('foo')
will still be found when working inside a package directory. Rationale is that we ensure that we are using a standard set of dev dependencies across all packages without any divergent versions. I know that you want developers to be able to work within package directories, but they still need to clone the repo in order to do that, so declaring the dev dependencies at the top level doesn't make working locally any harder. Take a look at a typical monorepo project like Babel and you'll see that all the dev dependencies are at the top, with only a couple of exceptions.
If you're interested, I have a checker in that sample project that checks to make sure that dev dependencies only get declared at the top. Other checks are for things like missing deps, mismatched deps etc.
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 had tried that originally but then I ran into issues with resolutions when I was in a package itself. Something couldve been out of wack so I will try that again though.
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'd say it's worth it. Babel at least has some docs on set-up for monorepos, although that might not help with the resolution issues you were having.
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
import * as React from 'react'; | ||
import getCN from 'classnames'; |
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.
Maybe we should bind this to classNames
, which is what the "classnames" README examples use.
import * as TestRenderer from 'react-test-renderer'; | ||
import <%= componentName %> from '../<%= componentName %>'; | ||
|
||
describe('<%= componentName %>', function() { |
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.
describe('<%= componentName %>', function() { | |
describe('<%= componentName %>', () => { |
I see you're already using arrow functions in the it
examples.
import <%= componentName %> from '../<%= componentName %>'; | ||
|
||
describe('<%= componentName %>', function() { | ||
it('should render', () => { |
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.
Style: generally "should" should be avoided in example descriptions. You can always express it more concisely by leading directly with a verb. This is useful because it makes it more likely that you can fit the description in a single line. So in this case it would be:
it('should render', () => { | |
it('renders', () => { |
tsconfig.json
Outdated
"removeComments": true, | ||
"baseUrl": "./", | ||
"paths": { | ||
"@clay/*": ["packages/*/src"], |
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.
"@clay/*": ["packages/*/src"], | |
"@clayui/*": ["packages/*/src"], |
To match the change you made elsewhere? AFAIK we've requested @clay
but no idea whether that can/will happen.
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.
hey @bryceosterhaus, I left some comments. I know we can improve the way we package each package, I had opened an issue about it in #1107. But I think we can improve this in the future.
"lerna": "lerna bootstrap -- --no-optional --no-package-lock", | ||
"link": "lerna run link", | ||
"lint": "eslint packages/**/*.js examples/**/*.js scripts/**/*.js", | ||
"pa11y": "pa11y-ci ./packages/clay-*/demos/a11y.html", | ||
"prettier": "prettier-eslint packages/**/**/*.js examples/**/**/*.js scripts/**/**/*.js", | ||
"start": "http-server . -p 4000", |
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.
hey @bryceosterhaus, I know we had talked about the demos and that this would not be the best option, I've been thinking about testing https://storybook.js.org/, I've seen some use cases in a monorepo, I think it is a great experience. We can test it once we start having some components in the master.
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 I agree we definitely need easily accessible demos on the repo level. Storybook is pretty great, I have used it in the past and it was easy to use. One other thing I am investigating is the possibility of using "Framer X" and that could also possible be a way to run demos. I am working with some of the UX leads here in LA and gonna determine if framer fits our needs.
I think this can be a tracked in a differ issue though, so I have created one #1562
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 great, I tested a component of Metal.js at the time with Framer X
worked up, even though it was not React, I built a layer to give compatibility... The big problem was the CSS that are scoped.
package.json
Outdated
"lerna": "lerna bootstrap -- --no-optional --no-package-lock", | ||
"link": "lerna run link", | ||
"lint": "eslint packages/**/*.js examples/**/*.js scripts/**/*.js", | ||
"pa11y": "pa11y-ci ./packages/clay-*/demos/a11y.html", | ||
"prettier": "prettier-eslint packages/**/**/*.js examples/**/**/*.js scripts/**/**/*.js", | ||
"start": "http-server . -p 4000", | ||
"test": "npm run build && npm run jest && npm run pa11y", | ||
"test": "lerna run test && npm run pa11y", |
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.
Just putting my thoughts about it:
- One of the points I like about having the jest running at the root is that we will only have one jest startup running and we can reap the coverage much better than terms in each package its coverage... This facilitates the information on https://coveralls.io/github/liferay/clay.
- We will have many components here still, so running the test for each project will take a long time for you to know if you have not broken another component that depends on it.
- When running the tests in this way, we will have the high boot time in each package, since we raise the jest all the time to test the package, maybe increase the CI time.
- I like to run the tests at the root because I can select which tests I want to run when I'm working on just one project.
yarn jest packages/clay-badge
for example.
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 yeah that makes sense. I think if we hoist devDependencies like Greg had suggested then we can also probably run a single instance of Jest at both the root and package levels. Ill look into this.
@matuzalemsteles @wincent just updated. Here are the highlights
Also I added charts to the eslint and prettier ignore for now. Gonna re-write it to use typescript and ill remove those from the ignore files in that issue. |
packages/clay-badge/package.json
Outdated
@@ -0,0 +1,31 @@ | |||
{ | |||
"name": "@clayui/clay-badge", |
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.
hey @bryceosterhaus as we now have the scope, I think it is no longer necessary to add clay-
, just leaving @clayui/badge
.
"scripts": { | ||
"build": "babel src --root-mode upward --out-dir lib --extensions .ts,.tsx", | ||
"build:types": "tsc --project ./tsconfig.declarations.json", | ||
"prepublish": "npm run build && npm run build:types", |
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 should probably be "prepublishOnly", right?
@matuzalemsteles @wincent made updates in regards to your comments, re-ran the generator for clay-badge and then also added ts parser for eslint. |
CC @marcoscv-work and @carloslancha in case you haven't seen this yet. |
.eslintrc
Outdated
} | ||
] | ||
], | ||
"sort-vars": 2 |
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.
A lot of this custom stuff would ideally be merged up into the "eslint-config-liferay" package, but that is currently a little hard for us to update because it is not in the Liferay org repo even though that's where the package metadata says it should be; I have an internal ticket open for sorting that out: https://issues.liferay.com/browse/IFI-482.
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.
Great idea. I had just copied over some of the rules we used in Analytics cloud. We slowly added them as we worked on the project and found them beneficial.
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 in the process of migrating the config to its proper location so we can start adapting it... one thing I'm worried about is if these long list makes sense for all cases or just for the jsx
one... should we have different config bases, like eslint-config-liferay
and eslint-config-liferay-jsx
?
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.
One config to rule them all...
package.json
Outdated
"start": "http-server . -p 4000", | ||
"test": "npm run build && npm run jest && npm run pa11y", | ||
"lint": "eslint \"**/*.{js,ts,tsx}\"", | ||
"prettier": "prettier-eslint \"**/*.{js,ts,tsx}\"", |
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.
You can safely use single quotes here if you want to avoid the backslash escaping.
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
import * as React from 'react'; | ||
import * as ReactDOM from 'react-dom'; |
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 don't think we need to do the * as
thing here (or in the other files either). If you search, you'll find a few discussions about what React exports (and what it "should export"); this is the current reality:
- https://github.com/facebook/react/blob/1d6b1660a29c452e954d053a14c5adc42ccf94ba/packages/react-dom/index.js#L14-L16
- https://github.com/facebook/react/blob/1d6b1660a29c452e954d053a14c5adc42ccf94ba/packages/react-dom/index.js#L14-L16
And the official docs (ReactDOM, React) just tell you to import React
, import ReactDOM
.
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 reason I use * as React
was due to the ts compiler complaining.
I looked into it and we would have to add this option to our tsconfig, "allowSyntheticDefaultImports": true
. Not sure if that is the route we want to go though.
I was reading these issues about it, microsoft/TypeScript#3337 and microsoft/TypeScript-React-Starter#8
Any preference on 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.
Ah, that's a bummer. I wanted to stick to the pattern in the React docs but allowSyntheticDefaultImports
seems like a bit of a hack. So * as React
is probably the least horrible option.
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 thats what I figured as well. Ill just leave it as is for now, and then if for some reason TS fixes this, we can make the change everywhere.
@@ -0,0 +1 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
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 would have expected there to be some content in here.
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.
Updated this in the generator
const HWP = require('html-webpack-plugin'); | ||
|
||
module.exports = { | ||
entry: path.join(__dirname, './demo/App.tsx'), |
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.
nit: if you're using path.join
, you don't need the "./" in "./demo/App.tsx".
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.
Updated this in the generator
Once the generator portion of this PR is good to go, I am going to re-generate the badge component based on the generator. I'll also squash all of the generator commits into a single commit. |
Just started reviewing :) |
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.
LGTM!
Nah, I don't have anything else. I think this is a good enough base upon which we can iterate further. I wanted to make sure we didn't rush this, in order to give people time to comment, but I figure that at this point everybody who cares has probably already shared their opinions. |
I care and I haven't! (I'll just take a quick look right away, but I'm sure it'll be to my liking 🤓) |
Ah, a thing I forgot to mention. |
Updated |
@jbalsas , Let me know if there is anything else wanted in this PR. |
hey guys, just an update about the |
I went ahead and created a new PR with a cleaned up commit history, seen here #1648 |
Closing in favour of #1648 to reduce noise here! |
Our previous generator was named
generator-metal-clay
so I renamed it and removed the metal reference and then added the react and ts support.