npm package: @rexlabs/plz-cli
Description: Toolkit for creating, developing building & testing projects - Vivid Module
Author: Rexlabs
Latest version: 4.2.3

<p align="center">
  <img src="./logo.svg" />
</p>
<br />

# @rexlabs/plz-cli :pray:

CLI toolkit for frontend web dev at rexlabs, enabling you to:

- generate new apps and npm packages
- preview UI with [Webpack Dev Server](https://webpack.js.org/guides/development/) and [Storybook](https://storybook.js.org/)
- run tests with [Jest](https://jestjs.io/) and [Storyshots](https://storybook.js.org/docs/testing/structural-testing/)
- build distributions with [Babel](https://babeljs.io/) and [Webpack](https://webpack.js.org)

The latest version of plz comes with webpack 4, babel 7, jest 24 and storybook 5, as well as everything needed to support React 16.9 😊

## Why? — Rationale

> "Oh geez, another front dev tool" ... **wrong!**  
> This is a kit of tools - it says so in the first sentence. It is 💯 gud.

Frontend development is filled to the brim with open source tools like webpack, babel, jest and storybook. As great as they are, they're difficult to configure, don't play nice together, and each new tool introduces learning curves. Boo.

Rather than we all struggling through the pains of configuration setup and maintenance, in each app and package we build @ rexlabs, we invest all that tooling focus into `plz`. It can sit in front of these tools, with a bunch of sane default configurations and hacks, to then be consistently employed in our projects. Devs are given the opportunity to forget about tooling woes, freeing their minds for better tasks. What a pleasant experience!

### Why not just use `create-react-app`?

[CRA](https://github.com/facebook/create-react-app), or more specifically [react-scripts](https://github.com/facebook/create-react-app/tree/master/packages/react-scripts), is an amazing toolkit and one of the starters of this trend we're now seeing. However, it is (for [very good reasons](https://github.com/facebook/create-react-app#philosophy)) very opinionated when it comes to the ability to customise it. We needed something a little bit more flexible, since every app after all is different and will have different requirements to certain extends.

Also, we wanted a toolkit that would allow us to build all kinds of projects, not just apps. Since we heavily invest in building centralised components and solutions in form of npm libraries, we were looking for a toolkit that could sit on top of any form of project. This is exactly what `plz` does 😊

### Shoutout 🙌

Even though he's not working at rexlabs anymore, [Lochlan Bunn](https://twitter.com/loklaan) still deserves a massive shout out here. Not only did he create `plz` in the first place, he also drove its adaption, educating everyone about the concepts, motivations and benefits. Without his work this library and the work that we do thanks to it would not be the same 🎉

## Getting started

```bash
# Install plz globally to use it for bootstrapping new projects
npm i -g @rexlabs/plz-cli
plz <command> [options]

# ...or use npx
npx @rexlabs/plz-cli <command> [options]
```

## Usage

```text
$ plz --help

Commands:
  plz build                     Bundles a project for distribution.
  plz clean                     Removes previously built files.
  plz config [key] [value]      Sets (or reads) config of the plz instance.
                                Can be used to change defaults.
  plz create <name> [root-dir]  Generates a new project called <name>
  plz serve                     Starts an dev server for the project.
  plz stories                   Starts a storybook for UI components.
  plz test [options]            Starts a jest test runner in current
                                directory.
  plz use <package-name>        Sets the given package as template source.
                                See --help for more details.

Options:
  -h, --help  Show help                                                [boolean]
  --no-emoji  Strip all emojis from the cli output in the terminal.    [boolean]
  --report    Add memory reporting at the end of each command execution.
                                                                       [boolean]
  --version   Show version number                                      [boolean]

Run `plz --help` or `plz <command> --help` to get more info.

Run `DEBUG=plz plz <command> [options]` to get more detailed output for
troubleshooting.
```

## CLI Commands and options

### create

Creates a new project.

```text
$ plz create <name> [root-dir]

Generates a new project called <name>

Positionals:
  name      Name of the project, will be used by default for the name of the
            generated directory.                             [string] [required]
  root-dir  Optional root directory for new project                     [string]

Options:
  -h, --help          Show help                                        [boolean]
  --no-emoji          Strip all emojis from the cli output in the terminal.
                                                                       [boolean]
  --report            Add memory reporting at the end of each command execution.
                                                                       [boolean]
  --version           Show version number                              [boolean]
  --project-type, -t  Project type, one of: react-app, react-component,
                      module.The tooling configs (webpack, babel, etc.) will be
                      determined from the project type.   [default: "react-app"]
  --template, --tpl   Optional custom URL of template repo to be used for the
                      project. Templates use handlebars to create directories
                      and files dynamically.
```

**name**

Name of the project, will be used by default for the name of the generated directory. It will also be passed down to the template to be used for the package name, core class names, etc.

**project-type**

The type of project you want to create. This determines the default template, as well as the default configs and setup for the other commands.

**template**

By default plz will pick the template, according to the project type, from the `src/templates/[type]` folder. Optionally you can pass in your own template, either via path (relative to the current working directory), or via git repo. You can also define a sub directory of a repo, by just extending the repo URL with the dir path, e.g.:

```bash
# Relative path
plz create new-project --template ./my/relative/sub-folder

# Github repo
plz create new-project --template git@github.com:smith/my-monorepo.git

# Github repo with subfolder specified
# This will clone `git@github.com:smith/my-monorepo.git` and then copy `some/sub-folder`
# based on the repos root directory
plz create new-project --template git@github.com:smith/my-monorepo.git/some/sub-folder
```

The above will clone `git@github.com:smith/my-monorepo.git` and then use the sub directory `some/sub-folder` (relative to the repo's root folder) as the template directory.

You can also override the default template via `plz config`, so you don't have to always manually specify them when using plz.

```bash
# set template.[type], can be any format mentioned above
plz config templates.react-app ./my/relative/sub-folder
```

If you want to use an npm package for your templates, you can use the `plz use` shortcut.

```bash
npm i -g my-template-package
plz use my-template-package
```

Templates are parsed using [copy-template-dir](https://github.com/yoshuawuyts/copy-template-dir), which allows injecting variables via mustache syntax. See below for more details and available variables. For more details on how templates work see the [advanced docs](./docs/templates.md).

## serve

> Exclusive to project type `react-app`!

Starts webpack dev server for a dev enviroment with good developer experience.

```text
$ plz serve

Options:
  -h, --help      Show help                                            [boolean]
  --version       Show version number                                  [boolean]
  --port          Port for the dev server.                       [default: 3000]
  --host          Host for the dev server.                [default: "localhost"]
  --open-browser  Open the server automatically in the default browser once it
                  is started.                                    [default: true]
```

**port / host**

Port and host to be used for the dev server. By default, plz will start the server on [http://localhost:3000](http://localhost:3000). If the port is already used, plz will prompt you with the option to use the next available port instead.

**open-browser**

By default plz will automatically open the dev environment in your default browser once the server is successfully started. If you don't want that, you can disable it via `plz serve --open-browser=false`.

### build

Bundles a project for distribution.

```text
$ plz build

Bundles a project for distribution.

Options:
  -h, --help  Show help                                                [boolean]
  --no-emoji  Strip all emojis from the cli output in the terminal.    [boolean]
  --report    Add memory reporting at the end of each command execution.
                                                                       [boolean]
  --version   Show version number                                      [boolean]
  --stats     Use this option to generate webpack stats during the build and
              automatically start webpack-bundle-analyzer after successful
              build.
  --serve     Starts express server to serve the production bundle after
              successful build.
```

The output depends on the project type. Modules and React components will be bundled optimised for releasing them as npm libraries, while React apps will be bundled into a `public` directory optimised for deployment. Plz will default the `NODE_ENV` to production, unless manually specified otherwise.

**stats**

For react apps you can run `plz build --stats`. This will run the normal build, and then automatically run [`webpack-bundle-analyser`](https://github.com/webpack-contrib/webpack-bundle-analyzer), giving you a nice visual representation of your bundles and which dependencies they consist of. This can be really useful when trying to improve your bundle size 😊

**serve**

Also for react apps, you can run `plz build --serve`. Again, this will build your app normally, but will then start up a local node server to serve that build. This can be helpful if you want to test your application in production mode.

### stories

Opens development environment, starting a Storybook dev server. Plz will pick up stories from `src/.stories.js` by default, you can override this via the `storybook.storiesPattern` config.

```text
$ plz stories

Options:
  -h, --help    Show help                                              [boolean]
  --version     Show version number                                    [boolean]
  --port        Port for the storybook server.                   [default: 3001]
  --root-dir    Directory to search in, for multiple package stories.
                                                [string] [default: "components"]
  --output-dir  Directory to build & output a static storybook app.     [string]
```

**port**

Same as with `serve`, the port for the dev server. Again, plz will prompt you if the port is already in use. Defaults to [http://localhost:3001](http://localhost:3001).

**root-dir**

This option is for monorepo support. If you're maintaining a monorepo with multiple repos that all contain stories (ideally bootstrapped via plz to ensure proper folder structure), you can run `plz serve` from the root specifying the root dir for all the repos you want plz to look in for stories.

**output-dir**

If you specify this, instead of booting up the dev server, plz will run `build-stories` and put the output into the specified output directory. This can be useful e.g. for CI, if you want to create a static build of storybook for you master or PR branches.

### test

Runs jest tests on the project.

```text
$ plz test

Options:
  -h, --help  Show help                                                [boolean]
  --version   Show version number                                      [boolean]
  --watch     Rerun tests when files change.          [boolean] [default: false]
```

Any options will be passed through to `jest` itself, so you can use everything you already know, e.g. `--watch`, `--coverage`, etc.

### config

Set instance config key value pair, or read current config. This can be useful for globally installed `plz` instances, e.g. to override the templates used for the `create` command.

```text
$ plz config [key] [value]

Sets (or reads) config of the plz instance. Can be used to change defaults.

Positionals:
  key    Config key                                                     [string]
  value  Config value for given key, if a relative path is given it will be
         resolved based on the current working directory.               [string]

Options:
  -h, --help  Show help                                                [boolean]
  --no-emoji  Strip all emojis from the cli output in the terminal.    [boolean]
  --report    Add memory reporting at the end of each command execution.
                                                                       [boolean]
  --version   Show version number                                      [boolean]
  --get       Read config value(s).
```

Example for overriding the default template for react apps:

```bash
plz config templates.react-app ./my/custom/path
```

### use

Abstraction for `config`, using the given npm package for template paths in the cli default config.

```text
$ plz use <package-name>

Sets the given package as template source. See --help for more details.

Positionals:
  package-name  Name of globally installed npm package. It needs to be already
                installed, plz will use "npm root -g" to find the given package.
                                                             [string] [required]

Options:
  -h, --help  Show help                                                [boolean]
  --no-emoji  Strip all emojis from the cli output in the terminal.    [boolean]
  --report    Add memory reporting at the end of each command execution.
                                                                       [boolean]
  --version   Show version number                                      [boolean]
```

## Debugging

If you need to troubleshoot issues, you might find the more verbose debug output helpful. To show these, simply run:

```bash
DEBUG=plz plz <command> [options]
```

You can find more info here: [https://github.com/visionmedia/debug](https://github.com/visionmedia/debug)

## Config

Config for the `plz` 🙏 cli is resolved from established configuration files [like other cli tools](https://github.com/davidtheclark/cosmiconfig#explorersearch).

- the `plz` property in `package.json` file
- the `.plzrc` file (optionally with `.json`, `.yaml`, `.js` extensions)
- the `.plz.config.js` file

The Javascript versions are especially helpful when overriding the tool configs, as you will want to define a function that receives the proposed config and returns your adjusted version.

### Available options

```js
{
  // Project type, determines how project is bootstraped, built, served, etc.
  // One of "react-app", "react-component" and "module"
  "projectType": "react-component",

  // Build dir, by default "public" for React apps
  // For modules and React components its the project root, since they
  // will generate multiple bundle dirs (module, lib)
  "buildDir": "public",

  // If enabled it adds css modules support to the project
  // https://github.com/css-modules/css-modules
  "cssModules": false,

  // When enabled, packages found in node_modules/ that have a package.json
  // plz:main field will be compiled & watched with Babel
  // This can be especially helpful within monorepos
  "runtimeCompilation": false,

  // A map of proxy configs
  // See "further documentation" for more details
  "proxy": {},

  // All options for Storybook's runtime
  "storybook": {},

  // The version of corejs to apply polyfills with using `@babel/preset-env`
  "corejs": 3,

  // Middleware for babel config
  "babel": (config) => config,

  // Same for webpack
  "webpack": (config) => config
}
```

For more details about the tool configs see the [futher documentation](./docs/tool-configs.md).

## Contributing

### Structure of this repo

```bash
.
├── CHANGELOG.md # Automatically generated by lerna!
├── __tests__ # Test files for plz, run via `yarn test(:watch)`
├── package.json
├── README.md
├── src
│   ├── bin.js # Node binary entry point
│   ├── commands # Commands dir, automatically detected through yargs
│   │   ├── build.js
│   │   ├── clean.js
│   │   ├── create.js
│   │   ├── serve.js
│   │   ├── stories.js
│   │   └── test.js
│   ├── configs # Tooling configs + collection for project types in `project`
│   │   ├── babel
│   │   ├── jest
│   │   ├── project
│   │   ├── storybook
│   │   └── webpack
│   ├── index.js # Entry point for imports
│   ├── templates # Default templates for the different project types
│   │   ├── module
│   │   ├── react-app
│   │   └── react-component
│   └── utils # General util methods
└── support # Any node helper scripts

```

All commands are automatically detected by [yargs](https://github.com/yargs/yargs) through the [`commandDir` method](https://github.com/yargs/yargs/blob/master/docs/advanced.md#commanddirdirectory-opts), which is set to `/commands`. Files in there need to export all the command relevant information themselves.

### Running tests

```bash
# Watch for changes, rerunning tests
yarn test:watch

# Run watch once
yarn test

# Get test coverage
yarn test --coverage

# Test the slower project tests
yarn test:integration
```

## Further documentation

- [Templates](./docs/templates.md)
- [Tool configs in detail (webpack, babel, jest, storybook)](./docs/tool-configs.md)
- [Proxy config](./docs/proxy.md)

## Resources

- https://storybook.js.org
- https://github.com/storybooks/storybook/tree/master/addons/options
- https://github.com/storybooks/storybook/tree/master/addons/storyshots
- https://webpack.js.org
- https://webpack.js.org/configuration/
- https://facebook.github.io/jest
- https://babeljs.io
- https://babeljs.io/docs/usage/api/
- https://github.com/davidtheclark/cosmiconfig

## Roadmap

- [ ] Typescript support
- [ ] Better error handling and more helpful / meaningful messages