ionic-team / stencil-ds-output-targets Goto Github PK
View Code? Open in Web Editor NEWThese are output targets that can be added to Stencil for React and Angular.
Home Page: https://stenciljs.com
License: MIT License
These are output targets that can be added to Stencil for React and Angular.
Home Page: https://stenciljs.com
License: MIT License
@my-scope/[email protected] tsc /Users//Projects/component-library/packages/component-library-react
tsc -p .
src/components.ts:8:54 - error TS2307: Cannot find module '@my-scope/component-library/loader' or its corresponding type declarations.
8 import { defineCustomElements, applyPolyfills } from '@my-scope/component-library/loader';
~~~~~~~~~~~~~~~~~~~~~~~~
Found 1 error.
The above error was thrown when I tried to compile the react output of my component library which was generated using '@stencil/react-output-target'.
However, I was able to figure out the error. The import statement should be
8 import { defineCustomElements, applyPolyfills } from '@my-scope/component-library/dist/loader';
instead of
8 import { defineCustomElements, applyPolyfills } from '@my-scope/component-library/loader';
Hello. I originally posted this issue in the demo project repo, but have not got any response in a week, so thought I would also post it here, since I believe it actually an issue with the plugin.
see ionic-team/stencil-ds-plugins-demo#14
Steps to Repro:
See following error in console (twice)
AppComponent.html:3 ERROR NullInjectorError: StaticInjectorError(AppModule)[DemoComponent -> ChangeDetectorRef]:
StaticInjectorError(Platform: core)[DemoComponent -> ChangeDetectorRef]:
NullInjectorError: No provider for ChangeDetectorRef!
at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (http://localhost:4200/vendor.js:89853:25)
at resolveToken (http://localhost:4200/vendor.js:101046:24)
at tryResolveToken (http://localhost:4200/vendor.js:100990:16)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (http://localhost:4200/vendor.js:100892:20)
at resolveToken (http://localhost:4200/vendor.js:101046:24)
at tryResolveToken (http://localhost:4200/vendor.js:100990:16)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (http://localhost:4200/vendor.js:100892:20)
at resolveNgModuleDep (http://localhost:4200/vendor.js:109362:29)
at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (http://localhost:4200/vendor.js:110033:16)
at resolveDep (http://localhost:4200/vendor.js:110404:45)
I couldn't find a clear answer why, but through trial-and-error I learned that bindings are only generated for production, not when --dev
is passed:
I can remove --dev
easy enough, but I want to understand the implications of this (cannot find documentation clearly stating what it does).
My goal is to generate bindings during development so I can leverage Storybook for showing both my Stencil components and stories for Angular/React/Vue.
I'm a bit new with Angular so please excuse any ignorance on my part. From all my digging and experimenting, I cannot get Stencil with angular-output-target working with Angular 8. Neither have I seen any documentation or notes on what versions it is compatible with - considering how fast Angular has major version updates, this is unfortunate.
This demo uses Angular 7.2 and I am able to get that working correctly.
However, when I create a fresh install of Stencil, follow the documentation here and on the demo template to set up angular-output-target and try to use it with a fresh installation of Angular 8, the app breaks.
The error thrown is NullInjectorError: No provider for ChangeDetectorRef
I'm unfortunately not familiar enough with Angular to know enough about ChangeDetectorRef
or why it would be failing within a v8 ecosystem. I'd love to help update the plugin to work with Angular 8, so hopefully all of this makes sense and someone can shed some light on the issues!
In normal React components, the following is a no-op:
<SomeComponent onSomeEvent={undefined} />
This is useful in cases where props are optional, or handlers are conditional for some other reason. E.g.
const TestInput = ({ name, onBlur, onChange }) => (
<input name={name} onBlur={onBlur} onChange={onChange} />
)
But will fail when used similarly with a wrapped stencil component if onBlur
is not supplied:
const TestInput = ({ name, onBlur, onChange }) => (
<MyStencilInput name={name} onBlur={onBlur} onChange={onChange} />
)
// attachEventProps.js?9a31:67 Uncaught TypeError: Cannot read property 'call' of undefined
// at HTMLElement.handler (attachEventProps.js?9a31:67)
The addEventListener
call below should be wrapped in a newEventHandler != null
check (or possibly even a typeof newEventHandler === 'function'
)
https://github.com/ionic-team/stencil-ds-plugins/blob/1ed6161741d6210ebbe4def607a4d3532e804b8a/packages/react-output-target/react-component-lib/utils/attachEventProps.ts#L73
Hi!
When I use [email protected], the props are being removed from the initial render which causes missing data when doing SSR.
Here is how to reproduce:
https://github.com/nowseemee/react-proxy-bug-repro
Here is what I think the fix is:
49a0219
Any reason for manipulating props in the render method? I think all manipulation should takes place in componentDidUpdate.
Let me know, thanks!
Output of ts
/* eslint-disable */
/* tslint:disable */
/* auto-generated react proxies */
import { createReactComponent } from './react-component-lib';
import { JSX } from 'stencil-components';
import { defineCustomElements, applyPolyfills } from 'stencil-components';
applyPolyfills().then(() => defineCustomElements());
file: loader/index.d.ts
export declare function defineCustomElements(win: Window, opts?: CustomElementsDefineOptions): Promise<void>;
Versions:
I provide an ValueAccessorConfig with multiple different elementSelectors and events for a single type: E.g.:
const valueAccessorConfig = [
{
elementSelectors: 'my-input',
event: 'myinputchange',
targetAttr: 'value',
type: 'text',
},
{
elementSelectors: 'my-search',
event: 'mysearchtrigger',
targetAttr: 'value',
type: 'text',
}
];
The build produces invalid typescript by missing "," at the end of the lines:
// text-value-accessor.ts
...
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'scu-input, scu-search, scu-text-area',
host: {
'(scuinputchange)': 'handleChangeEvent($event.target.value)'
'(scusearchtrigger)': 'handleChangeEvent($event.target.value)' // <= ',' expected. ts(1005)
'(scutextareainput)': 'handleChangeEvent($event.target.value)' // <= ',' expected. ts(1005)
},
...
Hello and thank you for this great plugin. It shows lots of promise for making web component libraries easier to consume from React. That said, I have observed a couple warnings I've encountered while trying to use the React components within React applications.
The library that I published is here and is being used as follows:
import { ManifoldInit } from "@manifoldco/manifold-init-react/dist/components";
const Home = () => (
<div className="container">
<ManifoldInit env="stage" clientId="my-client-id" />
The app renders the component correctly but I've seen some warnings both in CRA and NextJS.
When I use create-react-app I get the following warning in my browser console:
Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of ManifoldInit which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://fb.me/react-strict-mode-find-node
in manifold-init (created by ManifoldInit)
in ManifoldInit (created by ForwardRef(ManifoldInit))
in ForwardRef(ManifoldInit) (at App.js:9)
in div (at App.js:8)
in App (at src/index.js:9)
in StrictMode (at src/index.js:8)
I'd probably trace this to the createReactComponent
which contains this in the cjs build:
componentDidUpdate(prevProps) {
const node = ReactDom.findDOMNode(this);
attachEventProps(node, this.props, prevProps);
}
The component renders as it should for now but since findDOMNode
is deprecated I expect that this will break in the future. Can this be updated to support StrictMode properly?
When I run my NextJS dev server, my terminal shows following error the first time I load the app:
(node:13529) UnhandledPromiseRejectionWarning: TypeError: head.querySelector is not a function
at Object.bootstrapLazy (/home/sam/taco-cloud-react/node_modules/@manifoldco/manifold-init/dist/cjs/index-1ab6c73d.js:825:44)
at /home/sam/taco-cloud-react/node_modules/@manifoldco/manifold-init/dist/cjs/loader.cjs.js:8:16
(node:13529) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:13529) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I don't know if that's because NextJS is SSR and there's some code that shouldn't be running on the server side, but I tried rendering the component only when process.browser
is defined and the error didn't go away, so it's hard to tell.
Again, the component renders fine on the page, but perhaps there are some places where SSR should be taken into account.
Use strict for Typescript and also fix any issues that arise from this change
When a Stencil component uses a slot and is not using the shadow DOM, the React component should be able to dynamically update the children it passes the component (as slotted elements) and not have it completely overwrite the internals of the Stencil component.
For example:
A Stencil component implemented as such:
@Component({ tag: 'custom-button' })
export class CustomButton {
render() {
return (
<button>
<span>Pre-existing Content:</span>
<slot />
</button>
);
}
}
In React:
import React, { useState } from "react";
import { CustomButton } from "../../components";
export default function ButtonWrapper() {
const [buttonText, setButtonText] = useState('button text')
return (
<>
<CustomButton>{buttonText}</CustomButton>
<input value={buttonText} onChange={e => setButtonText(e.target.value)}></input>
</>
);
}
On initial render, the custom button's DOM looks like:
<custom-button class="hydrated">
<button>
<span>Pre-existing Content:</span>
<span class>button text</span>
</button>
</custom-button>
When we update the value and thereby the slotted content that gets rendered inside the <slot />
in our custom button, the DOM looks like this:
<custom-button class="hydrated">updated text</custom-button>
thereby wiping out the internal structure of our custom element.
I am aware that using shadow DOM is a possible remedy to this problem, however there are actual bugs in Google Chrome with shadow DOM that prevent us from completely adopting shadow DOM across the board.
Versions:
Our stencil.config.ts
looks like this:
import { Config } from '@stencil/core';
import { angularOutputTarget, ValueAccessorConfig } from '@stencil/angular-output-target';
export const config: Config = {
namespace: 'schwarz-core-ui',
globalScript: 'src/global/global.ts',
globalStyle: './src/assets/index.global.less',
outputTargets: [
...
angularOutputTarget({
componentCorePackage: '@my/lib',
directivesProxyFile: '../my-lib-angular-bindings/src/directives/proxies.ts',
directivesArrayFile: '../my-lib-angular-bindings/src/directives/array.ts',
directivesUtilsFile: '../my-lib-angular-bindings/src/directives/utils.ts',
valueAccessorConfigs,
}),
],
};
The proxy.ts import path tries to import the component types from the incorrect relative path ../my-lib-repo/dist/types/components/
.
Instead it should just reference the package directly (via package name @my/lib
) like in the first line of this proxy.ts snippet:
// my-lib-angular-bindings/src/directives/proxies.ts
...
import { Components } from '@my/lib' // <= Uses library here correctly
import { MyAccordion as IMyAccordion } from '../my-lib-repo/dist/types/components/my-accordion/my-accordion'; // <= refernces original repo incorrectly
export declare interface MyAccordion extends Components.MyAccordion {}
@ProxyCmp({inputs: ['accordionStyle', 'disabled', 'open', 'toggleClickArea']})
@Component({ selector: 'my-accordion', changeDetection: ChangeDetectionStrategy.OnPush, template: '<ng-content></ng-content>', inputs: ['accordionStyle', 'disabled', 'open', 'toggleClickArea'], outputs: ['myaccordiontoggle'] })
...
Versions:
Our valueAccessorConfigs
for the angularOutputTarget
looks like this:
[
{
elementSelectors: 'scu-checkbox',
event: 'scucheckboxchange',
targetAttr: 'value',
type: 'boolean',
},
{
elementSelectors: 'scu-switch',
event: 'scuswitchchange',
targetAttr: 'checked',
type: 'boolean',
}
]
Which produces the following boolean-value-accessor.ts
// boolean-value-accessor.ts
import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'scu-checkbox, scu-switch',
host: {
'(scucheckboxchange)': 'handleChangeEvent($event.target.value)'
'(scuswitchchange)': 'handleChangeEvent($event.target.checked)'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: BooleanValueAccessor,
multi: true
}
]
})
export class BooleanValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
}
writeValue(value: any) {
this.el.nativeElement.checked = this.lastValue = value == null ? false : value; // <= this will only work for scu-switch web component
}
}
The writeValue
method of the ValueAccessor is only being overwritten for targetAttr
of the scu-switch
web-component and won't work for scu-checkbox
web-component with the targetAttr
"value".
In this case the selectors should probably not be merged into one ValueAccessor Directive, but be two separate directives.
import { Config } from '@stencil/core';
import { angularOutputTarget, ValueAccessorConfig } from '@stencil/angular-output-target';
export const config: Config = { namespace: 'demo', outputTargets: [ angularOutputTarget({ componentCorePackage: 'component-library', directivesProxyFile: '../component-library-angular/src/directives/proxies.ts', valueAccessorConfigs: angularValueAccessorBindings, }), { type: 'dist', }, ], };
When creating the component definition in the proxies.ts
for components with events, the compiler generates an import that looks like this as mentioned in #86 and #95
import { Input as IInput } from '../component-library/dist/types/components/my-input/my-input';
the issue within the relative import seems to be fixed in the code that is currently in the master branch but another concern is the /dist/
in the generated import.
Since we don't intend to maintain the two projects as siblings. I'd like a way to generate this import path without the /dist/
, like this
import { Input as IInput } from 'component-library/types/components/my-input/my-input';
I have noticed several things when running the bootstrap command.
../../node_modules/.bin/jest
path. This can be fixed by added Jest as a dev dependency to the affected projects and changing ../../node_modules/.bin/jest
to just jest --passWithNoTests
. Needs to be changed per Lerna package. I did some investigation regarding common dev dependencies with Lerna and found the following (https://github.com/lerna/lerna#common-devdependencies): "Note that devDependencies providing "binary" executables that are used by npm scripts still need to be installed directly in each package where they're used."rm -rf
this breaks the build. Needs to be installed per Lerna package. Is the case in component-library-vue and component-library-react.component-library\C:\Users\jan.dewilde\projects\stencil-ds-output-targets\packages\example-project\component-library\src\components\my-button\my-button
. I fixed this by changing the way the import path is assembled so this generates component-library/dist/types/components/my-button/my-button
.The changed code is from:
const typePath = path.parse(path.join(componentCorePackage, cmpMeta.sourceFilePath.replace(path.join(rootDir, 'src'), distTypesDir)));
To:
const typePath = path.parse(path.join(componentCorePackage, path.join(cmpMeta.sourceFilePath, '').replace(path.join(rootDir, 'src'), distTypesDir)))
const importPath = path.join(typePath.dir, typePath.name).replace(/\\/g, "/");
I'm willing to open a Pull Request with changes, but it would be great if someone on a *nix system would like to validated the path fix, since I don't have a Mac anymore (and no WSL (yet)).
If I have a Stencil component with named slots and another normal component:
...
class CompSlot {
...
render() {
return (<Host>
<slot />
<slot name='a'/>
</Host>)
}
}
...
class CompContent {
...
render() {
return (<Host>
...
</Host>)
}
}
When using the wrapped React component like this:
...
<CompSlot>
Text
<CompContent
slot='a'
/>
</CompSlot>
Typescript throws the error slot
does not exist on CompSlot
.
If I silent the error with ts-ignore
, the rendered result is correct and the CompContent was put inside the correct slot:
...
<comp-slot>
Text
<comp-content></comp-content>
</comp-slot>
Thanks for the new Vue Output Target! I look forward in using it.
But I haven't been able to get it working properly with my Stencil component library testing repo: https://github.com/elwinvaneede/elwins-test-web-components. Unlike the React & Angular output targets.
The docs say:
There is an example component library package available on Github so that you can get started.`
But I can't find the stencil-ds-vue-template
repo (like https://github.com/ionic-team/stencil-ds-react-template & https://github.com/ionic-team/stencil-ds-angular-template), so I've had to guess the correct package.json
setup.
I've also found the example-project in this repo, which seem like new example templates, but those package.json
files seem to have unnecessary devDependencies like Rollup, and too many regular dependencies?
This is the one I currently use for my Vue output target: https://github.com/elwinvaneede/elwins-test-web-components-vue/blob/master/package.json.
But when using it in a Vue project created with the vue-cli
, my components don't properly render. Any styling and functionality is missing. Only the text I add in a slot is visible in my browser. I can inspect the component in Chrome (where any props I've defined are not rendered). I don't get any console errors, and the Vue DevTools also show the components (with the props I've defined).
Do you have ideas how to fix this, and are there any plans on adding a stencil-ds-vue-template
repo?
Thanks in advance.
When using react output generated components do not work in SSR (like Next.js) because generated components try to use document without safety checking if document exists.
This was already fixed by https://github.com/ionic-team/stencil-ds-output-targets/pull/40/files but it got removed in v.0.0.7.
Install Angular ^9 and import Angular-wrapped web-components created via the stencil.config.ts output target.
You'll see this error when importing the angular-wrapped component library.
Update 2
It appears that the problem is related to the Ivy compiler and symlinks. Using preserveSymlink: true
in the angular.json and angularCompiler options did nothing to help. Only creating a release to npm and installing from remote resolved the Ivy build issues for me.
I'd love if someone could shed some light on this.
Update
I did some more work following the ionic/ionic repo as an example, this is what I'm now stuck on:
ERROR Error: inject() must be called from an injection context
at injectInjectorOnly (core.js:899)
at ɵɵinject (core.js:915)
at Module.ɵɵdirectiveInject (core.js:20756)
at NodeInjectorFactory.XdsButton_Factory [as factory] (system-angular.js:97)
at getNodeInjectable (core.js:5598)
at instantiateAllDirectives (core.js:12645)
at createDirectivesInstances (core.js:11881)
at Module.ɵɵelementStart (core.js:20943)
at AppComponent_Template (app.component.html:6)
at executeTemplate (core.js:11841)
I'm using ng-packager 9, Angular 9, and I'm no longer using the ds-plugins - I'm just using the angular compiler option shipped in stencil 1.8.7. My tsconfig for angular is below.
{
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": true,
"flatModuleOutFile": "core.js",
"flatModuleId": "@system/angular",
"skipTemplateCodegen": true,
"fullTemplateTypeCheck": false,
"enableResourceInlining": true,
"enableIvy": false
},
"compilerOptions": {
"alwaysStrict": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"declaration": true,
"declarationDir": "dist",
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"lib": ["dom", "es2017"],
"module": "es2015",
"moduleResolution": "node",
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "build/es2015",
"pretty": true,
"removeComments": false,
"importHelpers": true,
"rootDir": "src",
"strictPropertyInitialization": false,
"target": "es2015",
"baseUrl": ".",
"paths": {
"@system/core": ["../core"]
}
},
"exclude": ["node_modules", "src/schematics"],
"files": ["src/index.ts"]
}
ERROR in getInternalNameOfClass() called on a non-ES5 class: expected XdsBadge to have an inner class declaration
With aot disabled, this warning is thrown in the terminal:
WARNING in Invalid constructor parameter decorator in /Users/jsmith582/dev/components/packages/angular/dist/fesm2015.js:
() => [
{ type: ChangeDetectorRef },
{ type: ElementRef },
{ type: NgZone }
]
"@stencil/angular-output-target": "^0.0.3"
"@stencil/core": "^1.16.3"
Upgrading angular-output-target from 0.0.2 to 0.0.3, the proxies.ts file now adds an import statement for each component, e.g.:
import { TabsLabelComponent as ITabsLabelComponent } from '../@meridian/web/dist/types/lib/components/tabs/mds-tabs-label';
The pathing is not right for my project however, I don't want the "../" at the start of the path. Expected output would be:
import { TabsLabelComponent as ITabsLabelComponent } from '@meridian/web/dist/types/lib/components/tabs/mds-tabs-label';
On compile, I get the following error due to the pathing:
libs/angular/src/lib/directives/proxies.ts:568:59 - error TS2307: Cannot find module '../@meridian/web/dist/types/lib/components/tabs/mds-tabs-label'.
568 import { TabsLabelComponent as ITabsLabelComponent } from '../@meridian/web/dist/types/lib/components/tabs/mds-tabs-label';
Here is my stencil.config.ts blurb for the Angular output target:
angularOutputTarget({
componentCorePackage: '@meridian/web',
directivesProxyFile: resolve(
__dirname,
'../angular/src/lib/directives/proxies.ts'
),
directivesUtilsFile: resolve(
__dirname,
'../angular/src/lib/directives/proxies-utils.ts'
),
directivesArrayFile: resolve(
__dirname,
'../angular/src/lib/directives/proxies-list.txt'
),
excludeComponents: [],
valueAccessorConfigs: [],
}),
Is there a way to prevent that relative pathing prefix to be added to the import?
I'm having a problem with @react-output-target - version 0.0.6 (latest)
, when I'm trying to build the package the tcs
I receive this throble:
src/react-component-lib/createOverlayComponent.tsx(15,17): error TS2742:
The inferred type of 'createOverlayComponent'
cannot be named without a reference to 'react-dom/node_modules/@types/react'.
This is likely not portable. A type annotation is necessary.
I saw that the commit 9d385ee fixed this problem and it was merged with the master branch, but it is not available in version 0.0.6 in NPM.
so, when will you guys publish a new version with these important updates?
Update create-react-component to follow same convention as ionic-react.
ComponentType should extend React.HTMLAttributes
Carrying over from #37
The library that I published is here and is being used as follows:
import { ManifoldInit } from "@manifoldco/manifold-init-react/dist/components";
const Home = () => (
<div className="container">
<ManifoldInit env="stage" clientId="my-client-id" />
The app renders the component correctly but I've seen some warnings in NextJS.
When I run my NextJS dev server, my terminal shows following error the first time I load the app:
(node:13529) UnhandledPromiseRejectionWarning: TypeError: head.querySelector is not a function
at Object.bootstrapLazy (/home/sam/taco-cloud-react/node_modules/@manifoldco/manifold-init/dist/cjs/index-1ab6c73d.js:825:44)
at /home/sam/taco-cloud-react/node_modules/@manifoldco/manifold-init/dist/cjs/loader.cjs.js:8:16
(node:13529) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:13529) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I don't know if that's because NextJS is SSR and there's some code that shouldn't be running on the server side, but I tried rendering the component only when process.browser
is defined and the error didn't go away, so it's hard to tell.
Again, the component renders fine on the page, but perhaps there are some places where SSR should be taken into account.
createComponent.txt's ReactComponent
class includes a constructor that does nothing:
In a create-react-app project, ESLint complains about this:
Compiled with warnings.
./src/react-component-lib/createComponent.tsx
Line 39:5: Useless constructor @typescript-eslint/no-useless-constructor
The outputs from the angular proxies should inherit the events from the stencil component class.
The current implementation adds the outputs as the properties of the angular class.
import { Components } from 'component-library'
export declare interface MyButton extends Components.MyButton {}
@ProxyCmp({ inputs: ["buttonType"] })
@Component({
selector: "my-button",
changeDetection: ChangeDetectionStrategy.OnPush,
template: "<ng-content></ng-content>",
inputs: ["buttonType"],
})
export class MyButton {
ionFocus!: EventEmitter<CustomEvent>;
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ["ionFocus"]);
}
}
I believe they should be inherited from the stencil class like this to inherit types and docs in similar fashion to how inputs are added.
import { Components } from 'component-library'
++ import { Button as IButton } from 'component-library/dist/types/components/my-button/my-button'
++ export declare interface MyButton extends Required<Pick<IButton, 'ionFocus'>> {}
export declare interface MyButton extends Components.MyButton {}
@ProxyCmp({ inputs: ["buttonType"] })
@Component({
selector: "my-button",
changeDetection: ChangeDetectionStrategy.OnPush,
template: "<ng-content></ng-content>",
inputs: ["buttonType"],
++ outputs: ["ionFocus"]
})
export class MyButton {
-- ionFocus!: EventEmitter<CustomEvent>;
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ["ionFocus"]);
}
}
Hello,
i've been using react-output-target
following this setup and upgrading to latest version i've got this issue.
react-component-lib/interfaces.ts
has this import so, does it mean the React component lib requires @stencil/core as a devDependency now?
Thanks!
Hello,
After upgrading @stencil/react-output-target from 0.0.6 to 0.0.7 my stencil components are failing silently and failing to render in React.
Inspecting createComponent.tsx it seems this function has changed quite abit. Please help me by providing some guidance on this issue, thanks much for your time.
Expected: After upgrade from 0.0.6 to 0.0.7 stencil components render in React.
Actual: After upgrade to 0.0.7, stencil components fail to render with no error messages.
I am having an issue where a proxied component is not accepting input bindings. I am required to use attribute bindings to pass data:
// This does NOT WORK and the [value] gets an empty string (nothing)
<my-textarea *ngFor="let value of values" [value]="value"></my-textarea>
// This DOES work and the [value] gets the expected data
<my-textarea *ngFor="let value of values" [attr.value]="value"></my-textarea>
I noticed it works as expected when using an ionic component:
// Works
<ion-input *ngFor="let color of colors" [value]="color"></ion-input>
I cannot see the difference between what Ionic does and what this plugin does. (or even what the built-in Stencil angular output target does. Does anyone have some insight?
Thanks!
Our component library uses stencil-state-tunnel. When I use the react-output-target to build a React component library, the first component that gets defined in components.ts
looks like this:
export const ContextConsumer = createReactComponent<JSX.ContextConsumer, HTMLContextConsumerElement>('context-consumer');
TypeScript is highlighting two errors here:
Namespace 'LocalJSX' has no exported member 'ContextConsumer'
Cannot find name 'HTMLContextConsumerElement'
And indeed, when I use 'Go to Definition', it takes me to the dist/types/components.d.ts
file, where the word Context
does not appear at all.
Hello folks
I have this code from a React project:
<IonPhaser ref={(ref) => console.log(ref)} game={game} initialize={initialize} />
But the console.log never runs, therefore useRef of React is not working:
import React, { useRef } from 'react'
export default function App () {
const gameRef = useRef<HTMLIonPhaserElement>(null)
const debug = () => {
console.log('Reference', gameRef.current) // Always is null
}
return (
<>
<IonPhaser ref={gameRef} game={game} initialize={initialize} />
<button onClick={debug}>Debug</button>
</>
)
}
This is the project: https://github.com/proyecto26/ion-phaser
Thanks in advance!
Regards
When using react output generated components do not work in ssr (like Next.js) because generated component try to use document without safety checking if document exists.
Since the events are added to the outputs array - there's no need to create an observable listener anymore to bubble the events. Instead - to keep the outputs array and the types, fromEvent
can be replaced with an empty EventEmitter
in the angular proxy utils.
export const proxyOutputs = (instance: any, el: any, events: string[]) => {
-- events.forEach((eventName) => (instance[eventName] = fromEvent(el, eventName)));
++ events.forEach((eventName) => (instance[eventName] = new EventEmitter()));
};
I will document my steps so to best describe the use case.
npm install
npm run bootstrap
npm run build
Next I run npm pack
on component-library and component-library-angular so I can use these packages in an Angular 8 application I locally created.
Next I import the ComponentLibraryModule
in app.module.ts
, add it to imports and run ng serve
.
import { ComponentLibraryModule } from 'component-library-angular';
@NgModule({
imports: [
ComponentLibraryModule
]
})
ERROR in node_modules/component-library/dist/types/components/my-range/my-range.d.ts:113:17 - error TS1086: An accessor cannot be declared in an ambient context.
113 private get valA();
~~~~
node_modules/component-library/dist/types/components/my-range/my-range.d.ts:114:17 - error TS1086: An accessor cannot be declared in an ambient context.
114 private get valB();
~~~~
node_modules/component-library/dist/types/components/my-range/my-range.d.ts:115:17 - error TS1086: An accessor cannot be declared in an ambient context.
115 private get ratioLower();
~~~~~~~~~~
node_modules/component-library/dist/types/components/my-range/my-range.d.ts:116:17 - error TS1086: An accessor cannot be declared in an ambient context.
116 private get ratioUpper();
First of all, thank you so much for open sourcing this. This is really useful addition to our team’s toolchain.
One issue we faced while implementing this is that it doesn’t seem to be possible to customize the import path in the generated proxiesFile. So in our case, the generated import line in proxiesFile looks like this:
import { defineCustomElements, applyPolyfills } from "@duetds/components/loader"
But it should actually be:
import { defineCustomElements, applyPolyfills } from "@duetds/components/lib/loader"
Is there a way to customize this somehow or specify the import path in config?
This is the output TS
/* eslint-disable */
/* tslint:disable */
/* auto-generated react proxies */
import { createReactComponent } from './react-component-lib';
import { JSX } from 'tinacms-ui';
import { defineCustomElements, applyPolyfills } from 'tinacms-ui/loader';
applyPolyfills().then(() => defineCustomElements());
export const MyComponent = /*@__PURE__*/createReactComponent<JSX.MyComponent, HTMLMyComponentElement>('my-component');
This code will not compile
It must be passed defineCustomElement(window)
When components rootDir
(e.g. core) and componentCorePackage
(e.g. @ionic/core) have different names the current interface import generates:
import { Checkbox as ICheckbox } from '../@ionic/core/dist/types/components/my-checkbox/my-checkbox';
Adjusting the relative import to the rootDir
will accommodate all cases and generate the right path.
- const typePath = path.relative(componentCorePackage, cmpMeta.sourceFilePath).replace('../src', path.join(componentCorePackage, distTypesDir)).replace('.tsx', '');
+ const typePath = path.parse(path.join(componentCorePackage, cmpMeta.sourceFilePath.replace(path.join(rootDir, 'src'), distTypesDir)));
- ? `import { ${cmpMeta.componentClassName} as I${cmpMeta.componentClassName} } from '${typePath}';`
+ ? `import { ${cmpMeta.componentClassName} as I${cmpMeta.componentClassName} } from '${path.join(typePath.dir, typePath.name)}';`
The following errors can be seen and detected by typescript on react-component-lib/createComponent.tsx
when building @Stencil library, therefore npm run build
fail when trying to compile the react library:
I believe the fix is already in the master branch, is there some ETA about when a @stencil/[email protected]
will come out?
Thank you!
I have configured my react output target to live in ./dist/react as follows:
reactOutputTarget({
proxiesFile: './dist/react/index.ts',
}),
When I run stencil build
once, the proxies file and react-component-lib dir get created in ./dist/react. However, if I run stencil build
again the ./dist/react dir is being removed entirely.
So in order to rebuild react components I need to run stencil build
twice. Desired behavior would be to have the output target created with latest changes every time I run stencil build
When using componentes generated with this plugin in Next.js, server page load throw a TypeError: head.querySelector is not a function because this plugin auto initialize CustomElement even if there is no document or window element.
Related to ionic-team/stencil#2374
I very easily found out that this project does not produce usable code with #29
This could be prevented by having a simple CI script that builds a stencil project and then tries to build the autogenerated React code.
Stencil version:
@stencil/core@<version>
I'm submitting a:
[ ] bug report
[ x ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/
Add official svelte support!!
I created a React set of components using https://github.com/ionic-team/stencil-ds-react-template and @stencil/react-output-target
and the stencil project I'm using is largely based on the default config.
We use Renovate in our project which bumps the versions of packages automatically and our CI pipeline fails at the build stage due to the TS issue
When updating @stencil/react-output-target
from 0.0.4
-> 0.0.6
Build then causes an error in the createComponent
script:
src/react-component-lib/createComponent.tsx:32:24 - error TS2345: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'.
Type 'null' is not assignable to type 'HTMLElement'.
32 attachEventProps(node, this.props, prevProps);
It looks like one of the following is true:
node
is just HTMLElement
)Hoping it's a simple fix - It currently means we can't update.
In the 'react' package (based on the template)
{
"devDependencies": {
"@types/react": "16.9.35",
"@types/react-dom": "16.9.8",
"react": "16.13.1",
"react-dom": "16.13.1",
"typescript": "3.8.3"
}
}
In the 'core' package
{
"devDependencies": {
"@babel/core": "7.9.6",
"@babel/preset-env": "7.9.6",
"@babel/preset-typescript": "7.9.0",
"@stencil/angular-output-target": "0.0.2",
"@stencil/core": "1.12.7",
"@stencil/eslint-plugin": "0.3.1",
"@stencil/postcss": "1.0.1",
"@stencil/react-output-target": "0.0.6",
"@storybook/addon-info": "5.3.18",
"@storybook/addon-knobs": "5.3.18",
"@storybook/addon-notes": "5.3.18",
"@storybook/addon-viewport": "5.3.18",
"@storybook/html": "5.3.18",
"@types/jest": "25.2.1",
"@types/puppeteer": "2.0.1",
"@types/storybook__addon-knobs": "5.2.1",
"@types/storybook__html": "5.2.1",
"@typescript-eslint/eslint-plugin": "2.31.0",
"@typescript-eslint/parser": "2.31.0",
"awesome-typescript-loader": "5.2.1",
"babel-loader": "8.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"case": "1.6.3",
"cssnano": "4.1.10",
"eslint": "6.8.0",
"eslint-config-airbnb-base": "14.1.0",
"eslint-config-airbnb-typescript": "7.2.1",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.19.0",
"eslint-plugin-react-hooks": "4.0.0",
"glob": "7.1.6",
"jest": "24.9.0",
"jest-cli": "24.9.0",
"npm-run-all": "4.1.5",
"postcss-calc": "7.0.2",
"postcss-custom-properties": "9.1.1",
"postcss-import": "12.0.1",
"postcss-preset-env": "6.7.0",
"puppeteer": "3.0.4",
"rimraf": "3.0.2",
"storybook": "5.3.18",
"typescript": "3.8.3",
"webpack": "4.43.0",
"workbox-build": "5.1.3"
}
}
Having just upgraded to 0.0.7 of the React output target, I got this error in my consuming React project:
/path/to/react-app/src/react-component-lib/createComponent.tsx
TypeScript error in /path/to/react-app/src/react-component-lib/createComponent.tsx(10,36):
Cannot find module '@stencil/core/internal/stencil-public-runtime' or its corresponding type declarations. TS2307
It looks like a runtime dependency on @stencil/core has been introduced into the build output of react-output-target. That would mean that every React app that consumes React proxies would need to add Stencil to its package.json, which I do not believe is how react-output-target is intended to work (and wasn't the case for 0.0.6).
The dependency was introduced by 1b0a49c#diff-0c5775a0b0c1a17c5b8e386f105c1683R10.
In 0.0.6
the output included defineCustomElements
by default. As of 0.0.7
this is no longer the case.
I notice new config options were introduced:
includeDefineCustomElements
includePolyfills
Looking at the code, it seems these should default to true
but for whatever reason, this is not happening.
My suspicion is that whilst the logic in normalizeOutputTarget
is correct, the result of that function is not used anywhere. If you look at the generator
method, it is referencing to the closed over outputTarget rather than the normalised result.
Of course I can workaround this by explicitly setting the options, but it took me some time to work out why things suddenly broke, and fixing this may save someone else the effort :)
is there a way to create the react-component-library within my existing stencil-app rather than creating another repository?
Thanks!
Thank you very much for this incredible work! Stencil is really awesome and allows us to unify our codebase for all projects!
But I noticed that generated React component can't have data attributes.
I don't know, maybe this is already known issue and there is some plan or roadmap to fix this.
Could you take a look on my PR, I believe it's able to fix this.
Thank you 🙏
Is there any idea?
related issue: https://youtrack.jetbrains.com/issue/WEB-36114
I am trying to use this library with Angular 10.
I get the following error when I try to build the Angular project:
src/directives/generated/value-accessor.ts:4:14 - error NG2007: Class is using Angular features but is not decorated. Please add an explicit Angular decorator.
4 export class ValueAccessor implements ControlValueAccessor {
This new behaviour seems to have been introduced by angular/angular#36921.
Manually appending @Directive()
to ValueAccessor
fixes the issue:
import {Directive, ElementRef, HostListener} from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
@Directive()
export class ValueAccessor implements ControlValueAccessor {
// ...
I wanted to create a pull request for that, but @Directive
changed between Angular 9 and Angular 10.
In Angular 9, @Directive()
requires a selector attribute, while in Angular 10, you can pass it without any option.
So maybe Stencil needs to be aware of the Angular version effectively used?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.