Migrating from v1 -> v2
Hi there! I have a pretty big project that is in OneJS v1, and you might've seen my posts recently about various issues I've been grappling with it, as well as some perf concerns. I'd like to see if I can migrate it to v2, but that's been a pretty thorny task that has come with its own set of problems. So I'm creating this forum thread to both ask for help along the way, and also document exactly what has changed for me.
Some context from me:
* Even with v1, I was using a custom esbuild setup to create a minified JS file to use
* I use hookstate as my main state management system. This requires a full preact-compat, so I have a custom version vendored in.
So far, in attempting to work with v2, I have
1. interop between my existing C# and TS seem fine, and I appreciate the new generated typedefs
2. DOTween also seems to include fine without errors.
3. It builds
Nothing shows up ingame at the moment though! There's still a whole slew of errors to work through first.
57 Replies
Open Questions So Far
1. OneJS's
preact
(or its types?) seems to be incomplete compared to what we had in v1. The most prominent is the import { Style } from "preact/jsx"
definition, which was a part of Scriptlib. Is that available in v2? (Other missing definitions include Fragment
and a lot of the pieces of JSXInternal
.
2. Do the onejs/comps
components still exist? (I can probably vendor them in if needed, but was curious)
3. Typescript complains if we reach into a C# class and use nested variables or functions; is there something I'm missing there? I generated the type defs from the ScriptEngine object.
4. I asked 5 months ago (?!) about how to handle actions, and got https://discord.com/channels/971959898655051806/971963260704260146/1231847737620697088 as an answer. Is this still the case?1. The def for Fragment was rencently added. But yeah, to get full npm and esbuild workflow working, I had to manually pull in and check every single declaration for onejs-preact and had to leave out some typings that had conflicts at the time. Feel free to PR https://github.com/DragonGround/onejs-preact to get missing typings in.
2. It's been on my mind, but I haven't gotten around to these yet for V2.
3. Nested classes? Those can be tricky when translating them from C# to TS. Half of time, they'll require some manual adjustment, especially when combined with explicit interfaces.
4. Reading over your code again, I think you might have something else that's triggering the delegate bridge error. Do you still get the error if your event is Action<float> instead of Action<bool>? Because it just seem weird that Action<float> works fine and Action<bool> doesn't. The former is being used in both the Ul Meter tutorial and the fortnite UI sample. I didn't need to explicitly declare
UsingAction<float>
for these.
oh for Style
, you can use Partial<CS.OneJS.Dom.DomStyle>
in most cases
I will start migrating the headless comps from v1 to v2 https://github.com/Singtaa/onejs-comps Just a slider right now (needed that one for something Yesterday)Is there an equivalent for
onEngineReload
for v2? I used that a lot to remove C# bindings in v1 and it's saying it doesn't exist now.
In v1, you could use p, h1, etc. tags that don't seem to exist in v2. Those can easily be substituted with label
or textElement
. More importantly, I used <span> tags in v1 -- how would I go about recreating those?
Are there any docs regarding how to handle Lists, Arrays, and Dictionaries in v2? In v1, I think things generally auto-converted to JS objects, and I was able to iterate through, say, arrays and dicts using for (... of ...)
loops. Now Typescript is producing errors when I do that.Yes, you can use
onejs.subscribe
(which is also in V1; I need to document this). See here for more info: https://discord.com/channels/971959898655051806/971963260704260146/1253911013128929311
technically, they also don't exist in V1, and will default to plain VisualElement. I think you are only experiencing typing issues right? You can just augment it like this:
One more question! How do we generate Unity types so that they have their fields populated? My vector3 typings look like
so doing something as simple as
vector.x
produces a type errorPuerts has some samples in regard to these. This is the one I use the most for reference: https://github.com/chexiongsheng/puerts_unity_demo/blob/master/projects/0_Basic_Demo/Assets/Examples/05_Typescript/Resources/QuickStart.mjs
You need to include your types explicitly either in DTSGen if you are doing it programmatically, or the DTSGenerator component on ScriptEngine.
Yep, I've been trying to include my types on DTSGenerator, and can successfully do so with my assemblies. However, Vector3 is in the UnityEngine namespace, and when I try to include that, it doesn't seem to populate.
hmm Vector3 is in the UnityEngine.CoreModule assembly, so you need to make sure that's included. But Vector3 is already included by
onejs-core
, you shouldn't need to generate it againI guess something is generating an empty Vector3 definition and that's overwriting VSCode's autocomplete from the one in
onejs-core
could be. Then you try to blacklist the type, namespace, or assembly in your own generation.
Blacklisting
Vector3
does not appear to do anything to type generation 🤔
Looks like checking 'strict namespaces and assemblies' did the trick, thoughCool, yeah I thin kthe former only blacklist from the starting set of types, but doesn't prevent supporting ones from being generated
I think I've squashed most of the issues, one more type error I'm seeing is
Property 'PreventDefault' does not exist on type 'NavigationMoveEvent'.
I think I saw that there was an upgrade to onejs-core to fix something about events, but this is happening with the latest npm versionI'm not sure if it's because it's obsolete:
(just seeing this now)
Uhhh, hm. Which version of UI Toolkit / Unity is that for? PreventDefault is definitely not obsolete in 2022.3, and doesn't look quite like what you shared there either.
I'll just add it to the type definition for now.
ah yeah, it was deprecated in 2023.2 onwards https://docs.unity3d.com/2023.2/Documentation/ScriptReference/UIElements.EventBase.PreventDefault.html
ok, it now builds in esbuild, but the C# <> JS array thing might be a thornier problem. I have a C# object that I pass into my JS, and in v1 it contained an array that I do JS-array manipulations on with an external library (spread operator...) before calling C# functions on the original object. In v2, that kind of breaks apart.
Is there any way to have a C# object have a member-variable array be represented as a JS array in v2, while still being able to call functions from C#? Trying to do something like
caused a
Error: c# exception:Non-static method requires a target
complaint when AdvanceLine
is called from the wrapper object.
Ok, worked around that by forking the library and creating JS arrays to use in there 😅
One more error! I'm still having Action
issues, though it looks like basic actions are working fine. But I'm still seeing the issue for Error: c# exception:can not find delegate bridge for System.Action<bool, string>
, so I'll first see if the answer I got 5 months ago helps with that.
Hrm. that didn't seem to have changed the error message.
I guess I can also work around this, I probably don't need both a bool and a string.
...or not? Doing that caused me to get Exception: <unknow>:-1: Error: c# exception:can not find delegate bridge for System.Action<bool>, Please use JsEnv.UsingAction() Or JsEnv.UsingFunc() following the FAQ.
issues from somewhere elseyou can see if adding
_jsEnv.UsingAction<bool, string>()
directly in ScriptEngine's Init() works.
do it right after _jsEnv = new JsEnv();
lineOk, I had to add all the permutations of actions I'm using but that error has now gone away.
There are no more errors logging in console, but no UI is showing up.
So adding them with
OnReload
had no effect? Only worked inside the Init() method?Yes, they worked in
Init()
OnReload
didn't seem to help, unfortunately.
(well, 'worked'. I'm not sure why nothing is being drawn.)Okay I added a PreInit event that you can use for this.
But I've no idea about your UI situation. probably need some code
Have you seen this warning before? hello world worked and when I live reloaded to my UI I got this:
what's the version on your
onejs-preact
?onejs-preact is 0.3.22
onejs-core is 0.3.26
oh okay try updating onejs-core to 0.3.28
the version on the C# side was a little out of date and didn't have contains yet. I'm upgrading that now.
ok, stuck on another error but it is 3AM now so I think I'll pick this up later.
It looks like
eventHandler
is null on this line https://github.com/Singtaa/onejs-preact/blob/dc4c534e1d9305929313141c526021abad906116/diff/props.js#L185 but I haven't dug into why that could happenGitHub
onejs-preact/diff/props.js at dc4c534e1d9305929313141c526021abad906...
Preact for OneJS. Contribute to Singtaa/onejs-preact development by creating an account on GitHub.
If you install
source-map-support
from npm and put the following at the start of your entry file, you will have better stacktraces.
looks like a bug. Do you know which event it's processing at that time?would this only work with node backend?
(esbuild is complaining about platform: node, which I can easily fix)
oh yes, other backends will require a bit more effort. but nodejs will work out-of-the-box
Hmmmmm, no dice on that one. Even with node.js backend, it complains that require is not defined.
It looks like we're losing the
_attached
variable every time I navigate to something. Also, I figured out why nothing was drawing, I think: somehow the UI lost practically all of the styles I was setting, and the root element was being set to height 0. Transitions and fades also caused errors and aren't working.
(This is using the built-in style prop for the most part)See if you can reproduce some of this in a minimal code sample, especially for the "navigation" you were referring to. I'm also west coast, gonna hit the sack soon as well 🙂
Still debugging -- a minimal repro attempt did not have the same problems, so I'm diagnosing that now. I'm thinking it's in one of the following areas, since these are not part of the current minimal:
* images - I confirmed resource loading worked with fonts, but none of my images have shown up properly in the actual game
* transitions - I used the
Transition
component extensively from the old onejs/comps
, which hasn't been formally ported to v2.
* C# Interop - haven't made anything that works with this yet
Things that are probably not the issue
* Hookstate - this worked in the minimal repro (despite being the bane of my existence in previous debugging sessions)
* absolute positioning - worked in minimal repro
As an aside, @Singtaa , the PreInit hook right now is not particularly helpful because there isn't an easy way to listen to that hook before Init
is called. ScriptEngine OnEnable
might run before another component's Awake
-- I guess we can play with component initialization order to try to fix that, but for the time being I just have the Action handlers inside of Init.Maybe I should rename it. It's meant for just setting up the JsEnv after its creation
Slowly getting stuff to show up ingame! The big 'nothing is rendering' error had the same root cause as https://discord.com/channels/971959898655051806/971963260704260146/1278838350748581955 -- nothing much I can do there except patch in styles that I was missing, because this has now been logged as an official Unity crash bug (that still repros all the way to Unity 6).
However, a lot of my styles are still missing. I'll start making a running log of the ones that didn't seem to make the transition via the
style
prop:
* backgroundColor
as an rgba()
string produced pure white all the time. I had to switch it to a Unity Color
object.
* unitySlice
styles (unitySliceTop
, unitySliceBottom
, etc.) appear to do nothing
* transition
styles appear to be broken
Images are confirmed to be working, but they look wonky because of the unity slice issues
@Singtaa I have a minimal repro for some of the issues stated now, which is in the same repository as usual on the latest main: https://github.com/a-morphous/onejs-hookstate-sample
Issues that you can see with this one:
* unitySlice
styles don't populate
* Whenever you click or hover on the special button, the _attached
error shows up.
There's a note in the FadeTransition
component where you can uncomment a version of the component that has no transition; doing that will fix the _attached
error on hover, but it'll still exist on click.
Unity slice issues can be worked around with emo. This worked:
The _attached issue is still an issue, and I'm sure I'll find more as I keep porting.
It looks like _attached may be an issue any time there is any transition. This is not captured in the minimal repro, but that error also shows up when I play the animation to translate the game title on my title screen too.1) the colors are now directly parsed with
ColorUtility.TryParseHtmlString
to conform with the rest of UIElements. In OneJS V1, all the styles were processed on the JS side, so there were more flexibility. In V1, all the style processors were moved to C# for performance reasons.
2) something weird is going on with the slice values. I'll need a closer look.
3) There were some transition
bugs (only affected the style
prop. Tailwind and uss worked fine). Fixed in latest commits.
Thx for testing all these btw. much appreciated! let me know if you can get the _attached
issue reliably reproduced. It does sound like a bugThe
_attached
issue is reliably reproduced on the example I sent, if you run it and click the button it reproduces. I updated that repository to use v2 and show this issue.
I've been able to reproduce it on most transition-y things, but I haven't updated to the latest commits.There's a perhaps-more-intuitive stack trace of the
_attached
issue when you comment out the FadeTransition
and click on the button:I also don't think the system in v2 right now likes
setTimeout
Even more minimal example; this one can be copied and pasted to a fresh project I think
Issues this has:
* _attached
error when interacting with the button (I think it's the event handlers)
* transition
doesn't work (this is true even when I upgraded OneJS)Okay I think I found the culprit. There's this code in original preact code:
I'll just remove this block then. Should be updated in latest
onejs-preact
Yep, that fixes it for buttons. There's apparently multiple
_attached
errors, and I've seen more of them on other components. I'll track down a repro for those.
(I still don't see any transitions, do you have any working examples with them?)sure, here was my test code:
You can hover over the last element to see the transition
Ok, it seems like another case where the style prop isn't working, but it does work on This doesn't appear to be consistent. It works in some components to move them to
Emo seems to be consistently working as long as you never try to set transition properties through the
emo
. the minimal example from before does not transition properly, but this does
emo
, and not others.style
prop. I'm assuming that style
is just broken for this. Tailwind also seems to work.Also, a somewehat silly but also pretty serious error: items in a list do not always appear to be drawn in the order they are meant to be in the list
this does not appear to be entirely deterministic, nor are there any errors that show up in console. Sometimes things are just drawn out of order.
This seems to happen the most often when any kind of redrawing happens; the entire list rendering for the first time, fading objects in and out in the list, etc.
it seems to always be the second object in the list being moved to the very end
Okay I solved the unitySlice issue. Preact is appending raw numbers with "px" suffix for styling values. I just made the fix in latest commit (C#)
are you still having issue with transition not working with the
style
prop?I never got transition working with the
style
prop. Instead I manually converted them all to emo
classes.
I have resolved (tentatively) the remaining _attach
issues. They were firing on transitionrun
and transitionend
events when using the Transition
object from onejs/comps
v1; I think setting style on ref.current
and having transition event listeners at the same time was probably related? I ended up rewriting the Transition
effect to not use refs at all, and that fixed it.
As of now besides some graphical glitches, the only blocking issue is the list ordering error.For transitions with style prop, I have it working like this. I think if you update
onejs-preact
you may also fix some prior issues (with transitions)
for ordering issue, can you reliably repro?
does using key={}
prop help in any way?It's reliably reproing ingame with the title screen. Key does not help. I'm trying to create a minimal repro, but it's so far not reproing in the minimal. I'll keep investigating.
I have a minimal repro
It has to do with changing a style with a timeout.
if you
render(<App />, document.body)
Button 2
will end up all the way at the end of the listOkay I think I fixed it!
Dom.insertBefore
did not properly take care of the case when both a and b are the same element. Phew, that's tough one to crackOk, the UI works in the editor now!
...but it breaks in build. Probably because DOTween isn't linking up correctly in Puerts? I have DOTween set as an Assembly in the ScriptEngine; is there more I need to do here?
I fixed this by adding these lines to
index.tsx
:
(The visualelementDOTweenExtensions are custom code from me)Great! Hopefully things will be much snappier from now on. To me, even though puerts is a bit more rigid than Jint, it just feels good knowing you are getting the theoretically best performance in terms of interop.
Ok, not blocking but one more issue: there are certain transitions between components that cause random textelement items to be inserted into the DOM - is there any code in OneJS that could account for that? I don't use textelement elements at all in my code.
They're a nuisance, in that they add extra height and padding to the UI unnecessarily, but I guess they're not really a problem (since I don't use them I can hide all of them)? More a curiosity.
So in regard to the TextNode, OneJS only provide this one function
Document.createTextNode()
:
Which gets called by Preact in diffElementNodes()
:
Other than that, I've got no ideas. Will need to see some of your code to go on