-
-
Notifications
You must be signed in to change notification settings - Fork 9
Support assets in mel.module
#134
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
Conversation
I have updated the PR to support both Webpack and Esbuild, via a new flag For now the generated filenames follow the default name scheme used on each bundler case. We can add more features later on while testing, e.g. file templates like I also have left some failed attempt to produce Rspack hashes commented, as currently rspack doesn't support proper content hashes. I decided to not include tests against the actual Webpack or Esbuild bundlers hashes because these hashes should not change over time, and it would slow down and complicate the test suite quite a bit. |
~doc: | ||
"generate paths to assets in mel.module using the file name scheme of \ | ||
the bundler of choice"; | ||
Driver.V2.register_transformation ~impl:structure_mapper |
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.
Changing to V2
here is what allows to get the ctxt
in structure_mapper
, which is used later on to get the path to the file being processed (so that we can open it to get its content for the hash).
.github/workflows/ci.yml
Outdated
@@ -55,6 +55,14 @@ jobs: | |||
dune-cache: true | |||
opam-disable-sandboxing: true | |||
|
|||
- name: Install xxhash (ubuntu) | |||
if: matrix.os == 'ubuntu-latest' | |||
run: sudo apt-get install -y libxxhash-dev |
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.
would it mean that all consumers of server-reason-react need to have this installed?
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.
Yes :( Alternatives can be:
- put the melange.ppx in a separate package
- reimplement the xxhash lib in OCaml
- ...
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.
and what about adding libxxhash-dev depext?
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.
Good idea 😄 Done in d69747d.
packages/melange.ppx/ppx.ml
Outdated
(* todo: maybe read line by line of buffered for large files *) | ||
let ic = open_in asset_path in | ||
let n = in_channel_length ic in | ||
let s = really_input_string ic n in | ||
close_in ic; |
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 used In_channel.with_open_bin file In_channel.input_all
in the past, if you want to avoid having to open/close_in
(* If it has asset payload (file with extension), calculate hash and replace external *) | ||
let name = Builder.pvar ~loc:pval_name.loc pval_name.txt in | ||
let path = | ||
let asset_path = Filename.(concat (dirname module_path) str) 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.
Smart, this way we don't care what dune dones
| Webpack -> Mel_module.Webpack.filename | ||
| Esbuild -> Mel_module.Esbuild.filename | ||
in | ||
let prefix = (* todo: read from config *) "/" 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.
What's prefix here? The cdn url/etc?
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.
Yeah anything that comes before the file name itself.
@@ -401,6 +544,20 @@ module Debug = struct | |||
end | |||
|
|||
let () = | |||
Driver.register_transformation ~impl:structure_mapper | |||
Driver.add_arg "-bundler" |
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 didn't like the idea of coupling our melange_ppx with a bundler, and I would prefer to keep a --assets-hash-fn
where it specifies "xxhash64" or even a format like webpack, but after seeing the complexity it carries... It's perfectly fine to keep it coupled.
Did you thought the same?
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.
It's a bit tricky, because the behavior changes a bit between bundlers:
- webpack is the most flexible of those i've investigated, allowing to use any kind of hash function and any kind of template to build the resulting asset name
- rspack allows any kind of template, but hash functions are delimited to xxhash64 or md4 (and the hashes are not really from the file content, unlike webpack)
- esbuild allows any template, but only supports xxhash64 (postprocessed with base32, which makes it different from the two above)
How do you think we should model this? It certainly seems we should allow users to configure somewhere the file name template to be used to generate the final paths, right? But we should somehow guarantee that the templates are also compatible across bundlers?
In my mind, this wasn't blocking an initial mvp of this feature because users can always update their JS bundler config to use the default asset filename of each bundler, which is what is currently implemented:
- esbuild:
[name]-[hash][ext]
- webpack:
[hash][ext]
Wdyt?
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.
Current impl looks good, I tried to rationalise over the idea of coupling, but it's not practical. Thanks for the explanation, it might deserve a blog post.
CHANGES: ## 0.3.1 * Update quickjs dependency to 0.1.2 by @davesnx ## 0.3.0 * browser-ppx: process stritems by @jchavarri in ml-in-barcelona/server-reason-react#127 * Make React.Children.* APIs work as expected by @davesnx in ml-in-barcelona/server-reason-react#130 * Improve global crashes by @davesnx in ml-in-barcelona/server-reason-react#132 * Support assets in `mel.module` by @jchavarri in ml-in-barcelona/server-reason-react#134 * browser_only: don't convert to runtime errors on identifiers or function application by @jchavarri in ml-in-barcelona/server-reason-react#138 * Port `j` quoted strings interpolation from Melange by @jchavarri in ml-in-barcelona/server-reason-react#139 * mel.module: handle asset prefix by @jchavarri in ml-in-barcelona/server-reason-react#140 * Add browser_only transformation to useEffect automatically by @davesnx in ml-in-barcelona/server-reason-react#145 * Append doctype tag on html lowercase by @davesnx in ml-in-barcelona/server-reason-react#136 * Transform Pexp_function with browser_only by @davesnx in ml-in-barcelona/server-reason-react#146 ## 0.2.0 - Remove data-reactroot attr from ReactDOM.renderToString ml-in-barcelona/server-reason-react#129 by @pedrobslisboa - Make useUrl return the provided serverUrl ml-in-barcelona/server-reason-react#125 by @purefunctor - Replace Js.Re implemenation from `pcre` to quickjs b1a3e225cdad1298d705fbbd9618e15b0427ef0f by @davesnx - Remove Belt.Array.push ml-in-barcelona/server-reason-react#122 by @davesnx ## 0.1.0 Initial release of server-reason-react, includes: - Server-side rendering of ReasonReact components (renderToString, renderToStaticMarkup & renderToLwtStream) - `server-reason-react.browser_ppx` for skipping code from the server - `server-reason-react.melange_ppx` for enabling melange bindings and extensions which run on the server - `server-reason-react.belt` a native Belt implementation - `server-reason-react.js` a native Js implementation (unsafe and limited) - `server-reason-react.url` and `server-reason-react.url-native` a universal library with both implementations to work with URLs on the server and the client - `server-reason-react.promise` and `server-reason-react.promise-native` a universal library with both implementations to work with Promises on the server and the client. Based on https://github.com/aantron/promise - `server-reason-react.melange-fetch` a fork of melange-fetch which is a melange library to fetch data on the client via the Fetch API. This fork is to be able to compile it on the server (not running). - `server-reason-react.webapi` a fork of melange-webapi which is a melange library to work with the Web API on the client. This fork is to be able to compile it on the server (not running).
CHANGES: ## 0.3.1 * Update quickjs dependency to 0.1.2 by @davesnx ## 0.3.0 * browser-ppx: process stritems by @jchavarri in ml-in-barcelona/server-reason-react#127 * Make React.Children.* APIs work as expected by @davesnx in ml-in-barcelona/server-reason-react#130 * Improve global crashes by @davesnx in ml-in-barcelona/server-reason-react#132 * Support assets in `mel.module` by @jchavarri in ml-in-barcelona/server-reason-react#134 * browser_only: don't convert to runtime errors on identifiers or function application by @jchavarri in ml-in-barcelona/server-reason-react#138 * Port `j` quoted strings interpolation from Melange by @jchavarri in ml-in-barcelona/server-reason-react#139 * mel.module: handle asset prefix by @jchavarri in ml-in-barcelona/server-reason-react#140 * Add browser_only transformation to useEffect automatically by @davesnx in ml-in-barcelona/server-reason-react#145 * Append doctype tag on html lowercase by @davesnx in ml-in-barcelona/server-reason-react#136 * Transform Pexp_function with browser_only by @davesnx in ml-in-barcelona/server-reason-react#146 ## 0.2.0 - Remove data-reactroot attr from ReactDOM.renderToString ml-in-barcelona/server-reason-react#129 by @pedrobslisboa - Make useUrl return the provided serverUrl ml-in-barcelona/server-reason-react#125 by @purefunctor - Replace Js.Re implemenation from `pcre` to quickjs b1a3e225cdad1298d705fbbd9618e15b0427ef0f by @davesnx - Remove Belt.Array.push ml-in-barcelona/server-reason-react#122 by @davesnx ## 0.1.0 Initial release of server-reason-react, includes: - Server-side rendering of ReasonReact components (renderToString, renderToStaticMarkup & renderToLwtStream) - `server-reason-react.browser_ppx` for skipping code from the server - `server-reason-react.melange_ppx` for enabling melange bindings and extensions which run on the server - `server-reason-react.belt` a native Belt implementation - `server-reason-react.js` a native Js implementation (unsafe and limited) - `server-reason-react.url` and `server-reason-react.url-native` a universal library with both implementations to work with URLs on the server and the client - `server-reason-react.promise` and `server-reason-react.promise-native` a universal library with both implementations to work with Promises on the server and the client. Based on https://github.com/aantron/promise - `server-reason-react.melange-fetch` a fork of melange-fetch which is a melange library to fetch data on the client via the Fetch API. This fork is to be able to compile it on the server (not running). - `server-reason-react.webapi` a fork of melange-webapi which is a melange library to work with the Web API on the client. This fork is to be able to compile it on the server (not running).
This PR adds initial support to compile externals like:
Into something like:
The output file naming follows esbuild default shape and hash function. There is no option to configure anything else for now, we can slowly introduce as needed.Edit: the ppx now support choosing either-bundler esbuild
or-bundler webpack
. The default is webpack.I decided to vendor the libraries
base32
andxxhash
for simplicity, to avoid forcing consumers to pin or download new packages, as they are quite small libraries and the versions that were needed are not available in opam.