-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add @browser_only #185
base: main
Are you sure you want to change the base?
Add @browser_only #185
Conversation
2c5e185
to
9bef4f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea behind this PR, but it collides with the switch%platform that is a bit more explicit than the annotations.
Looking at the tests I see there's no clear use-case that this enables that isn't possible with a switch expression, so I would rather ask to add more test cases to expose clearly the patterns.
Otherwise looks great to add
|
||
$ ./standalone.exe -impl input_let.ml | ocamlformat - --enable-outside-detected-project --impl | ||
let x = | ||
let y = 44 [@@platform native] in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
platform attribute should not be part of the output right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The platform attr is part of the output on all the examples of this test. Like this one:
Nested
$ cat > input.ml << EOF
> module X = struct
> include struct
> type t = Js.Json.t
> let a = 2 + 2
> end [@@platform js]
>
> include struct
> type t = Js.Json.t
> let a = 4 + 4
> end [@@platform native]
> end
> EOF
With -js flag it picks the block with `[@@platform js]`
$ ./standalone.exe -impl input.ml -js | ocamlformat - --enable-outside-detected-project --impl
module X = struct
include struct
type t = Js.Json.t
let a = 2 + 2
end [@@platform js]
end
Without -js flag, it picks the block with `[@@platform native]`
$ ./standalone.exe -impl input.ml | ocamlformat - --enable-outside-detected-project --impl
module X = struct
include struct
type t = Js.Json.t
let a = 4 + 4
end [@@platform native]
end
> let y = 42 [@@platform js] in | ||
> let y = 44 [@@platform native] in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This snapshot is indeed interesting because currently, the switch%platform makes more sense in those scenarios, right?
I know that it's just a test, but trying to understand better how it works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, in case you want to handle a single variable as y
the switch%platform
is the way:
let y = switch%platform () {
| Client => 42
| Server => 44
}
But there will be cases which we just want to say that this code is "browser_only".
Example:
let make = (~initial, ~onClick as [@platform js] onClick) => {
let (count, [@platform js] setCount) = RR.useStateValue(initial);
[@platform js]
let onClick = e => {
setCount(count + 1);
Js.log("This prints to the console");
Js.log2("Printing count", count);
onClick(e);
};
//...
In this case, for example, onClick is not required on serve, so we ca remove it from native code, setCount
is also browser_only
so we change it to _
on native, same with onClick
I don't know if it's possible to have switch%platform
on those cases, for example:
switch%platform () {
| Client =>
let onClick = e => {
setCount(count + 1);
Js.log("This prints to the console");
Js.log2("Printing count", count);
onClick(e);
};
();
| Server => ()
};
// Outputs the code bellow, which will not work:
{
let onClick = e => {
setCount(count + 1);
Js.log("This prints to the console");
Js.log2("Printing count", count);
onClick(e);
};
();
};
I think %browser_only
would cover the function (will still have the warning) but not the tuple of even the prop.
The prop is a very common case. It is pretty normal to have onClick props on a CustomComponent, as shown in the code above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo we should consolidate to either platform js
or browser_only
. Keeping both is a bit confusing to me. If we decide for one, we could deprecate the other in one version and remove it in the next.
let (x [@platform native]), _ = (42, 44) | ||
|
||
$ ./standalone.exe -impl input_let.ml -js | ocamlformat - --enable-outside-detected-project --impl | ||
let _, (y [@platform js]) = (42, 44) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case is indeed cool, but extremly rare in practice, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be common with useStates, for example, where the setState is commonly used on event callbacks as onClick.
I added it just as a test covered, but the [@platform]
should work on every pattern, not only tuples but arrays, args, etc.
I answered here that maybe switch%platform cannot fully cover some cases: #185 (comment) I agree that the [@platform js] is not good for those cases; what about the [@browser_only]
let make = () => {
let (a, [@browser_only] y) = (42, 44)
} |
@davesnx By the way, this PR is an attempt to improve what we already had with the
But we could not do something like:
Because |
@@ -2,7 +2,6 @@ | |||
(name server) | |||
(enabled_if | |||
(= %{profile} "dev")) | |||
(flags :standard -w -26-27) ; browser_only removes code form the server, making this warning necessary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:3 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool!
packages/runtime/Runtime.ml
Outdated
in | ||
raise (Impossible_in_ssr (Printf.sprintf {|'%s' shouldn't run on the server|} fn)) | ||
|
||
let fail_impossible_action_in_ssr_anonymous fn = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different than the other function? The only difference I can see is that this one prints the function with Function:
while the other just shows it at the beginning of the msg (`'%s' sohld only run on the client...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first, I thought it was better to have it as an anonymous function, separated to be clear.
But I guess it's not necessary
demo/universal/native/lib/Counter.re
Outdated
switch%platform (Runtime.platform) { | ||
| Server => print_endline("This prints to the server terminal") | ||
| Client => print_endline("This prints to the console") | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jchavarri This piece of code was present before, but @davesnx removed it, and on the merge, I didn't notice it. Going to remove it.
@@ -5,8 +5,9 @@ type target = Native | Js | |||
|
|||
let mode = ref Native | |||
let browser_ppx = "browser_ppx" | |||
let browser_only = "browser_only" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be used in a few places to replace string literal (e.g. line 131)
> let y = 42 [@@platform js] in | ||
> let y = 44 [@@platform native] in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo we should consolidate to either platform js
or browser_only
. Keeping both is a bit confusing to me. If we decide for one, we could deprecate the other in one version and remove it in the next.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now [@browser_only]
gets transformed into "do nothing" while [%browser_only] gets transformed into raising, do you think we could unify both? Or make [@browser]
not fail, while _only fails?
I'm happy to merge as is, and keep this idea around until we solidify the concepts, no rush on pushing it now :D
5baa98c
to
65e1945
Compare
65e1945
to
96536e3
Compare
96536e3
to
8b57eeb
Compare
8b57eeb
to
ff118b8
Compare
34fe287
to
e81cd90
Compare
@davesnx @jchavarri Any extra comments about it? |
Description
Working on removing platform code from expressions and pattern
Why
A common problem when using
browser_only
is that we need to disable some warnings due to a present code on the native:So we still have
foo
on native. It only raises an error at runtime, and asfoo
should only be used on browsers, the compiler will complain of a non-used variable.Another issue with browser_only is that it only works on functions, limiting its usage for other cases, such as args, variables, etc.
To work around it, I incremented
browser_only
to work as an attribute, which allowed us to work on other cases.Example:
The ugliest part is that ocaml doesn't allow (At least I didn't find a way) to add an attribute directly to labeled args, so we need to do
(~x as [@browser_only] x
in reason and~x:(x[@browser_only])
in ocaml 🫠.@davesnx @jchavarri Tagging, you guys, to discuss it. With this feature, I was able to remove the warning disables