I'm creating some basic elements in Stencil for a custom design system. I created some basic components, which work fine on their own as custom elements, but throw errors when used as React components.
I generated the React components via Stencil by includng the @stencil/react-output-target
in stencil.config.ts
.
reactOutputTarget({
componentCorePackage: '@sr-design-system/simple-stencil-demo',
proxiesFile: './react/src/components/index.ts',
includeImportCustomElements: true
}),
I then uploaded all of the components (custom elements & React) to a private npm package and installed them in a seperate project. The custom elements seem to work fine, but with the React elements I get the following error.
ERROR in ./node_modules/@sr-design-system/simple-stencil-demo/react/src/index.ts 6:12
Module parse failed: Unexpected token (6:12)
File was processed with these loaders:
* ./node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| import { createReactComponent } from './react-component-lib';
|
> import type { JSX } from '@sr-design-system/simple-stencil-demo/';
|
| import { defineCustomElement as defineSrText } from '@sr-design-system/simple-stencil-demo/dist/components/sr-text';
@ ./src/App.jsx 7:0-73
@ ./src/index.jsx 7:0-24 12:33-36
webpack 5.65.0 compiled with 1 error and 1 warning in 63 ms
I've been stuck on this issue for days now. Any idea what the solution could be?
===tsconfig.json===
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"declaration": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"lib": ["dom", "es2017"],
"module": "es2015",
"moduleResolution": "node",
"pretty": true,
"removeComments": false,
"strictPropertyInitialization": false,
"target": "es2017",
"baseUrl": ".",
"paths": {
"@srds/react": ["./react"]
},
"jsx": "react",
"jsxFactory": "h"
},
"include": ["src"]
}
===stencil.config.ts===
import { Config } from '@stencil/core';
import { reactOutputTarget } from '@stencil/react-output-target';
export const config: Config = {
namespace: 'simple-stencil-demo',
bundles: [{ components: ['sr-text'] }, { components: ['text-demo'] }],
outputTargets: [
reactOutputTarget({
componentCorePackage: '@sr-design-system/simple-stencil-demo',
proxiesFile: './react/src/components/index.ts',
includeImportCustomElements: true,
}),
{
type: 'dist',
esmLoaderPath: './loader',
},
{
type: 'dist-custom-elements',
},
{
type: 'docs-readme',
},
{
type: 'www',
serviceWorker: null, // disable service workers
},
],
buildEs5: 'prod',
};
I figured out what the issue. For some reason, the dist
folder was not being generated for me every time I ran npm run build
.
Sometimes it was generated, other times it wasn't. I believe it was due to some errors in my component code, which failed silently. So now I check for the dist folder every time I build the library.
In my final, working attempt I went with the monorepo approach as advised by the Stencil team in their documentation.
Here are all I took the steps for a basic Stencil library with a React output:
npx stencil generate
npm i @stencil/react-output-target
stencil.config.ts
react({
componentCorePackage: 'MY_LIBRARY',
proxiesFile: '../MY_REACT_LIBRARY/src/components/stencil-generated/index.ts',
includeDefineCustomElements: true,
}),
package.json
to MY_REACT_LIBRARYpackage.json
npm run build
npm link
to generate a global symlinknpm link MY_LIBRARY
npm i
npm run build
(Not sure if this step is required as it is not documented, but I did it anyway)npm link
npx create-react-app MY_REACT_DEMO --template typescript
npm link MY_REACT_LIBRARY
App.tsx
npm run start
When I confirmed everything worked fine, I added a basic lerna.json
config for npm package management. Using this config, Lerna will automatically handle symver for our packages.
{
"version": "independent",
"npmClient": "npm",
"command": {
"publish": {
"allowBranch": ["master", "react-generation"],
"ignoreChanges": ["*.md", "build.js", "config.json"],
"message": "(auto) Lerna publish",
"registry": "URL_TO_MY_PACKAGE_REGISTRY"
},
"bootstrap": {
"ignore": "component-*",
"npmClientArgs": ["--no-package-lock"]
}
},
"packages": ["MY_LIBRARY", "MY_REACT_LIBRARY"]
}
After configuring Lerna, I published using the command npx lerna publish
, following their publishing wizard.
When it's published the package can be installed in any React project using npm i MY_REACT_LIBRARY
and it should work.