Open refi64 opened 5 years ago
Just sharing a thought (probably infeasible)
How about a heavy use of code generation packages like 'build', 'source_gen' and 'analyzer' ?
component.dart
class MouseLogic {
int x = 0;
int y = 0;
MouseLogic() {
// some magic
}
}
class Component {
void setup() {
final mousePos = MouseLogic();
final other = OtherLogic();
return {
x: mousePos.x,
y: mousePos.y,
z: other
};
}
component.vue.dart
.class _State {
int x;
int y;
Other z;
_State(this.x, this.y, this.z);
}
class Component extends Vue<_State> {
setup() {
final mousePos = MouseLogic();
final other = OtherLogic();
return _State(mousePose.x, mousePose.y, other);
}
}
As long as the library user is educated to write component.dart
but import component.vue.dart
, this approach is doable and very flexible. However, the implementation of this builder might be very costly or even impossible since user-written 'setup' function might be complex enough to make static analysis impossible.
I've been working on a dart port of our javascript/typescript project, and applied this approach. Despite the difficulty of builder implementation, it makes it possible to both reducing the amount of code user needs to write and keeping the public API as consistence with the original one as possible. The migration is still WIP so I cannot tell if there's any pitfall.
@Nandiin VueDart already used compile-time tweaking, the main issue with that approach is that, without running a full build, none of the code can be type-checked, which IMO isn't my favorite compromise.
Hi, @refi64 . Could you lead me to understand why there is a typechecking problem (before build) ? As far as I can imagine, the public interface of reusable hooks would hopefully be comprehensive to be referred to without running any build step, and I think the only type information we need from a component is 'whether it is a Component or not (typical inheritance relationship)' as all logical compositions should be implemented by hooks and component compositions are only for expressing ui hierarchy.
Consider this same example:
class Component {
setup() {
final mousePos = MouseLogic();
final other = OtherLogic();
return {
x: mousePos.x,
y: mousePos.y,
z: other
};
}
If we have a custom render function:
void render(/*???*/ state, ...)
what's the type of our state? We could at best represent it as a Map<String, dynamic>
, which means that the values would all be untyped.
This also causes questions such as this:
setup() {
// ...
var map = {
// ...
};
map.pop(...);
return map; // how do we compile this?
}
Basically, Dart maps are far more untyped than TypeScript's...
I must admit that I didn't think of custom render functions and maps.
https://github.com/vuejs/rfcs/pull/42 is the new proposed preferred API for Vue 3, and I've been really trying to think hard about how to best apply this to the more traditional OO, nominally typed Dart.
Here's basically the API I have in mind:
Merging state
One problem that persist is how we should handle merged state, e.g. the Dart version of this in setup:
Most likely this will continue to use Dart's mixins for the best typing support:
However, this does re-introduce the problem of namespace conflicts, which I quite frankly am not sure how to solve yet.
The more basic reactivity API will still be supported (e.g.
var v = value(0)
), and all State will probably be is some sort of base class with acreateVueState
method that returns the state in the format Vue wants.Timeline: I have no idea, this is likely going to be paired with some fundamental backend changes in order to utilize Dart's part system to avoid screwing with line numbers, so it's going to take a bit. Definitely messes with the 0.5/0.6 release plans I was shooting for.