ARCHIVED - Use https://github.com/ionic-team/stencil-ds-plugins
The ionic team has released their own official library for this purpose that better integrates and should have much better support. Leaving this around as an example of wrapper component generation.
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.
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
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} />
}
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}
/>
)
}
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
:
mkdir awesome-lib-react
npm init -y
npm i awesome-lib
npm i -D restencil
- 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
{
"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"
}
}
npm run build
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).
- Generate
package.json
with an init script. - Automate checking for updates of the stencil library, and use lockstep versions with it