1
0
Fork 0

Merge pull request #37 from transitive-bullshit/feature/typescript-support-v2

add typescript support v2
This commit is contained in:
Travis Fischer 2018-07-11 12:27:58 -04:00 committed by Joost De Cock
parent faba0e5f9e
commit c0769c2743
45 changed files with 2544 additions and 6662 deletions

View file

@ -14,6 +14,7 @@ const pkg = require('../package')
module.exports = async (info) => { module.exports = async (info) => {
const { const {
manager, manager,
template,
name name
} = info } = info
@ -25,7 +26,7 @@ module.exports = async (info) => {
info.dest = dest info.dest = dest
await mkdirp(dest) await mkdirp(dest)
const source = path.join(__dirname, '../template') const source = path.join(__dirname, '..', 'template', template)
const files = await globby(source, { const files = await globby(source, {
dot: true dot: true
}) })
@ -39,7 +40,7 @@ module.exports = async (info) => {
info info
}) })
}) })
ora.promise(promise, `Copying template to ${dest}`) ora.promise(promise, `Copying ${template} template to ${dest}`)
await promise await promise
} }
@ -98,14 +99,12 @@ module.exports.initPackageManager = async (opts) => {
{ {
cmd: `${info.manager} link`, cmd: `${info.manager} link`,
cwd: dest cwd: dest
} },
].concat(info.manager === 'yarn' ? [
{ {
cmd: `${info.manager}`, cmd: `${info.manager} install`,
cwd: example cwd: example
} }
] : [ ] ]
)
return pEachSeries(commands, async ({ cmd, cwd }) => { return pEachSeries(commands, async ({ cmd, cwd }) => {
return execa.shell(cmd, { cwd }) return execa.shell(cmd, { cwd })

View file

@ -14,7 +14,17 @@ const tests = [
description: 'this is a auto-generated test module. please ignore.', description: 'this is a auto-generated test module. please ignore.',
repo: 'nala/my-test-library', repo: 'nala/my-test-library',
license: 'MIT', license: 'MIT',
manager: 'yarn' manager: 'yarn',
template: 'default'
},
{
name: 'my-test-typescript-library',
author: 'nala',
description: 'this is a auto-generated test module. please ignore.',
repo: 'nala/my-test-library',
license: 'MIT',
manager: 'yarn',
template: 'typescript'
}, },
{ {
name: 'my-test-library', name: 'my-test-library',
@ -22,7 +32,17 @@ const tests = [
description: 'this is a auto-generated test module. please ignore.', description: 'this is a auto-generated test module. please ignore.',
repo: 'nala/my-test-library', repo: 'nala/my-test-library',
license: 'MIT', license: 'MIT',
manager: 'npm' manager: 'npm',
template: 'default'
},
{
name: 'my-test-library',
author: 'nala',
description: 'this is a auto-generated test module. please ignore.',
repo: 'nala/my-test-typescript-library',
license: 'MIT',
manager: 'npm',
template: 'typescript'
}, },
{ {
name: '@automagical/nala', name: '@automagical/nala',
@ -30,32 +50,36 @@ const tests = [
description: 'this is a auto-generated test module. please ignore.', description: 'this is a auto-generated test module. please ignore.',
repo: 'superstar-cats/nala', repo: 'superstar-cats/nala',
license: 'GPL', license: 'GPL',
manager: 'yarn' manager: 'yarn',
template: 'default'
} }
] ]
tests.forEach((info) => { tests.forEach((opts) => {
test.serial(`creating "${info.name}" using ${info.manager}`, async (t) => { test.serial(`creating "${opts.name}" using ${opts.manager}`, async (t) => {
console.log(`creating "${info.name}" using ${info.manager}...`) console.log(`creating "${opts.name}" using ${opts.manager}...`)
let ret let ret
// ensure library is created successfully // ensure library is created successfully
const root = await createLibrary(info) const root = await createLibrary(opts)
t.truthy(root.indexOf(info.shortName) >= 0) const example = path.join(root, 'example')
t.truthy(root.indexOf(opts.shortName) >= 0)
// ensure yarn runs successfully in src/ // ensure deps install successfully in root
ret = await execa.shell('yarn', { cwd: root }) ret = await execa.shell(`${opts.manager} install`, { cwd: root })
t.is(ret.code, 0) t.is(ret.code, 0)
// ensure jest tests pass // ensure root tests pass
ret = await execa.shell('yarn test', { cwd: root }) ret = await execa.shell(`${opts.manager} test`, { cwd: root })
t.is(ret.code, 0) t.is(ret.code, 0)
if (info.manager === 'yarn') { // ensure deps install successfully in example
// ensure yarn runs successfully in example/ ret = await execa.shell(`${opts.manager} install`, { cwd: example })
ret = await execa.shell('yarn install', { cwd: path.join(root, 'example') }) t.is(ret.code, 0)
t.is(ret.code, 0)
} // ensure bundle builds successfully in example
ret = await execa.shell(`${opts.manager} build`, { cwd: example })
t.is(ret.code, 0)
// ensure git is initialized properly // ensure git is initialized properly
ret = await execa.shell('git status', { cwd: root }) ret = await execa.shell('git status', { cwd: root })

View file

@ -14,7 +14,8 @@ module.exports = async () => {
author: config.get('author'), author: config.get('author'),
repo: (info) => `${info.author}/${info.name}`, repo: (info) => `${info.author}/${info.name}`,
license: config.get('license', 'MIT'), license: config.get('license', 'MIT'),
manager: config.get('manager', 'npm') manager: config.get('manager', 'npm'),
template: config.get('template', 'default')
} }
try { try {
@ -41,7 +42,11 @@ module.exports = async () => {
defaults.manager = 'yarn' defaults.manager = 'yarn'
} }
config.set('manager', defaults.manager || 'npm') config.set('manager', defaults.manager)
}
if (!config.get('template')) {
config.set('template', defaults.template)
} }
} catch (err) { } } catch (err) { }

View file

@ -1,6 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict' 'use strict'
const path = require('path')
const program = require('commander') const program = require('commander')
const { version } = require('../package') const { version } = require('../package')
@ -20,6 +21,7 @@ module.exports = async () => {
.option('-l, --license <string>', 'package license', defaults.license) .option('-l, --license <string>', 'package license', defaults.license)
.option('-r, --repo <string>', 'package repo path') .option('-r, --repo <string>', 'package repo path')
.option('-m, --manager <npm|yarn>', 'package manager to use', /^(npm|yarn)$/, defaults.manager) .option('-m, --manager <npm|yarn>', 'package manager to use', /^(npm|yarn)$/, defaults.manager)
.option('-t, --template <default|typescript>', 'package template to use', /^(default|typescript)$/, defaults.template)
.option('-s, --skip-prompts', 'skip all prompts (must provide package-name via cli)') .option('-s, --skip-prompts', 'skip all prompts (must provide package-name via cli)')
.parse(process.argv) .parse(process.argv)
@ -29,6 +31,7 @@ module.exports = async () => {
license: program.license, license: program.license,
repo: program.repo, repo: program.repo,
manager: program.manager, manager: program.manager,
template: program.template,
skipPrompts: program.skipPrompts skipPrompts: program.skipPrompts
} }
@ -47,20 +50,20 @@ module.exports = async () => {
} }
const params = await promptLibraryParams(opts) const params = await promptLibraryParams(opts)
const lib = await createLibrary(params) const dest = await createLibrary(params)
console.log(` console.log(`
Your module has been created at ${opts.dest}. Your module has been created at ${opts.dest}.
To get started, in one tab, run: To get started, in one tab, run:
$ cd ${opts.name} && ${opts.manager} start $ cd ${params.shortName} && ${params.manager} start
And in another tab, run the create-react-app devserver: And in another tab, run the create-react-app devserver:
$ cd ${opts.name}/example && ${opts.manager} start $ cd ${path.join(params.shortName, 'example')} && ${params.manager} start
`) `)
return lib return dest
} }
module.exports() module.exports()

View file

@ -64,12 +64,20 @@ module.exports = async (opts) => {
message: 'Package Manager', message: 'Package Manager',
choices: [ 'npm', 'yarn' ], choices: [ 'npm', 'yarn' ],
default: opts.manager default: opts.manager
},
{
type: 'list',
name: 'template',
message: 'Template',
choices: [ 'default', 'typescript' ],
default: opts.template
} }
]) ])
config.set('author', info.author) config.set('author', info.author)
config.set('license', info.license) config.set('license', info.license)
config.set('manager', info.manager) config.set('manager', info.manager)
config.set('template', info.template)
return info return info
} }

View file

@ -39,7 +39,7 @@
"handlebars": "^4.0.11", "handlebars": "^4.0.11",
"inquirer": "^6.0.0", "inquirer": "^6.0.0",
"make-dir": "^1.3.0", "make-dir": "^1.3.0",
"node-compat-require": "^1.0.4", "node-compat-require": "^1.0.5",
"ora": "^2.1.0", "ora": "^2.1.0",
"p-each-series": "^1.0.0", "p-each-series": "^1.0.0",
"parse-git-config": "^2.0.2", "parse-git-config": "^2.0.2",

View file

@ -13,8 +13,6 @@
<img width="600" src="https://cdn.rawgit.com/transitive-bullshit/create-react-library/master/media/demo.svg"> <img width="600" src="https://cdn.rawgit.com/transitive-bullshit/create-react-library/master/media/demo.svg">
</p> </p>
The CLI is based on this [boilerplate](https://github.com/transitive-bullshit/react-modern-library-boilerplate), which you can optionally read about [here](https://hackernoon.com/publishing-baller-react-modules-2b039d84bce7).
## Features ## Features
@ -27,6 +25,7 @@ The CLI is based on this [boilerplate](https://github.com/transitive-bullshit/re
- [Jest](https://facebook.github.io/jest/) for testing - [Jest](https://facebook.github.io/jest/) for testing
- Supports complicated peer-dependencies - Supports complicated peer-dependencies
- Supports CSS modules - Supports CSS modules
- Optional support for TypeScript
- Sourcemap creation - Sourcemap creation
- Hundreds of public modules created - Hundreds of public modules created
- Thorough documentation :heart_eyes: - Thorough documentation :heart_eyes:
@ -76,7 +75,6 @@ The second part will be running the `example/` create-react-app that's linked to
```bash ```bash
# (in another tab) # (in another tab)
cd example cd example
npm link <your-module-name> # you can skip this step if using yarn
npm start # runs create-react-app dev server npm start # runs create-react-app dev server
``` ```
@ -116,6 +114,10 @@ Here is a [branch](https://github.com/transitive-bullshit/react-modern-library-b
Here is a [branch](https://github.com/transitive-bullshit/react-modern-library-boilerplate/tree/feature/material-ui) which demonstrates how to make use of a relatively complicated peer dependency, [material-ui](https://github.com/mui-org/material-ui). It shows the power of [rollup-plugin-peer-deps-external](https://www.npmjs.com/package/rollup-plugin-peer-deps-external) which makes it a breeze to create reusable modules that include complicated material-ui subcomponents without having them bundled as a part of your module. Here is a [branch](https://github.com/transitive-bullshit/react-modern-library-boilerplate/tree/feature/material-ui) which demonstrates how to make use of a relatively complicated peer dependency, [material-ui](https://github.com/mui-org/material-ui). It shows the power of [rollup-plugin-peer-deps-external](https://www.npmjs.com/package/rollup-plugin-peer-deps-external) which makes it a breeze to create reusable modules that include complicated material-ui subcomponents without having them bundled as a part of your module.
### Boilerplate
The CLI is based on this [boilerplate](https://github.com/transitive-bullshit/react-modern-library-boilerplate), which you can optionally read about [here](https://hackernoon.com/publishing-baller-react-modules-2b039d84bce7).
### Libraries ### Libraries
Here are some example libraries that have been bootstrapped with `create-react-library`. Here are some example libraries that have been bootstrapped with `create-react-library`.
@ -133,7 +135,6 @@ Here are some example libraries that have been bootstrapped with `create-react-l
Want to add yours to the list? Submit an [issue](https://github.com/transitive-bullshit/create-react-library/issues/new)! Want to add yours to the list? Submit an [issue](https://github.com/transitive-bullshit/create-react-library/issues/new)!
## License ## License
MIT © [Travis Fischer](https://github.com/transitive-bullshit) MIT © [Travis Fischer](https://github.com/transitive-bullshit)

View file

@ -2,14 +2,14 @@
"name": "{{name}}-example", "name": "{{name}}-example",
"homepage": "https://{{author}}.github.io/{{name}}", "homepage": "https://{{author}}.github.io/{{name}}",
"version": "0.0.0", "version": "0.0.0",
"private": true,
"license": "MIT", "license": "MIT",
"private": true,
"dependencies": { "dependencies": {
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.4.1", "react": "^16.4.1",
"react-dom": "^16.4.1", "react-dom": "^16.4.1",
"{{name}}": "{{#if yarn}}link:..{{else}}*{{/if}}", "react-scripts": "^1.1.4",
"react-scripts": "^1.1.4" "{{name}}": "file:.."
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

View file

@ -1,7 +1,3 @@
/**
* @class ExampleComponent
*/
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

View file

@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# builds
build
dist
.rpt2_cache
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View file

@ -0,0 +1,31 @@
# {{name}}
> {{description}}
[![NPM](https://img.shields.io/npm/v/{{name}}.svg)](https://www.npmjs.com/package/{{name}}) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
## Install
```bash
npm install --save {{name}}
```
## Usage
```tsx
import * as React from 'react'
import MyComponent from '{{name}}'
class Example extends React.Component {
render () {
return (
<MyComponent />
)
}
}
```
## License
{{license}} © [{{author}}](https://github.com/{{author}})

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
{
"name": "{{name}}-example",
"homepage": "https://{{author}}.github.io/{{name}}",
"version": "0.0.0",
"license": "MIT",
"private": true,
"dependencies": {
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "^1.1.4",
"{{name}}": "file:.."
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

View file

@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<title>{{name}}</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>

View file

@ -0,0 +1,8 @@
{
"short_name": "{{name}}",
"name": "{{name}}",
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View file

@ -0,0 +1,13 @@
import React, { Component } from 'react'
import ExampleComponent from '{{name}}'
export default class App extends Component {
render () {
return (
<div>
<ExampleComponent text='Modern React component module' />
</div>
)
}
}

View file

@ -0,0 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

View file

@ -0,0 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))

View file

@ -0,0 +1,53 @@
{
"name": "{{name}}",
"version": "1.0.0",
"description": "{{description}}",
"author": "{{author}}",
"license": "{{license}}",
"repository": "{{repo}}",
"main": "dist/index.js",
"module": "dist/index.es.js",
"jsnext:main": "dist/index.es.js",
"scripts": {
"test": "cross-env CI=1 react-scripts-ts test --env=jsdom",
"test:watch": "react-scripts-ts test --env=jsdom",
"build": "rollup -c",
"start": "rollup -c -w",
"prepare": "{{manager}} run build",
"predeploy": "cd example && {{manager}} install && {{manager}} run build",
"deploy": "gh-pages -d example/build"
},
"dependencies": {},
"peerDependencies": {
"prop-types": "^15.5.4",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
"devDependencies": {
"@types/jest": "^23.1.5",
"@types/react": "^16.3.13",
"@types/react-dom": "^16.0.5",
"babel-core": "^6.26.3",
"babel-runtime": "^6.26.0",
"cross-env": "^5.1.4",
"gh-pages": "^1.2.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-scripts-ts": "^2.16.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts-ts": "2.15.1",
"rollup": "^0.62.0",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss-modules": "^1.0.8",
"rollup-plugin-typescript2": "^0.13.0",
"rollup-plugin-url": "^1.4.0",
"typescript": "^2.8.3"
},
"files": [
"dist"
]
}

View file

@ -0,0 +1,37 @@
import typescript from 'rollup-plugin-typescript2'
import commonjs from 'rollup-plugin-commonjs'
import external from 'rollup-plugin-peer-deps-external'
import postcss from 'rollup-plugin-postcss-modules'
import resolve from 'rollup-plugin-node-resolve'
import url from 'rollup-plugin-url'
import pkg from './package.json'
export default {
input: 'src/index.tsx',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true
},
{
file: pkg.module,
format: 'es',
sourcemap: true
}
],
plugins: [
external(),
postcss({
modules: true,
writeDefinitions: true
}),
url(),
resolve(),
typescript({
rollupCommonJSResolveHack: true
}),
commonjs()
]
}

View file

@ -0,0 +1,23 @@
/**
* @class ExampleComponent
*/
import * as React from 'react'
import styles from './styles.css'
export type Props = { text: string }
export default class ExampleComponent extends React.Component<Props> {
render() {
const {
text
} = this.props
return (
<div className={styles.test}>
Example Component: {text}
</div>
)
}
}

View file

@ -0,0 +1,8 @@
/* add css styles here (optional) */
.test {
display: inline-block;
margin: 2em auto;
border: 2px solid #000;
font-size: 2em;
}

View file

@ -0,0 +1,7 @@
import ExampleComponent from './'
describe('ExampleComponent', () => {
it('is truthy', () => {
expect(ExampleComponent).toBeTruthy()
})
})

View file

@ -0,0 +1,8 @@
/**
* Default CSS definition for typescript,
* will be overridden with file-specific definitions by rollup
*/
declare module '*.css' {
const content: { [className: string]: string };
export default content;
}

View file

@ -0,0 +1,23 @@
{
"compilerOptions": {
"outDir": "build",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom", "es2016", "es2017"],
"sourceMap": true,
"allowJs": false,
"jsx": "react",
"declaration": true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true
},
"include": ["src"],
"exclude": ["node_modules", "build", "dist", "example", "rollup.config.js"]
}

View file

@ -0,0 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs"
}
}

View file

@ -3595,9 +3595,9 @@ nice-try@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
node-compat-require@^1.0.4: node-compat-require@^1.0.5:
version "1.0.4" version "1.0.5"
resolved "https://registry.yarnpkg.com/node-compat-require/-/node-compat-require-1.0.4.tgz#f7df99a2ddca0892c1a1a285395255d03ac5253b" resolved "https://registry.yarnpkg.com/node-compat-require/-/node-compat-require-1.0.5.tgz#600802c65964be6282e29dbc56ce12d1b382d548"
dependencies: dependencies:
execa "^0.10.0" execa "^0.10.0"
npx "^10.2.0" npx "^10.2.0"