Hi, @straight-shoota, I consider there is a more elegant way to achieve this.
I wan working on a new kemal project, it use a layout like this:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<%= yield_content "title" %>
<link rel="stylesheet" href="/materialize/css/materialize.min.css" />
</head>
<body>
<%= yield_content "footer" %>
</body>
</html>
I checked yesterday, i can confirm this solution should works, though, i consider this is not a good solution, because we need hack not only one library files.
I want to compile the css file src/assets//materialize/css/materialize.min.css
into binary use backed_file_system
, when kemal server is starting, those file can be serve directly.
your’s solution should works, though, i consider this is not a good solution, because we need hack several source code file, e.g.
src/kemal/static_file_handler.cr
src/kemal/helpers/helpers.cr
replace all File
IO
to with backed_file_system, then it should work. HTTP::StaticFileHandler in Crystal std-lib probably don’t need change.
Anyway, i found a more elegant solution:
-
save file into binary use backed_file_system
,
-
instead hack source code read from backed_file_system
directly, we can recreate those file in the default public/
asset folder when starting kemal sever.
We can achieve this use macro, like this: (may need improve, but it works)
require "baked_file_system"
private macro mount(from, to)
{% begin %}
{% root = system("pwd").strip.id %}
class FileStorage
extend BakedFileSystem
bake_folder "{{root}}/{{from.id}}"
end
def create_public_assets
Dir.glob("{{from.id}}/**/*").each do |filename|
next unless File.file? filename
target_file_name = filename.sub("{{from.id}}", "{{to.id}}")
FileUtils.mkdir_p File.dirname(target_file_name) unless File.exists?(target_file_name)
File.write(target_file_name, FileStorage.get(filename.sub("{{from.id}}/", "")).gets_to_end)
end
end
{% end %}
end
mount "src/assets", "public"
create_public_assets
╰─ $ tree src/assets/ public/
src/assets/
└── materialize
├── css
│ └── materialize.min.css
└── js
└── materialize.min.js
public/
└── materialize
├── css
│ └── materialize.min.css
└── js
└── materialize.min.js
3 directories, 2 files
For my cases, it will save files in src/assets
into binary use backed_file_system
when build, then, it will read those files from backed_file_system, then them in real file system public
folder again when start kemal.
Maybe it be worth to create a shards to make kemal support it.
EDIT:
Sorry, above code not work, i fix it and release it as a shard. check here