Skip to content

Commit

Permalink
Create a yeoman generator for React+Typescript components
Browse files Browse the repository at this point in the history
  • Loading branch information
bryceosterhaus committed Feb 13, 2019
1 parent 1b06b1e commit 63e59fc
Show file tree
Hide file tree
Showing 13 changed files with 454 additions and 0 deletions.
31 changes: 31 additions & 0 deletions packages/generator-clay-component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Clay component Generator

> A Yeoman Generator that scaffolds a `clay-component` package.
## Install

First, install [Yeoman](http://yeoman.io/) from [npm](https://www.npmjs.org/):

```sh
[sudo] npm install -g yo
```

Then, install this generator:

```sh
[sudo] npm install -g generator-clay
```

## Usage

Just run the following command on the directory you wish to use for your project:

```sh
yo clay-component
```

The generator will ask you a few questions about the package. Once you've answered all of them it will automatically generate a starting structure for you, as well as download all the local dependencies.

## License

[BSD License](http://opensource.org/licenses/BSD-3-Clause) © Liferay, Inc.
44 changes: 44 additions & 0 deletions packages/generator-clay-component/__tests__/test-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* © 2018 Liferay, Inc. <https://liferay.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
'use strict';

let path = require('path');
let assert = require('yeoman-generator').assert;
let helpers = require('yeoman-generator').test;

describe('clay-component-generator:app', function() {
beforeAll(function(done) {
helpers
.run(path.join(__dirname, '../app'))
.withOptions({skipInstall: true})
.withPrompts({
componentName: 'MyComponent',
repoDescription: 'My awesome Clay component',
})
.on('end', done);
});

it('creates files', function() {
assert.file([
'demo/App.tsx',
'demo/index.html',
'src/MyComponent.tsx',
'src/__tests__/MyComponent.tsx',
'webpack.config.js',
'package.json',
'tsconfig.json',
'README.md',
]);
});

it('content of MyComponent.tsx', function() {
assert.fileContent(
'src/MyComponent.tsx',
/const MyComponent: React.FunctionComponent<Props> = \(\{/
);
assert.fileContent('src/MyComponent.tsx', /export default MyComponent/);
});
});
166 changes: 166 additions & 0 deletions packages/generator-clay-component/app/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* © 2018 Liferay, Inc. <https://liferay.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
'use strict';

let _ = require('lodash');
let chalk = require('chalk');
let yeoman = require('yeoman-generator');
let yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
initializing: function() {
this.log(
yosay(
'Welcome, let\'s generate a ' +
chalk.blue('Clay') +
' component!'
)
);
},

prompting: function() {
let done = this.async();

let prompts = [
{
type: 'input',
name: 'componentName',
message: 'How do you want to name your component?',
default: 'ClayComponent',
validate: function(input) {
if (!input) {
return 'You must provide a component name.';
}
if (!/^[^_\-\s\d][^_\-\s]*$/.test(input)) {
return (
'Invalid component name. Component names can\'t contain whitespace or ' +
'any of the following characters: "-_". Also, class names can\'t ' +
'start with digits.'
);
}

return true;
},
},
{
type: 'input',
name: 'repoDescription',
message: 'How would you describe this component?',
default: 'My awesome Clay component',
},
];

this.prompt(
prompts,
function(props) {
let componentName = props.componentName;

this.camelCaseName = _.camelCase(componentName);
this.componentName = componentName;
this.capitalizeName = _.startCase(componentName);
this.kebabCaseName = _.kebabCase(componentName);

this.repoName = this.kebabCaseName;
this.repoOwner = props.repoOwner;
this.repoDescription = props.repoDescription;
done();
}.bind(this)
);
},

writing: function() {
this.destinationRoot(this.repoName);
this.fs.copyTpl(
this.templatePath('demo/_App.tsx'),
this.destinationPath('demo/App.tsx'),
{
camelCaseName: this.camelCaseName,
componentName: this.componentName,
capitalizeName: this.capitalizeName,
kebabCaseName: this.kebabCaseName,
repoName: this.repoName,
}
);
this.fs.copyTpl(
this.templatePath('demo/_index.html'),
this.destinationPath('demo/index.html')
);
this.fs.copyTpl(
this.templatePath('src/_Boilerplate.tsx'),
this.destinationPath('src/' + this.componentName + '.tsx'),
{
buildFormat: this.buildFormat,
componentName: this.componentName,
templateLanguage: this.templateLanguage,
kebabCaseName: this.kebabCaseName,
repoName: this.repoName,
}
);

this.fs.copyTpl(
this.templatePath('src/tests/_Boilerplate.tsx'),
this.destinationPath(
'src/__tests__/' + this.componentName + '.tsx'
),
{
componentName: this.componentName,
kebabCaseName: this.kebabCaseName,
}
);
this.fs.copyTpl(
this.templatePath('src/tests/__snapshots__/_Boilerplate.tsx.snap'),
this.destinationPath(
'src/__tests__/__snapshots__/' +
this.componentName +
'.tsx.snap'
),
{
componentName: this.componentName,
kebabCaseName: this.kebabCaseName,
}
);
this.fs.copyTpl(
this.templatePath('_package.json'),
this.destinationPath('package.json'),
{
componentName: this.componentName,
repoName: this.repoName,
repoOwner: this.repoOwner,
repoDescription: this.repoDescription,
}
);
this.fs.copyTpl(
this.templatePath('_tsconfig.json'),
this.destinationPath('tsconfig.json')
);
this.fs.copyTpl(
this.templatePath('_README.md'),
this.destinationPath('README.md'),
{
repoName: this.repoName,
repoDescription: this.repoDescription,
componentName: this.componentName,
kebabCaseName: this.kebabCaseName,
}
);
this.fs.copyTpl(
this.templatePath('_webpack.config.js'),
this.destinationPath('webpack.config.js'),
{
componentName: this.componentName,
kebabCaseName: this.kebabCaseName,
repoName: this.repoName,
}
);
},

install: function() {
const ps = this.spawnCommand('yarn', ['install', '--no-lockfile'], {
stdio: 'ignore',
});
ps.on('close', code => console.log(`yarn install exited with ${code}`));
},
});
26 changes: 26 additions & 0 deletions packages/generator-clay-component/app/templates/_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# <%= kebabCaseName %>

<%= repoDescription %>

## Setup

1. Install NodeJS >= v0.12.0 and NPM >= v3.0.0, if you don't have it yet. You
can find it [here](https://nodejs.org).

2. Install local dependencies:

```
npm install
```

3. Build the code:

```
npm run build
```

4. Open the demo at demos/index.html on your browser.

## Contribute

We'd love to get contributions from you! Please, check our [Contributing Guidelines](CONTRIBUTING.md) to see how you can help us improve.
60 changes: 60 additions & 0 deletions packages/generator-clay-component/app/templates/_package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "<%= repoName %>",
"version": "3.0.0",
"description": "<%= componentName %> component",
"license": "BSD-3-Clause",
"repository": "https://github.com/liferay/clay/tree/master/packages/<%= repoName %>",
"engines": {
"node": ">=0.12.0",
"npm": ">=3.0.0"
},
"main": "lib/<%= componentName %>.js",
"esnext:main": "src/<%= componentName %>.js",
"jsnext:main": "src/<%= componentName %>.js",
"files": ["lib", "src"],
"scripts": {
"compile": "tsc",
"prepublish": "npm run compile",
"start": "webpack-dev-server --mode development",
"test": "jest"
},
"keywords": ["clay", "react"],
"dependencies": {
"@types/react": "^16.8.2",
"@types/react-dom": "^16.8.0",
"classnames": "^2.2.6"
},
"devDependencies": {
"@types/classnames": "^2.2.7",
"@types/jest": "^24.0.3",
"@types/jest-diff": "^20.0.0",
"@types/react-test-renderer": "^16.8.0",
"awesome-typescript-loader": "^5.2.1",
"clay-css": "^2.8.3",
"css-loader": "^2.1.0",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.1.0",
"react": "^16.8.1",
"react-dom": "^16.8.1",
"react-test-renderer": "^16.6.1",
"source-map-loader": "^0.2.4",
"style-loader": "^0.23.1",
"ts-jest": "^23.10.5",
"typescript": "^3.3.3",
"webpack": "^4.29.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
},
"peerDependencies": {
"react": "^16.8.1",
"react-dom": "^16.8.1"
},
"browserslist": ["extends browserslist-config-clay"],
"jest": {
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"]
}
}
12 changes: 12 additions & 0 deletions packages/generator-clay-component/app/templates/_tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"jsx": "react",
"module": "commonjs",
"outDir": "./lib/",
"sourceMap": true,
"strict": true,
"target": "es5"
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "./src/**/__tests__/**"]
}
25 changes: 25 additions & 0 deletions packages/generator-clay-component/app/templates/_webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* © 2018 Liferay, Inc. <https://liferay.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
const path = require('path');
const HWP = require('html-webpack-plugin');

module.exports = {
entry: path.join(__dirname, './demo/App.tsx'),
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'],
},
module: {
rules: [
{test: /\.tsx?$/, loader: 'awesome-typescript-loader'},
{enforce: 'pre', test: /\.js$/, loader: 'source-map-loader'},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [new HWP({template: path.join(__dirname, './demo/index.html')})],
};
20 changes: 20 additions & 0 deletions packages/generator-clay-component/app/templates/demo/_App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* © 2018 Liferay, Inc. <https://liferay.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import <%= componentName %> from '../src/<%= componentName %>';

import 'clay-css/lib/css/atlas.css';

const App: React.FunctionComponent = () => {
return (
<div>
<<%= componentName %> />
</div>
);
};

ReactDOM.render(<App />, document.getElementById('root'));
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<body style="margin: 48px;">
<div id="root"></div>
</body>
</html>
Loading

0 comments on commit 63e59fc

Please sign in to comment.