Open kimamil opened 1 year ago
Finally solved the issue. Maybe there's a better way to solve this, feel free to add it here:
The issue seems to be related to type definitions. In a typescript vue project, there's the file 'src/shims-vue.d.ts' declaring *.vue modules as
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
using the JsonFormsRegistryEntry inside the custom renderer component like
...
export default controlRenderer;
const entry: JsonFormsRendererRegistryEntry = {
renderer: controlRenderer,
tester: rankWith(3, schemaTypeIs("array")),
};
export { entry };
</script>
conflicts with this module definition, as the definition has no 'entry' element.
Solution I extracted the registry entries to where I set my renderers, and now the formControls get rendered also in production environment.
Source of the issue (best guess) I am not too experienced with typescript, but I think what is missing is the correct controlRenderer type definition within my vue application (since I have only modified html parts in the template, this should still be the same type). Vue thinks, that the controller is a "simple" vue component and uses the module declaration in 'shims-vue.d.ts' which doesn't match the controllerRenderer type.
Hi @kimamil, thanks for the detailed report. I ran into exact the same issue. Wrote a bunch of custom renderer to use instead of the vanilla renderer. Everything is working nicely in development. In production mode only the more or less empty HTML is rendered.
Breaking my head here a little bit since a day. I also ended up with checking the 'src/shims-vue.d.ts' and config but was not able to solve it.
Could you please help me understanding your solution a bit? 'I extracted the registry entries to where I set my renderers, and now the formControls get rendered also in production environment.'
From what I understand I could use JsonFormsRegistryEntry where I set my renderers and add the Tester part there. I just did not get it to work. It seams I missing or misunderstood something or my brain is just gone. A hint in the right direction would be highly appreciated.
Cheers!
Hi @mwessendorf
Sure! So the issue for me was, that I declared the tester function within my SFC (Single File Component) as it is done in the vanilla-renderers. This declares an export called „entry“. When assembling the registry in a different part of my code, I imported it via ‘‘‘import { entry as CustomRendererEntry} from CustomRenderer.vue‘‘‘.
This doesn‘t work since the shims declaration for SFCs has no export „entry“ declared. Therefore, in production mode, the entry object is not exported (don‘t ask me, why it‘s working in other modes).
To work around this, I needed to declare the tester function in a part of my app where I control the object declaration. I personally ended up defining them directly before assembling the registry without any export/import.
I am sure there‘s a possibility to extend the SFC type declaration with an optional ‚entry‘ export. I just couldn‘t get my head around it under the time pressure.
Let me know if this helped clarifying my approach. If you need more support, could you please try to explain your project folder structure and where you declare the renderer, the testing function and the registry - thanks!
This doesn‘t work since the shims declaration for SFCs has no export „entry“ declared. Therefore, in production mode, the entry object is not exported (don‘t ask me, why it‘s working in other modes).
Can you explain how you came to this conclusion? I would have expected the shim to only have an influence on Typescript type resolution and not on the actual export mechanism.
Many thanks @kimamil, will dive into that again and come back with (hopefully) results.
This doesn‘t work since the shims declaration for SFCs has no export „entry“ declared. Therefore, in production mode, the entry object is not exported (don‘t ask me, why it‘s working in other modes).
Can you explain how you came to this conclusion? I would have expected the shim to only have an influence on Typescript type resolution and not on the actual export mechanism.
Hi @sdirix - It’s quite possible that I am wrong since my knowledge on typescript is very limited.
My understanding is that when Vue 3 is setup with typescript and the options API this shims file is created in the project source: https://github.com/Code-Pop/Real-World-Vue-3-TypeScript/blob/75977c69c06e4c84d67f0709847b107687e935ca/src/shims-vue.d.ts
As far as I can tell, it declares an interface for all .vue modules. My custom renderer, copied from vanilla-renderers matches the .vue selector.
As you can see, it only declares a default export for a component. Naturally, when creating a custom renderer using additional exports, at some point linting throws errors.
I tried to modify this shims file adding an optional named „entry“ export but couldn‘t get it to work properly.
I hope this helps. If not I am happy to recreate the situation and give you more concrete feedback on the errors etc.
=== UPDATE
Here's a screenshot that shows my folder structure and the file where I import my custom renderer. When I use the entry export copied from vanilla-renderers, this is what I get:
And when I change the shims-vue.d.ts to:
import { JsonFormsRendererRegistryEntry } from "@jsonforms/core";
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
const entry: JsonFormsRendererRegistryEntry
export {entry}
}
I get more typescript type declaration errors ...
Had today some time to dive in again. Tried some ideas but ended up with the following solution which I guess is more or less the same you @kimamil have? Working example for String renderer (have some more in the project):
import StringControlRenderer from "components/jsonforms/StringControlRenderer.vue";
const stringRenderer = buildRendererRegistryEntry(StringControlRenderer, isStringControl)
const renderers = Object.freeze([ ...vanillaRenderers, stringRenderer ])
And here the function from another file (js and ts are both used in the project):
import { JsonFormsRendererRegistryEntry, rankWith, Tester} from "@jsonforms/core";
export function buildRendererRegistryEntry(testRenderer: any, controlType: Tester) {
const entry: JsonFormsRendererRegistryEntry = {
renderer: testRenderer,
tester: rankWith(3, controlType )
};
return entry
}
If there is any better solution I happy to follow up on it. At least happy to have now a working solution not only for dev env =) Many thanks to @kimamil again. And for sure also thanks to you guys @sdirix for all the efforts.
Describe the bug
I use the same code base locally and switch NODE_ENV between 'development' and 'production' to test different environments.
When I use the vue-vanilla renderers, my form looks the same in both environments. When I use my custom ArrayListRenderer, it is only rendered when NODE_ENV is not "production" (it can be "development" or be unset).
HTML rendered in "development" mode:
HTML rendered in "production" mode:
There's no JS error, rendering in "production" mode.
Custom ArrayListRenderer:
Expected behavior
I would expect the control to render with NODE_ENV = "production"
Steps to reproduce the issue
to reproduce, use the vue-vanilla example project and recreate my custom renderer.
register it as follows:
use the following schema:
and this UiSchema:
and this example data:
Screenshots
In which browser are you experiencing the issue?
Version 108.0.5359.124 (Offizieller Build) (arm64)
Which Version of JSON Forms are you using?
v3.0.0
Framework
Vue 3
RendererSet
Vanilla
Additional context
No response