# arc-components-builder

> Node module to create a bundle import file from ARC and any web components

Latest version **0.1.0** (published 2017-12-05) · Apache-2.0 OR CC-BY-4.0 license · 0 weekly downloads

## Install

```sh
npm install arc-components-builder
pnpm add arc-components-builder
yarn add arc-components-builder
bun add arc-components-builder
```

## Health

**Score 5/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: insecure dependencies; abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.1.0 |
| Published | 2017-12-05 |
| First published | 2017-12-05 |
| Weekly downloads | 0 |
| License | Apache-2.0 OR CC-BY-4.0 |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >=6.5.0 |
| Dependencies | 11 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | The Advanced REST client authors |
| Maintainers | jarrodek |

## Links

- npm: https://www.npmjs.com/package/arc-components-builder
- Repository: https://github.com/advanced-rest-client/arc-components-builder
- Homepage: https://github.com/advanced-rest-client/arc-components-builder#readme
- Issues: https://github.com/advanced-rest-client/arc-components-builder/issues
- npm.io page: https://npm.io/package/arc-components-builder

## Dependencies (11)

- [gulp](https://npm.io/package/gulp.md) github:gulpjs/gulp#4.0
- [colors](https://npm.io/package/colors.md) ^1.1.2
- [gulp-if](https://npm.io/package/gulp-if.md) ^2.0.2
- [winston](https://npm.io/package/winston.md) ^2.3.1
- [fs-extra](https://npm.io/package/fs-extra.md) ^3.0.0
- [through2](https://npm.io/package/through2.md) ^2.0.3
- [wc-reactor](https://npm.io/package/wc-reactor.md) ^0.1.0
- [merge-stream](https://npm.io/package/merge-stream.md) ^1.0.1
- [polymer-build](https://npm.io/package/polymer-build.md) 1.5.1
- [polymer-analyzer](https://npm.io/package/polymer-analyzer.md) ^2.7.0
- [api-console-dependency-manager](https://npm.io/package/api-console-dependency-manager.md) ^0.1.0

## Recent versions

- 0.1.0 (latest) — 2017-12-05

## README

# arc-components-builder

Node module to create a bundle import file from ARC or any Polymer powered components.
It also generates React wrapper definition for the components using [wc-reactor](https://github.com/advanced-rest-client/wc-reactor) module.

# What does it do?

Let's start what it doesn't do. It doesn't creates a new React components based on web components definition. After creating React wrapper you still have to use `import.html` file with bundled web components definitions.

This library generates a **bundle file of web components**. It can be used to optimize number of `import`s declaration in the web application. Under the hood it uses `polymer-build` library so it basically do the same thing with bundling the components.

Another thing it does **is generating a React wrapper for the web components** so it can be used in React application. It creates exactly the same interface as web components uses. It handles all custom events, property change events and data binding (in a React way).

## Example

```javascript
const builder = require('arc-components-builder');

builder({
  // Any web component, it can contain version declaration
  webComponents: [
    'PaperElements/paper-input#1.0.0',
    'vaadin/vaadin-button'
  ],
  // Any ARC component, it also can contain version declaration
  arcComponents: [
    'content-type-selector',
    'paper-combobox',
    'headers-editor',
    'http-method-selector',
    'url-input-editor'
  ],
  // print debug output
  verbose: true,
  // Creates React wrapper
  react: true,
  // Create React interface for the following components only.
  reactComponents: ['url-input-editor']
})
.then(() => console.log('Build complete <3'));
```

The result of building the components is located in `./build` directory.
It's structure is:

```
| build/
  | - bower-components/
      | - ...
  | - UrlInputEditor
      | - UrlInputEditor.js
      | - index.js
  | - import.html
```
Most important files are `import.html` and `UrlInputEditor/UrlInputEditor.js`. The import file
contains a bundle of web components defined in `webComponents` and `arcComponents`
configuration directive as well as all it's dependencies. This is single file build
of included web components.

The React component file contains autogenerated interface to communicate with web
components in a React application. Check names mapping section below to understand
how to map event names to React functions.

The `bower_components` directory contains all used web components definition. It can be useful
if the components that are bundled in `import.html` file contains a reference to a resource
in `bower_components` directory that couldn't been processed by `polymer-build`
(like dynamically loaded JS library from component's directory). You may want to copy
components directory to your web server. In most cases it won't be used at all.

## Names mapping in React component

React wrapper contains interface to manipulate web component's properties, handle
custom events (including properties change events) and to call public API functions.

### Properties mapping

Web components property names are the same as React's `props`. So you can use
generated component like this:

```javascript
render() {
  return (
    <PaperCombobox label="My label" value={this.props.value}/>
  );
}
```

When the `PaperCombobox` component is mounted then the `label` and `value` properties
are propagated to the underlying web component. The same is happening each time
when React's state change:

```javascript
/**
 * Updates list of suggestion in the PaperCombobox web component
 */
updateSuggestions() {
  this.setState({
    source: ['One', 'Two', 'Three']
  });
}

render() {
  return (
    <PaperCombobox label="My label" source={this.state.source}/>
  );
}
```

Updating the sate value will update corresponding web component's property.

#### Polymer's data binding

Polymer powered web components uses Polymer's data binding for properties. This
can be easily done in react by using `on` + `propertyName` + `Changed` function set to a property.

Assuming that the `PaperCombobox` web component has `value` property that `notify` value change (sends non-bubbling custom event when value changes).
You can handle it in React application using functions:

```javascript
_onValueChanged(newValue, e) {
  e.preventDefault();
  console.log(newValue);
}

render() {
  return (
    <PaperCombobox label="My label" source={this.state.source} onValueChanged={this._onValueChanged}/>
  );
}
```

New value and original event is always passed to data binding change function calls. You can use event to access additional data like information about the target or path. Note, that target may not be the web component but an element inside it.

Note: Only public properties are handled by the wrapper. It doesn't work with protected properties (property name starts with `_`).

### Methods mapping

Methods are mapped 1:1 from the web component. Only public methods are available to wrapper.
Web component's lifecycle methods are also unavailable.

Let's assume that the `PaperCombobox` element has a `selectNext` method in it's public API:

```javascript
selectNextDropdownItem() {
  this._refElement.selectNext();
}

render() {
  return (
    <PaperCombobox ref={(element) => {this._refElement = element;}}/>
  );
}
```

### Events mapping

Custom events names are translated to camel case function call as:
`on` + `UppercaseCamelCaseEventName`.

Custom event's detail object and the event itself is passed as an argument to the function call.

Assuming that the `paper-combobox` web components dispatches `next-selected` event. It can be handled by
setting `onNextSelected` property on the components that is a handler for event.

```javascript
_comboNextSelected(detail, e) {
  console.log(e.target, e.path);
  console.log('Next element selected', detail);
  // detail === e.detail
}

render() {
  return (
    <PaperCombobox onNextSelected={this._comboNextSelected}/>
  );
}
```

The script above handles the `next-selected` event and passes the detail of the event
to the function.

### More examples

Checkout our example build usage project to see how to use generated module in
React application: https://github.com/advanced-rest-client/arc-components-builder-example

## API

All options are defined in `lib/project-options.js`.

**arcComponents** {`Array<String>`}

A list of ARC web components to be used.
It should be a list of names of the components only, without `advanced-rest-client/`
prefix as it will be added by the program.

You can control version of the component by adding version number for the
components as in npm or bower.

Example: `['paper-autocomplete#1.0.0', 'raml-request-panel#^1.1.0']`

**webComponents** {`Array<String>`}

The same as `arcComponents` but it must be full bower definition of the component dependency.

Example: `['PolymerElements/paper-input', 'PolymerElements/paper-icon-button#1.0.0']`

**style** `{String}`

Path to `custom-style` module with theme definition for the ARC / web components.

**dev** `{Boolean}`

If set it will not create a bundle file but only an import file with
references to `bower_components` directory where the source code of the elements
is downloaded. It can be helpful for dubugging when you want to debug specific
element without braking current dev setup.

The build directory contains the import file and `bower_components`. Both should
be copied to server and put into the same location.

**react** `{Boolean}`

Specify to generate React components definition from the elements.
Generated source file contains classes definitions for each component with access
points to all public APIs of the element (properties, functions and custom events).

**reactComponents** {`Array<String>`}

List of web components names to be exposed to generated React component so it can
be included in React application.

Defining this option is optional. By default all listed components in `arcComponents`
and `webComponents` properties are exposed to React application.

To reduce size of generated code it is a good idea to declare number of components
that your application is actually using.

Provide list of components names only, without any repository path or version information.

For example `['raml-request-panel', 'paper-input']`

**bundleReactComponents** `{Boolean}`

By default it creates a separate React file for each web component that is to be wrapped in React code.
When this option is set then it bundles all React components into a single file and exports each React component in this file.

This can be set only if `react` option is set.

**dest** `{String}`

The destination where the build files are put. Absolute or relative path.

By default it puts the files into `build` directory of the working dir.

**logger** `{Object}`

Instance of any logger library that has `log()`, `info()`, `warn()` and `error()` functions.
If not provided a console's output will be used.

**verbose** `{Boolean}`

If set then it prints verbose messages.

## Double events problem

Sometimes Polymer web components sends an event that has the same name as
data binding event. In this case you will notice two handler function calls with
different set of arguments.

Polymer powered web component can contain a property declaration with `notify`
set to true. It is used by the data binding system to update property value on a
parent element / application. Those change events does not bubble. They can be only
handled when setting an event listener on the element. That's is why sometimes
authors prefer to send additional event with the same name that bubbles through
the DOM. Consider the following example:

```javascript
// Polymer element (v1)
Poymer({
  is: 'paper-combobox',
  properties: {
    value: {
      type: String,
      notify: true,
      observer: '_valueChanged'
    }
  },

  _valueChanged: function(value) {
    this.fire('value-changed', {
      value: value
    });
  }
});
```
This components sends two `value-changed` events when the value property have changed.
Because of the name collision the React wrapper automatically calls `onValueChanged`
prop function as a data binding automated function and then it also listens for
the `value-changed` event and calls the same `onValueChanged` function.

Automated change handler functions have a value of changed property as the first argument.
Regulars event handlers have event's detail object as a first argument. Therefore you
may end up handling the same event twice but with different argument.

## Contributing

1. Fork it
2. Create your feature branch: `git checkout -b my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin my-new-feature`
5. Submit a pull request <3

## Supported Node.js Versions

arc-components-builder officially supports the latest current & active [LTS](https://github.com/nodejs/LTS) versions of Node.js. It may be working with previous versions but it is not intentional.

---
_Source: https://npm.io/package/arc-components-builder · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
