-
Notifications
You must be signed in to change notification settings - Fork 311
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
What are the capabilities / limitations of the plugins? #2489
Comments
Can the plugins rewrite the module generated code? For example, for this code module TestB =
let getName (v : TestB) =
if v.Type = 1 then
"Class"
else
"Function" can it generates something like export let Config = {}
Config.getName = function (v) {
if (v.Type === 1) {
return "Class";
}
else {
return "Function";
}
}
// or
export const Config = {
getName: function (v) {
if (v.Type === 1) {
return "Class";
}
else {
return "Function";
}
}
} instead of export function TestBModule_getName(v) {
if (v.Type === 1) {
return "Class";
}
else {
return "Function";
}
} |
I should write some documentation about plugins, shouldn't I? 😅 Only thing is plugins have access to the internal AST and this is the only thing that's going to change for JS in Fable 4 so maybe it's better to keep them "a secret" a bit longer. Anyways, I'll try to quickly summarize the mechanism of plugins: Fable 3 allows for libraries to tell Fable it should load and scan the .dll for "hooks" to different steps of the compilation. This is similar to Type Providers in the sense the user doesn't need to pass explicitly the plugins to the compiler (as it happened with Fable 1). At the moment there're only two such hooks (intercepting function declarations and function calls), we can add more but as said above maybe we should wait until Fable 4 for expanding plugin capabilities. And also like TPs, plugins introduce complexity to the compilation process so it's better to explore alternatives before implementing one.
Not at the moment, but as well as we have a plugin to transform function declaration we probably should add one to alter type declarations. The problem is the "control how it's used" part, because unlike functions that can only be called, types can be used in multiple ways so we would have to intercept too many places for this to work correctly.
For this we would likely need a plugin that goes through all the expressions. Although I wouldn't recommend it for this particular case: it's hard to maintain an alternative fable-library in sync with all changes, we may change the way code from fable-library is imported (this may happen in Fable 4) and if you really need something like this you can just make a search & replace in the generated files. In any case, we should probably bring back the Replacements plugin from Fable 1 that was used to provide alternative implementations to FSharp.Core and BCL apis.
Not at the moment. We could add a plugin for that, or just a compiler option. Although reflection information is designed to be tree shaken if not used.
For that specific example, we could use a feature of let private getName x = if x > 5 then "foo" else "bar"
[<Emit("export const $0! = { $1!: $2 }")>]
let exportAsObject (name: string) (property: string) (value: obj): unit = jsNative
exportAsObject "Config" (nameof(getName)) getName This would generate the following code: function getName(x) {
if (x > 5) { return "foo"; }
else { return "bar"; }
}
export const Config = { getName: ((x) => getName(x)) }; |
Thank you for all your answers.
It would be nice yes ^^ as if it is not documented then it is harder to explore :)
This is also my though on it.
The thing is that if you want to serve the F# file as they are generated without post-processing or bundler then there are a "lot" of noise in the module. Because, you see all the Fable specific codes in it like Reflection etc. That's why I asked and also kind of because I really don't like Reflection ^^
The search and replace should indeed not be too hard to do if I needed. That's was a solution I had in mind, as looking up for certain pattern is not too hard to do.
I didn't know of this feature at the time. I thought for a second we could use let inline exportAsObject (name: string) (property: string) (value: obj): unit =
emitJsExpr (name, property, value)
"""
export const $0 = { $1: $2 };
"""
exportAsObject "Config" (nameof(getName)) getName generates export const "Config" = { "getName": ((x) => getName(x)) }; instead of export const Config = { getName: ((x) => getName(x)) }; |
Closing for now, please reopen if further details are needed. If you want to add some of the discussed features (e.g. the compiler flag to skip reflection), can you please open a separate issue for that?
|
@alfonsogarciacaro I will do. I kind of put on the same my work on Glutinum but plan on going back to it in the future. I am first trying to clean my backlog of tasks :) |
I gave it a go :) #2710 |
Description
Hello,
Fable 3 re-introduced a plugin system but I think it still doesn't have documentation on it.
In current form what are the capabilities and limitation of the plugins?
Here are some questions I have in mind but if you have others things to add to the list please do :)
Can they allow to rewrite a type definition? For example, if I attach a
[<Pojo>]
attribute to a record can I control how it is defined or used?Can it allow modification of the import paths? For example, could it intercept all the
./.fable/fable-library.3.2.9/XXX
calls and rewrite them to use afable-library
which could be an npm package?Can it prevent generation of some of the code like removing reflection informations?
Can it only rewrite "function call" like Feliz does?
The text was updated successfully, but these errors were encountered: