restencil v0.3.1
restencil
Automatically generates React components for a component library created with stencil.js. No more worrying about whether props are arrays or objects, and no more cumbersome attachment of event listeners. Just use them like any other React component.
Example
Assume we have a web component with an html tag of my-formatted-button
that:
- Has an attribute called
title
, of typestring
- Has a property called
values
of typeobject
- Fires a custom event called
buttonClicked
Without restencil, quite a bit of setup is needed just to pass down some values:
const TestComponent = (props) => {
// need a handle to the native DOM element
const ref = React.useRef()
React.useEffect(() => {
// can't pass objects as attributes in the render phase
ref.current.values = props.values
}, [props])
React.useEffect(() => {
const element = ref.current
const handleClick = () => console.log('button was clicked')
// have to attach event listeners via DOM methods
element.addEventListener('buttonClicked', handleClick)
// and don't forget to remove the listener on unmount!
return () => {
element.removeEventListener('buttonClicked', handleClick)
}
}, [])
return <my-formatted-button ref={ref} title={props.title} />
}
With restencil:
import { MyFormattedButton } from 'awesome-lib-react'
const RestencilTestComponent = (props) => {
const handleClick = () => console.log('button was clicked')
return (
<MyFormattedButton
title={props.title}
options={props.options}
onButtonClicked={handleClick}
/>
)
}
Setup
All that is required for restencil project is a package.json
. No source code, no additional config files. restencil takes care of everything.
Assuming the stencil component library is called awesome-lib
:
Create a new project with a package.json
mkdir awesome-lib-react
npm init -y
npm i awesome-lib
npm i -D restencil
Configure package.json
- Add a
source
entry, which is the destination path for the generated source code file. This will be overwritten on each build. - Add one or more build targets. These can include commonjs, es module, and umd for unpkg.
main
- commonjs modulemodule
- es moduleunpkg
- umd module
Example package.json
{
"name": "awesome-lib-react",
"version": "1.0.0",
"description": "React components for the awesome-lib component library",
"source": "dist/src.js", // this source file will be generated by restencil on each build
"main": "dist/awesome-lib-react.js", // desination for the compiled commonjs module
"module": "dist/awesome-lib-react.mjs", // desination for the compiled es module
"unpkg": "dist/awesome-lib-react.umd.js", // desination for the compiled umd module
"files": [ "dist" ], // base dir of the compiled files above
"scripts": {
"build": "restencil -m awesome-lib" // build script, with '-m stencil-module-name'
},
"peerDependencies": {
"awesome-lib": "1.2.3", // the stencil component module
"react": "^16.8.0" // must be used with React 16.8.x
},
"devDependencies": {
"awesome-lib": "1.2.3" // the stencil component module
"restencil": "^0.2.0"
}
}
Build
npm run build
Motivation
stencil.js creates web components that can be shared between different frameworks. Unfortunately, React doesn't have the best support for web components (see unsupported features). Working with them requires native DOM interactions, and that clashes somewhat with archetypal React patterns of allowing React to manage everything via the JSDOM.
This means that when using them, props passed to web components within JSX can only be primitives. Arrays, any type of object, or functions will be passed as their toString()
text. In particular, this means that any props you want to pass that are objects or arrays have to be set on the DOM element directly, and any events you want to handle have to be attached via addEventListener
(and also removed on unmount).
Future plans:
- Generate
package.json
with an init script. - Automate checking for updates of the stencil library, and use lockstep versions with it