Open wre232114 opened 1 year ago
After vue-compiler is released, will farm naturally provide built-in support for .vue files, similar to .jsx?
we will provide official plugin and scaffold to support.
Any plans for the Rust/SWC plugin system support?
we already have rust/swc plugins supported. see @farmfe/plugin-react, and examples/vue-jsx
Judging by the examples, does it only support string output?
The farmfe_core::plugin::Plugin
trait has transform
and process_module
functions, of which transform
seems to be the right one to take the source (param.content
). Now, how would you write a plugin (or loader in webpack world) which takes a string and returns an SWC AST?
transform is string to string, then the string will be passed to parse hook and be parsed to ast.
process_module is ast to ast. swc pklugins are executed during this stage.
if you want to parse string to ast directly, you need to use parse hook. for most situation transform would be enough, I think load + transform = webpack loader
One more question relevant to Vue compilation. Vue SFC's have <style>
blocks, which usually contain CSS/SCSS/etc.
Ideally, from the SFC compiler's perspective, I'd love to have the following flow:
parse
, as you mentioned, takes .vue
and converts it to SWC AST;<style lang="css" scoped>
and <style lang="scss" scoped>
.lightningcss
;How do I implement points 3 and 5?
We already have implemented Vue SFC compilation in JS, see https://github.com/farm-fe/farm/blob/main/js-plugins/vue/src/farm-vue-plugin.ts#L43.
I think there are 2 methods to implement Vue compilation in Rust:
js-plugin-vue
, use load
+ transform
. In transform
, Vue SFC compiler compiles .vue
into blocks(js/jsx/ts/tsx
, scss/less/etc
), then transform js/jsx/ts/tsx
block to js/jsx/ts/tsx
module, insert import './xx.scss?vue&scoped&hash=xxx'
to that module and return its code. So the .vue
file are compiled to a script
module and several scss/less/css
module. Then other plugins will be responsible for compiling js/jsx/ts/tsx
and scss/less
, including transforming and code generation. That's how vite and webpack deal with .vue
..vue
as a separate basic module type in Farm, you need to implement following hooks:
load
: use load
first to support load .vue
as custom module type like ModuleType::Customer("vue")
parse
: then use parse
to parse your custom module typeanalyze_deps
: return the specifiers like ./helpers
to resolve dependencies.process_module
: do AST transformation for your custom module type.build_end
: split your vue module type into js/jsx/ts/tsx
and css
modules that farm natively supports, and connect them in the ModuleGraph, so you do not need to implement optimization and code generation hooks
again for .vue
.I prefer method 1 because it's simple, the plugin-vue just needs to compile itself to js/jsx/ts/tsx
and scss/less/css
and other plugins will take the rest. If you want to reuse ast between transform
and parse
, you can implement both hooks, just cache the ast in transform
and then reuse it in parse
.
Big thanks for the explanation, I would certainly try the flow you suggested. Small follow-up question: do you have examples of how to cache intermediate plugin results (meaning cache managed by Farm), or should it be an own static
cache?
I was initially thinking of implementing method 1 as well, because it is mentally easier. But as you dig in the webpack/rollup loader implementations, especially when tracing Typescript flows, you notice that .vue
are sometimes parsed 3-4 times for every import './xx.vue?vue&block=style'
. Not only that, but the compiler tends to produce pretty bloated code when it treats SFC blocks as independent JS modules (this is a big issue for projects with 2000+ modules). And compilation in such cases gets as slow as < 100 modules/sec in best case (raw JS perf is around 1500).
Which are all the reasons I started the Rust implementation.
That's why I think of implementing method 2, even if it means adapting it to every major bundler API out there.
I think if the compiled blocks can be cached and reused, the performance of these two methods wouldn't be a big difference.
Farm doesn't manage cache for plugins, plugins should handle their cache themselves, see ast cache examples: https://github.com/farm-fe/farm/blob/main/crates/plugin_css/src/lib.rs#L49. Farm reuses ast for css modules implementation in the example
Investigate https://github.com/HerringtonDarkholme/vue-compiler