mirror of
				https://github.com/livebook-dev/livebook.git
				synced 2025-11-01 00:06:04 +08:00 
			
		
		
		
	Make priv generation into a compiler task (#2978)
This commit is contained in:
		
							parent
							
								
									d988d84679
								
							
						
					
					
						commit
						4c50755581
					
				
					 4 changed files with 83 additions and 57 deletions
				
			
		|  | @ -33,17 +33,17 @@ defmodule LivebookWeb.Endpoint do | |||
|   # To account for both cases, we configure Plug.Static :from as MFA | ||||
|   # and return the accessible priv/ location in both scenarios. | ||||
|   # | ||||
|   # The priv/ static files are generated by the livebook.gen_priv task | ||||
|   # before building the escript or the release. We gzip the static | ||||
|   # files in priv/, since we want to serve them gzipped, and we don't | ||||
|   # include the non-gzipped ones to minimize app size. Note that we | ||||
|   # still have a separate static/ directory with the CI-precompiled | ||||
|   # assets, which we keep in Git so that people can install escript | ||||
|   # from GitHub or run MIX_ENV=prod phx.server, without Node and NPM. | ||||
|   # Storing minified assets is already not ideal, but we definitely | ||||
|   # want to avoid storing the gzipped variants in Git. That's why we | ||||
|   # store the assets uncompressed and then generate priv/static with | ||||
|   # their compressed variants as part of the build process. | ||||
|   # The priv/ static files are generated by the compile.livebook_priv | ||||
|   # as part of compilation. We gzip the static files in priv/, since | ||||
|   # we want to serve them gzipped, and we don't include the non-gzipped | ||||
|   # ones to minimize app size. Note that we still have a separate | ||||
|   # static/ directory with the CI-precompiled assets, which we keep | ||||
|   # in Git so that people can install escript from GitHub or run | ||||
|   # MIX_ENV=prod phx.server, without Node and NPM. Storing minified | ||||
|   # assets is already not ideal, but we definitely want to avoid | ||||
|   # storing the gzipped variants in Git. That's why we store the | ||||
|   # assets uncompressed and then generate priv/static with their | ||||
|   # compressed variants at compile time. | ||||
| 
 | ||||
|   if code_reloading? do | ||||
|     # In development, we use assets from tmp/static_dev, which are | ||||
|  |  | |||
							
								
								
									
										70
									
								
								lib/mix/tasks/compile.livebook_priv.ex
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								lib/mix/tasks/compile.livebook_priv.ex
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| defmodule Mix.Tasks.Compile.LivebookPriv do | ||||
|   @moduledoc false | ||||
| 
 | ||||
|   use Mix.Task | ||||
| 
 | ||||
|   @gzippable_exts ~w(.js .css .txt .text .html .json .svg .eot .ttf) | ||||
| 
 | ||||
|   @impl true | ||||
|   def run(_args) do | ||||
|     app_path = Mix.Project.app_path() | ||||
|     manifest_path = Path.join(app_path, "compile.livebook_priv") | ||||
| 
 | ||||
|     prev_mtime = | ||||
|       case File.read(manifest_path) do | ||||
|         {:ok, binary} -> :erlang.binary_to_term(binary) | ||||
|         {:error, _error} -> nil | ||||
|       end | ||||
| 
 | ||||
|     mtime1 = | ||||
|       compress_and_copy( | ||||
|         "static", | ||||
|         Path.join(app_path, "priv/static"), | ||||
|         prev_mtime | ||||
|       ) | ||||
| 
 | ||||
|     mtime2 = | ||||
|       compress_and_copy( | ||||
|         "iframe/priv/static/iframe", | ||||
|         Path.join(app_path, "priv/iframe_static"), | ||||
|         prev_mtime | ||||
|       ) | ||||
| 
 | ||||
|     mtime = max(mtime1, mtime2) | ||||
|     File.write!(manifest_path, :erlang.term_to_binary(mtime)) | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   defp compress_and_copy(source_dir, target_dir, prev_mtime) do | ||||
|     source_paths = Path.wildcard(Path.join(source_dir, "**/*")) | ||||
|     mtime = paths_mtime(source_paths) | ||||
| 
 | ||||
|     changed? = prev_mtime == nil or mtime > prev_mtime | ||||
| 
 | ||||
|     if changed? do | ||||
|       File.rm_rf!(target_dir) | ||||
| 
 | ||||
|       for source_path <- source_paths, File.regular?(source_path) do | ||||
|         target_path = Path.join(target_dir, Path.relative_to(source_path, source_dir)) | ||||
|         File.mkdir_p!(Path.dirname(target_path)) | ||||
| 
 | ||||
|         if Path.extname(source_path) in @gzippable_exts do | ||||
|           content = source_path |> File.read!() |> :zlib.gzip() | ||||
|           File.write!(target_path <> ".gz", content) | ||||
|         else | ||||
|           File.cp!(source_path, target_path) | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       Mix.shell().info("Generated #{target_dir} with compressed files from #{source_dir}") | ||||
|     end | ||||
| 
 | ||||
|     mtime | ||||
|   end | ||||
| 
 | ||||
|   defp paths_mtime(paths) do | ||||
|     paths | ||||
|     |> Enum.map(fn path -> File.stat!(path).mtime end) | ||||
|     |> Enum.max() | ||||
|   end | ||||
| end | ||||
|  | @ -1,42 +0,0 @@ | |||
| defmodule Mix.Tasks.Livebook.GenPriv do | ||||
|   @moduledoc false | ||||
| 
 | ||||
|   use Mix.Task | ||||
| 
 | ||||
|   @gzippable_exts ~w(.js .css .txt .text .html .json .svg .eot .ttf) | ||||
| 
 | ||||
|   @impl true | ||||
|   def run([]) do | ||||
|     # Use absolute paths, instead of relying on the current mix project, | ||||
|     # so the task can be invoked by nerves_livebook. | ||||
|     app_path = Application.app_dir(:livebook) | ||||
|     project_dir = Path.expand("../../..", __DIR__) | ||||
| 
 | ||||
|     compress_and_copy(Path.join(project_dir, "static"), Path.join(app_path, "priv/static")) | ||||
| 
 | ||||
|     compress_and_copy( | ||||
|       Path.join(project_dir, "iframe/priv/static/iframe"), | ||||
|       Path.join(app_path, "priv/iframe_static") | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp compress_and_copy(source_dir, target_dir) do | ||||
|     File.rm_rf!(target_dir) | ||||
| 
 | ||||
|     source_paths = Path.wildcard(Path.join(source_dir, "**/*")) | ||||
| 
 | ||||
|     for source_path <- source_paths, File.regular?(source_path) do | ||||
|       target_path = Path.join(target_dir, Path.relative_to(source_path, source_dir)) | ||||
|       File.mkdir_p!(Path.dirname(target_path)) | ||||
| 
 | ||||
|       if Path.extname(source_path) in @gzippable_exts do | ||||
|         content = source_path |> File.read!() |> :zlib.gzip() | ||||
|         File.write!(target_path <> ".gz", content) | ||||
|       else | ||||
|         File.cp!(source_path, target_path) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     Mix.shell().info("Generated #{target_dir} with compressed files from #{source_dir}") | ||||
|   end | ||||
| end | ||||
							
								
								
									
										6
									
								
								mix.exs
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								mix.exs
									
										
									
									
									
								
							|  | @ -18,6 +18,7 @@ defmodule Livebook.MixProject do | |||
|       description: @description, | ||||
|       elixirc_paths: elixirc_paths(Mix.env()), | ||||
|       test_elixirc_options: [docs: true], | ||||
|       compilers: Mix.compilers() ++ [:livebook_priv], | ||||
|       start_permanent: Mix.env() == :prod, | ||||
|       aliases: aliases(), | ||||
|       deps: with_lock(target_deps(Mix.target()) ++ deps()), | ||||
|  | @ -68,10 +69,7 @@ defmodule Livebook.MixProject do | |||
|       setup: ["deps.get", "cmd --cd assets npm install"], | ||||
|       "assets.deploy": ["cmd npm run deploy --prefix assets"], | ||||
|       "format.all": ["format", "cmd --cd assets npm run --silent format"], | ||||
|       "protobuf.generate": ["cmd --cd proto mix protobuf.generate"], | ||||
|       "phx.server": ["livebook.gen_priv", "phx.server"], | ||||
|       "escript.build": ["livebook.gen_priv", "escript.build"], | ||||
|       release: ["livebook.gen_priv", "release"] | ||||
|       "protobuf.generate": ["cmd --cd proto mix protobuf.generate"] | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue