mirror of
https://github.com/woutdp/live_svelte
synced 2026-05-24 09:28:21 +00:00
chore: added igniter installer
This commit is contained in:
parent
31f1a9339d
commit
3f2684be40
12 changed files with 529 additions and 321 deletions
|
|
@ -1,71 +0,0 @@
|
|||
const esbuild = require("esbuild")
|
||||
const sveltePlugin = require("esbuild-svelte")
|
||||
const importGlobPlugin = require("esbuild-plugin-import-glob").default
|
||||
const sveltePreprocess = require("svelte-preprocess")
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
const watch = args.includes("--watch")
|
||||
const deploy = args.includes("--deploy")
|
||||
|
||||
let clientConditions = ["svelte", "browser"]
|
||||
let serverConditions = ["svelte"]
|
||||
|
||||
if (!deploy) {
|
||||
clientConditions.push("development")
|
||||
serverConditions.push("development")
|
||||
}
|
||||
|
||||
let optsClient = {
|
||||
entryPoints: ["js/app.js"],
|
||||
bundle: true,
|
||||
minify: deploy,
|
||||
conditions: clientConditions,
|
||||
alias: {svelte: "svelte"},
|
||||
outdir: "../priv/static/assets/js",
|
||||
logLevel: "info",
|
||||
sourcemap: watch ? "inline" : false,
|
||||
tsconfig: "./tsconfig.json",
|
||||
plugins: [
|
||||
importGlobPlugin(),
|
||||
sveltePlugin({
|
||||
preprocess: sveltePreprocess(),
|
||||
compilerOptions: {dev: !deploy, css: "injected", generate: "client"},
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
let optsServer = {
|
||||
entryPoints: ["js/server.js"],
|
||||
platform: "node",
|
||||
bundle: true,
|
||||
minify: false,
|
||||
target: "node19.6.1",
|
||||
conditions: serverConditions,
|
||||
alias: {svelte: "svelte"},
|
||||
outdir: "../priv/svelte",
|
||||
logLevel: "info",
|
||||
sourcemap: watch ? "inline" : false,
|
||||
tsconfig: "./tsconfig.json",
|
||||
plugins: [
|
||||
importGlobPlugin(),
|
||||
sveltePlugin({
|
||||
preprocess: sveltePreprocess(),
|
||||
compilerOptions: {dev: !deploy, css: "injected", generate: "server"},
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
esbuild
|
||||
.context(optsClient)
|
||||
.then(ctx => ctx.watch())
|
||||
.catch(_error => process.exit(1))
|
||||
|
||||
esbuild
|
||||
.context(optsServer)
|
||||
.then(ctx => ctx.watch())
|
||||
.catch(_error => process.exit(1))
|
||||
} else {
|
||||
esbuild.build(optsClient)
|
||||
esbuild.build(optsServer)
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// If you want to use Phoenix channels, run `mix help phx.gen.channel`
|
||||
// to get started and then uncomment the line below.
|
||||
// import "./user_socket.js"
|
||||
|
||||
// You can include dependencies in two ways.
|
||||
//
|
||||
// The simplest option is to put them in assets/vendor and
|
||||
// import them using relative paths:
|
||||
//
|
||||
// import "../vendor/some-package.js"
|
||||
//
|
||||
// Alternatively, you can `npm install some-package --prefix assets` and import
|
||||
// them using a path starting with the package name:
|
||||
//
|
||||
// import "some-package"
|
||||
//
|
||||
|
||||
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
||||
import "phoenix_html"
|
||||
// Establish Phoenix Socket and LiveView configuration.
|
||||
import {Socket} from "phoenix"
|
||||
import {LiveSocket} from "phoenix_live_view"
|
||||
import topbar from "../vendor/topbar"
|
||||
import {getHooks} from "live_svelte"
|
||||
import * as Components from "../svelte/**/*.svelte"
|
||||
|
||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
||||
let liveSocket = new LiveSocket("/live", Socket, {hooks: getHooks(Components), params: {_csrf_token: csrfToken}})
|
||||
|
||||
// Show progress bar on live navigation and form submits
|
||||
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
|
||||
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
|
||||
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
|
||||
|
||||
// connect if there are any LiveViews on the page
|
||||
liveSocket.connect()
|
||||
|
||||
// expose liveSocket on window for web console debug logs and latency simulation:
|
||||
// >> liveSocket.enableDebug()
|
||||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
||||
// >> liveSocket.disableLatencySim()
|
||||
window.liveSocket = liveSocket
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import * as Components from "../svelte/**/*.svelte"
|
||||
import {getRender} from "live_svelte"
|
||||
|
||||
export const render = getRender(Components)
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
||||
"phoenix_test": {:hex, :phoenix_test, "0.9.1", "ac58a4d341c594ac57ce52a6ce643200084fad419a91b72896a44881fe84809c", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:lazy_html, "~> 0.1.7", [hex: :lazy_html, repo: "hexpm", optional: false]}, {:mime, ">= 1.0.0", [hex: :mime, repo: "hexpm", optional: true]}, {:phoenix, ">= 1.7.10", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "ed453394c0f8987aa58a06e2302e7dd4bc53cd2d25eff5a18c4a5775241ebe61"},
|
||||
"phoenix_vite": {:hex, :phoenix_vite, "0.4.1", "16fc8b4acc7d4e26fab2bcfb10d125392fcfb5a4ba05dd3aea7f2bec048c5e71", [:mix], [{:bun, ">= 1.5.1 and < 2.0.0-0", [hex: :bun, repo: "hexpm", optional: true]}, {:igniter, "~> 0.6", [hex: :igniter, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "f2bdb1802bc82f2fa93b24606cd25ebdd389bcf2afc55af804f0af3377410f0d"},
|
||||
"plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
|
||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
defmodule LiveSvelte.Logger do
|
||||
@moduledoc false
|
||||
|
||||
@doc false
|
||||
def log_info(status), do: Mix.shell().info([status, :reset])
|
||||
|
||||
@doc false
|
||||
def log_success(status), do: Mix.shell().info([:green, status, :reset])
|
||||
|
||||
@doc false
|
||||
def log_warning(status), do: Mix.shell().info([:yellow, status, :reset])
|
||||
|
||||
@doc false
|
||||
def log_error(status), do: Mix.shell().error([status, :reset])
|
||||
end
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
defmodule Mix.Tasks.LiveSvelte.ConfigureEsbuild do
|
||||
@moduledoc """
|
||||
Creates Javascript files to be used by esbuild. Necessary for LiveSvelte to work.
|
||||
"""
|
||||
|
||||
import LiveSvelte.Logger
|
||||
|
||||
def run(_) do
|
||||
log_info("-- Configuring esbuild...")
|
||||
|
||||
Mix.Project.deps_paths(depth: 1)
|
||||
|> Map.fetch!(:live_svelte)
|
||||
|> Path.join("assets/copy/**/*.{js,json}")
|
||||
|> Path.wildcard()
|
||||
|> Enum.each(fn full_path ->
|
||||
[_beginning, relative_path] = String.split(full_path, "copy", parts: 2)
|
||||
|
||||
Mix.Generator.copy_file(full_path, "assets" <> relative_path)
|
||||
end)
|
||||
|
||||
Mix.Generator.create_directory("assets/svelte")
|
||||
end
|
||||
end
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
defmodule Mix.Tasks.LiveSvelte.ConfigurePhoenix do
|
||||
@moduledoc """
|
||||
Configures any necessary code changes inside Phoenix to make LiveSvelte work.
|
||||
"""
|
||||
|
||||
import LiveSvelte.Logger
|
||||
|
||||
@watcher_regex ~r/watchers:\s\[(?!\s+node:)/
|
||||
@esbuild_regex ~r/(?<!# )esbuild: {.*}/
|
||||
@nodejs_regex ~r/children\s+=\s+\[(?!\s+\{NodeJS)/
|
||||
@gitignore_regex ~r/\Z/
|
||||
|
||||
def run(_) do
|
||||
log_info("-- Configuring Phoenix...")
|
||||
|
||||
try do
|
||||
configure_dev_config()
|
||||
configure_application()
|
||||
configure_gitignore()
|
||||
rescue
|
||||
err ->
|
||||
err
|
||||
|> Exception.message()
|
||||
|> log_error()
|
||||
end
|
||||
|
||||
Mix.Task.run("format")
|
||||
end
|
||||
|
||||
defp configure_dev_config() do
|
||||
text = ~s"""
|
||||
node: ["build.js", "--watch", cd: Path.expand("../assets", __DIR__)],\
|
||||
"""
|
||||
|
||||
{path, file} = path_and_file("config/", "dev.exs")
|
||||
|
||||
File.read!(path)
|
||||
|> insert(@watcher_regex, text, "'#{text}' in #{file}")
|
||||
|> comment(@esbuild_regex, "old esbuild watcher in #{file}")
|
||||
|> save(path)
|
||||
end
|
||||
|
||||
defp configure_application() do
|
||||
text = ~s"""
|
||||
{NodeJS.Supervisor, [path: LiveSvelte.SSR.NodeJS.server_path(), pool_size: 4]},\
|
||||
"""
|
||||
|
||||
{path, file} = path_and_file("lib/**/", "application.ex")
|
||||
|
||||
File.read!(path)
|
||||
|> insert(@nodejs_regex, text, "'#{text}' in #{file}")
|
||||
|> save(path)
|
||||
end
|
||||
|
||||
defp configure_gitignore() do
|
||||
text = ~s"""
|
||||
|
||||
|
||||
# Ignore automatically generated Svelte files by the ~V sigil
|
||||
/assets/svelte/_build/
|
||||
|
||||
# Ignore ssr build for svelte.
|
||||
/priv/svelte/\
|
||||
"""
|
||||
|
||||
{path, file} = path_and_file("", ".gitignore")
|
||||
|
||||
File.read!(path)
|
||||
|> insert(@gitignore_regex, text, "'#{text}' in #{file}")
|
||||
|> save(path)
|
||||
end
|
||||
|
||||
defp path_and_file(wildcard, filename) do
|
||||
{find_file("#{wildcard}#{filename}", filename), filename}
|
||||
end
|
||||
|
||||
defp find_file(wildcard, file_name) do
|
||||
with [path] <- Path.wildcard(wildcard) do
|
||||
path
|
||||
else
|
||||
[] -> raise "Could not find #{file_name}"
|
||||
[_ | _] -> raise "Found multiple #{file_name} files"
|
||||
end
|
||||
end
|
||||
|
||||
defp insert(source, regex, to_insert, name) do
|
||||
case Regex.run(regex, source, return: :index) do
|
||||
[{pos, len}] ->
|
||||
log_success("Inserted #{name}")
|
||||
insert_position(source, pos + len, to_insert)
|
||||
|
||||
nil ->
|
||||
log_error("Could not insert #{name}, please do so yourself")
|
||||
source
|
||||
end
|
||||
end
|
||||
|
||||
defp comment(source, regex, name) do
|
||||
case Regex.run(regex, source, return: :index) do
|
||||
[{pos, _len}] ->
|
||||
log_success("Commented out #{name}")
|
||||
insert_position(source, pos, "# ")
|
||||
|
||||
nil ->
|
||||
log_warning("Could not comment out #{name}")
|
||||
source
|
||||
end
|
||||
end
|
||||
|
||||
defp insert_position(source, position, to_insert) do
|
||||
{head, tail} = String.split_at(source, position)
|
||||
head <> to_insert <> tail
|
||||
end
|
||||
|
||||
defp save(source, target_file), do: File.write!(target_file, source)
|
||||
end
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
defmodule Mix.Tasks.LiveSvelte.InstallNpmDeps do
|
||||
@moduledoc """
|
||||
Installs npm dependencies for LiveSvelte.
|
||||
"""
|
||||
|
||||
import LiveSvelte.Logger
|
||||
|
||||
def run(_) do
|
||||
log_info("-- Installing npm dependencies...")
|
||||
|
||||
"npm install --prefix ./assets --save-dev esbuild esbuild-svelte svelte svelte-preprocess esbuild-plugin-import-glob &&
|
||||
npm install --prefix ./assets --save ./deps/phoenix ./deps/phoenix_html ./deps/phoenix_live_view ./deps/live_svelte"
|
||||
|> String.to_charlist()
|
||||
|> :os.cmd()
|
||||
|> IO.puts()
|
||||
end
|
||||
end
|
||||
497
lib/mix/tasks/live_svelte.install.ex
Normal file
497
lib/mix/tasks/live_svelte.install.ex
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
defmodule Mix.Tasks.LiveSvelte.Install do
|
||||
@moduledoc """
|
||||
Installer for LiveSvelte with Vite.
|
||||
|
||||
This task first installs Vite using the PhoenixVite installer,
|
||||
then configures the project for LiveSvelte.
|
||||
|
||||
## Options
|
||||
|
||||
* `--bun` - Use Bun instead of Node.js/npm
|
||||
|
||||
## Examples
|
||||
|
||||
mix igniter.install live_svelte
|
||||
mix igniter.install live_svelte --bun
|
||||
|
||||
"""
|
||||
|
||||
import Mix.Tasks.PhoenixVite.Install.Helper
|
||||
|
||||
with_igniter do
|
||||
use Igniter.Mix.Task
|
||||
|
||||
alias Igniter.Libs.Phoenix
|
||||
alias Igniter.Project.Config
|
||||
|
||||
@impl Igniter.Mix.Task
|
||||
def info(_argv, _parent) do
|
||||
%Igniter.Mix.Task.Info{
|
||||
composes: ["phoenix_vite.install"],
|
||||
schema: [bun: :boolean],
|
||||
aliases: [b: :bun]
|
||||
}
|
||||
end
|
||||
|
||||
@impl Igniter.Mix.Task
|
||||
def igniter(igniter) do
|
||||
app_name = Igniter.Project.Application.app_name(igniter)
|
||||
|
||||
igniter
|
||||
|> Igniter.compose_task("phoenix_vite.install", igniter.args.argv)
|
||||
|> configure_environments(app_name)
|
||||
|> add_live_svelte_to_html_helpers(app_name)
|
||||
|> update_javascript_configuration()
|
||||
|> configure_tailwind_for_svelte()
|
||||
|> update_vite_configuration()
|
||||
|> update_package_json_for_svelte()
|
||||
|> create_svelte_files()
|
||||
|> setup_ssr_for_production(app_name)
|
||||
|> update_mix_aliases()
|
||||
|> add_svelte_demo_route()
|
||||
|> update_home_template()
|
||||
|> update_gitignore()
|
||||
|> create_ssr_vite_config()
|
||||
end
|
||||
|
||||
# Configure environments (config.exs, dev.exs, prod.exs)
|
||||
defp configure_environments(igniter, _app_name) do
|
||||
igniter
|
||||
|> Config.configure("config.exs", :live_svelte, [:ssr], true)
|
||||
|> Config.configure("dev.exs", :live_svelte, [:ssr_module], {:code, Sourceror.parse_string!("LiveSvelte.SSR.ViteJS")})
|
||||
|> Config.configure("dev.exs", :live_svelte, [:vite_host], "http://localhost:5173")
|
||||
|> Config.configure("prod.exs", :live_svelte, [:ssr_module], {:code, Sourceror.parse_string!("LiveSvelte.SSR.NodeJS")})
|
||||
|> Config.configure("prod.exs", :live_svelte, [:ssr], true)
|
||||
end
|
||||
|
||||
# Add import LiveSvelte to html_helpers in lib/app_web.ex
|
||||
defp add_live_svelte_to_html_helpers(igniter, _app_name) do
|
||||
web_module = Phoenix.web_module(igniter)
|
||||
web_folder = Macro.underscore(web_module)
|
||||
web_file = Path.join(["lib", web_folder <> ".ex"])
|
||||
|
||||
Igniter.update_file(igniter, web_file, fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
if String.contains?(content, "import LiveSvelte") do
|
||||
content
|
||||
else
|
||||
# Add after the use Gettext or import ...Gettext line in html_helpers
|
||||
web_module_name = web_module |> Module.split() |> Enum.join(".")
|
||||
|
||||
result =
|
||||
String.replace(
|
||||
content,
|
||||
~r/(use Gettext, backend: #{Regex.escape(web_module_name)}\.Gettext)/,
|
||||
"\\1\n\n import LiveSvelte"
|
||||
)
|
||||
|
||||
# Fallback: try matching import ...Gettext pattern
|
||||
if result == content do
|
||||
String.replace(
|
||||
content,
|
||||
~r/(import #{Regex.escape(web_module_name)}\.Gettext)/,
|
||||
"\\1\n\n import LiveSvelte"
|
||||
)
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
# Update app.js to import getHooks and Components from live_svelte
|
||||
defp update_javascript_configuration(igniter) do
|
||||
Igniter.update_file(igniter, "assets/js/app.js", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
content
|
||||
|> add_live_svelte_imports()
|
||||
|> update_live_socket_hooks()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp add_live_svelte_imports(content) do
|
||||
if String.contains?(content, "import {getHooks} from \"live_svelte\"") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
"import topbar from \"topbar\"",
|
||||
~s(import topbar from "topbar"\nimport {getHooks} from "live_svelte"\nimport Components from "virtual:live-svelte-components")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp update_live_socket_hooks(content) do
|
||||
String.replace(
|
||||
content,
|
||||
"hooks: {...colocatedHooks},",
|
||||
"hooks: {...colocatedHooks, ...getHooks(Components)},"
|
||||
)
|
||||
end
|
||||
|
||||
# Configure Tailwind to include Svelte files (add @source "../svelte"; to app.css)
|
||||
defp configure_tailwind_for_svelte(igniter) do
|
||||
if Igniter.exists?(igniter, "assets/css/app.css") do
|
||||
Igniter.update_file(igniter, "assets/css/app.css", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
if String.contains?(content, "@source \"../svelte\";") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
"@source \"../js\";",
|
||||
~s(@source "../js";\n@source "../svelte";)
|
||||
)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
else
|
||||
igniter
|
||||
end
|
||||
end
|
||||
|
||||
# Update vite.config.mjs to add Svelte plugin and liveSveltePlugin
|
||||
defp update_vite_configuration(igniter) do
|
||||
Igniter.update_file(igniter, "assets/vite.config.mjs", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
content
|
||||
|> add_svelte_vite_imports()
|
||||
|> update_vite_optimized_deps()
|
||||
|> update_vite_plugins()
|
||||
|> add_ssr_config()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp add_svelte_vite_imports(content) do
|
||||
if String.contains?(content, "import { svelte }") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
"import { phoenixVitePlugin } from 'phoenix_vite'",
|
||||
~s(import { svelte } from "@sveltejs/vite-plugin-svelte"\nimport liveSveltePlugin from "live_svelte/vitePlugin")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp update_vite_optimized_deps(content) do
|
||||
if String.contains?(content, "\"live_svelte\"") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~s(include: ["phoenix", "phoenix_html", "phoenix_live_view"],),
|
||||
~s(include: ["live_svelte", "phoenix", "phoenix_html", "phoenix_live_view"],)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp update_vite_plugins(content) do
|
||||
if String.contains?(content, "svelte(") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~r/phoenixVitePlugin\(\{\s*pattern: \/\\.\(ex\|heex\)\$\/\s*\}\)/s,
|
||||
"svelte({ compilerOptions: { css: \"injected\" } }),\n liveSveltePlugin({ entrypoint: \"./js/server.js\" })"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp add_ssr_config(content) do
|
||||
if String.contains?(content, "noExternal") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~r/build: \{/s,
|
||||
"ssr: { noExternal: process.env.NODE_ENV === \"production\" ? true : undefined },\n build: {"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Update package.json with Svelte dependencies
|
||||
defp update_package_json_for_svelte(igniter) do
|
||||
igniter
|
||||
|> Igniter.move_file("assets/package.json", "package.json")
|
||||
|> Igniter.update_file("package.json", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
content
|
||||
|> add_svelte_dependency()
|
||||
|> add_svelte_dev_dependencies()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp add_svelte_dependency(content) do
|
||||
if String.contains?(content, "\"live_svelte\"") do
|
||||
content
|
||||
else
|
||||
# Add live_svelte to dependencies section
|
||||
String.replace(
|
||||
content,
|
||||
~s("phoenix": "file:./deps/phoenix"),
|
||||
~s("live_svelte": "file:./deps/live_svelte",\n "phoenix": "file:./deps/phoenix")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp add_svelte_dev_dependencies(content) do
|
||||
if String.contains?(content, "\"@sveltejs/vite-plugin-svelte\"") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~s("typescript":),
|
||||
~s("@sveltejs/vite-plugin-svelte": "^5.0.0",\n "svelte": "^5.0.0",\n "typescript":)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Create Svelte project files
|
||||
defp create_svelte_files(igniter) do
|
||||
web_module = Phoenix.web_module(igniter)
|
||||
web_folder = Macro.underscore(web_module)
|
||||
|
||||
igniter
|
||||
|> Igniter.mkdir("assets/svelte")
|
||||
|> Igniter.mkdir("lib/#{web_folder}/live")
|
||||
|> Igniter.create_new_file("assets/js/server.js", server_js_content())
|
||||
|> Igniter.create_new_file(
|
||||
"assets/svelte/.gitignore",
|
||||
"# Ignore auto-generated Svelte files by ~V sigil\n_build/"
|
||||
)
|
||||
|> Igniter.create_new_file("assets/svelte/SvelteDemo.svelte", demo_svelte_content())
|
||||
|> Igniter.create_new_file(
|
||||
"lib/#{web_folder}/live/svelte_demo_live.ex",
|
||||
demo_live_view_content(igniter)
|
||||
)
|
||||
end
|
||||
|
||||
# Setup NodeJS SSR supervisor in application.ex
|
||||
defp setup_ssr_for_production(igniter, _app_name) do
|
||||
app_module = igniter |> Igniter.Project.Application.app_name() |> to_string()
|
||||
app_file = "lib/#{Macro.underscore(app_module)}/application.ex"
|
||||
|
||||
Igniter.update_file(igniter, app_file, fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
if String.contains?(content, "children = [") and not String.contains?(content, "NodeJS.Supervisor") do
|
||||
String.replace(
|
||||
content,
|
||||
~r/(children = \[\s*\n)/,
|
||||
"\\1 {NodeJS.Supervisor, [path: LiveSvelte.SSR.NodeJS.server_path(), pool_size: 4]},\n"
|
||||
)
|
||||
else
|
||||
content
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
# Update mix.exs aliases in the consumer app to use Vite
|
||||
defp update_mix_aliases(igniter) do
|
||||
bun? = igniter.args.options[:bun] || false
|
||||
pm = if bun?, do: "bunx", else: "npx"
|
||||
|
||||
Igniter.update_file(igniter, "mix.exs", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
if String.contains?(content, "vite build") do
|
||||
content
|
||||
else
|
||||
content
|
||||
|> add_assets_js_alias(pm)
|
||||
|> update_assets_deploy_alias(pm)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp add_assets_js_alias(content, pm) do
|
||||
if String.contains?(content, "\"assets.js\"") do
|
||||
content
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~r/("assets\.setup":)/,
|
||||
~s("assets.js": [\n "cmd --cd assets #{pm} vite build",\n "cmd --cd assets #{pm} vite build --config vite.ssr.config.js",\n "tailwind default"\n ],\n \\1)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp update_assets_deploy_alias(content, pm) do
|
||||
# Replace esbuild references in assets.deploy with Vite commands
|
||||
String.replace(
|
||||
content,
|
||||
~r/"esbuild default[^"]*"/,
|
||||
~s("cmd --cd assets #{pm} vite build --mode production", "cmd --cd assets #{pm} vite build --config vite.ssr.config.js --mode production")
|
||||
)
|
||||
end
|
||||
|
||||
# Add svelte_demo route to router
|
||||
defp add_svelte_demo_route(igniter) do
|
||||
web_module = Phoenix.web_module(igniter)
|
||||
web_folder = Macro.underscore(web_module)
|
||||
web_module_name = web_module |> Module.split() |> Enum.join(".")
|
||||
router_file = Path.join(["lib", web_folder, "router.ex"])
|
||||
|
||||
Igniter.update_file(igniter, router_file, fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
if String.contains?(content, "live \"/svelte_demo\"") do
|
||||
content
|
||||
else
|
||||
if String.contains?(content, "live_dashboard") do
|
||||
String.replace(
|
||||
content,
|
||||
~r/(live_dashboard.*)/,
|
||||
"\\1\n live \"/svelte_demo\", #{web_module_name}.SvelteDemoLive"
|
||||
)
|
||||
else
|
||||
String.replace(
|
||||
content,
|
||||
~r/(pipe_through :browser.*)/,
|
||||
"\\1\n live \"/dev/svelte_demo\", #{web_module_name}.SvelteDemoLive"
|
||||
)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
# Update home template with LiveSvelte info
|
||||
defp update_home_template(igniter) do
|
||||
web_module = Phoenix.web_module(igniter)
|
||||
web_folder = Macro.underscore(web_module)
|
||||
home_template = Path.join(["lib", web_folder, "controllers", "page_html", "home.html.heex"])
|
||||
|
||||
Igniter.update_file(igniter, home_template, fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
content
|
||||
|> String.replace(
|
||||
"Peace of mind from prototype to production.",
|
||||
"End-to-end reactivity for your Live Svelte apps."
|
||||
)
|
||||
|> String.replace(
|
||||
~s(<div class="flex">),
|
||||
~s(<a href={~p"/svelte_demo"} class="btn btn-primary mt-4">Svelte Demo</a>\n <div class="flex">)
|
||||
)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
# Add gitignore entries for Svelte build artifacts
|
||||
defp update_gitignore(igniter) do
|
||||
Igniter.update_file(igniter, ".gitignore", fn source ->
|
||||
Rewrite.Source.update(source, :content, fn content ->
|
||||
content
|
||||
|> add_gitignore_entry("/assets/svelte/_build/")
|
||||
|> add_gitignore_entry("/priv/svelte/")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp add_gitignore_entry(content, entry) do
|
||||
if String.contains?(content, entry) do
|
||||
content
|
||||
else
|
||||
content <> "\n#{entry}"
|
||||
end
|
||||
end
|
||||
|
||||
# Create the SSR Vite config file
|
||||
defp create_ssr_vite_config(igniter) do
|
||||
Igniter.create_new_file(igniter, "assets/vite.ssr.config.js", ssr_vite_config_content())
|
||||
end
|
||||
|
||||
# Content helpers
|
||||
|
||||
defp server_js_content do
|
||||
"""
|
||||
import { getRender } from "live_svelte"
|
||||
import Components from "virtual:live-svelte-components"
|
||||
export const render = getRender(Components)
|
||||
"""
|
||||
end
|
||||
|
||||
defp ssr_vite_config_content do
|
||||
"""
|
||||
import { defineConfig } from "vite"
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
ssr: { noExternal: true },
|
||||
build: {
|
||||
ssr: "./js/server.js",
|
||||
outDir: "../priv/svelte",
|
||||
rollupOptions: {
|
||||
output: { entryFileNames: "server.js", format: "es" }
|
||||
}
|
||||
}
|
||||
})
|
||||
"""
|
||||
end
|
||||
|
||||
defp demo_svelte_content do
|
||||
"""
|
||||
<script>
|
||||
let { count, socket } = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h1>LiveSvelte Demo</h1>
|
||||
<p>Count: {count}</p>
|
||||
<button phx-click="increment">+</button>
|
||||
<button phx-click="decrement">-</button>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp demo_live_view_content(igniter) do
|
||||
web_module_name = Phoenix.web_module(igniter) |> Module.split() |> Enum.join(".")
|
||||
|
||||
"""
|
||||
defmodule #{web_module_name}.SvelteDemoLive do
|
||||
use #{web_module_name}, :live_view
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H\"\"\"
|
||||
<.svelte name="SvelteDemo" props={%{count: @count}} socket={@socket} />
|
||||
\"\"\"
|
||||
end
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, assign(socket, count: 0)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("increment", _params, socket) do
|
||||
{:noreply, update(socket, :count, &(&1 + 1))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("decrement", _params, socket) do
|
||||
{:noreply, update(socket, :count, &(&1 - 1))}
|
||||
end
|
||||
end
|
||||
"""
|
||||
end
|
||||
else
|
||||
use Mix.Task
|
||||
|
||||
@impl Mix.Task
|
||||
def run(_argv) do
|
||||
Mix.shell().error("""
|
||||
The task 'live_svelte.install' requires igniter. Please install igniter and try again.
|
||||
|
||||
For more information, see: https://hexdocs.pm/igniter/readme.html#installation
|
||||
""")
|
||||
|
||||
exit({:shutdown, 1})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
defmodule Mix.Tasks.LiveSvelte.Setup do
|
||||
@moduledoc """
|
||||
Runs all setup tasks for LiveSvelte.
|
||||
"""
|
||||
|
||||
import LiveSvelte.Logger
|
||||
|
||||
def run(_) do
|
||||
[
|
||||
"install_npm_deps",
|
||||
"configure_phoenix",
|
||||
"configure_esbuild"
|
||||
]
|
||||
|> Enum.each(&Mix.Task.run("live_svelte." <> &1))
|
||||
|
||||
log_success("live_svelte setup finished.")
|
||||
end
|
||||
end
|
||||
6
mix.exs
6
mix.exs
|
|
@ -45,7 +45,7 @@ defmodule LiveSvelte.MixProject do
|
|||
GitHub: @repo_url
|
||||
},
|
||||
files:
|
||||
~w(assets/copy assets/js lib mix.exs package.json .formatter.exs LICENSE.md README.md CHANGELOG.md)
|
||||
~w(assets/copy/tsconfig.json assets/js lib mix.exs package.json .formatter.exs LICENSE.md README.md CHANGELOG.md)
|
||||
]
|
||||
end
|
||||
|
||||
|
|
@ -61,6 +61,8 @@ defmodule LiveSvelte.MixProject do
|
|||
defp deps do
|
||||
[
|
||||
{:ex_doc, "~> 0.37.3", only: :dev, runtime: false},
|
||||
{:igniter, "~> 0.6", optional: true},
|
||||
{:phoenix_vite, "~> 0.4"},
|
||||
{:jsonpatch, "~> 2.3"},
|
||||
{:ecto, ">= 3.0.0", optional: true},
|
||||
{:phoenix_ecto, ">= 4.0.0", optional: true},
|
||||
|
|
@ -70,7 +72,7 @@ defmodule LiveSvelte.MixProject do
|
|||
{:telemetry, "~> 0.4 or ~> 1.0"},
|
||||
{:phoenix, ">= 1.7.0"},
|
||||
{:phoenix_html, ">= 3.3.1"},
|
||||
{:phoenix_live_view, ">= 0.18.0"}
|
||||
{:phoenix_live_view, "~> 1.0"}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
40
mix.lock
40
mix.lock
|
|
@ -7,28 +7,42 @@
|
|||
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
|
||||
"esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"},
|
||||
"finch": {:hex, :finch, "0.21.0", "b1c3b2d48af02d0c66d2a9ebfb5622be5c5ecd62937cf79a88a7f98d48a8290c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87dc6e169794cb2570f75841a19da99cfde834249568f2a5b121b809588a4377"},
|
||||
"fine": {:hex, :fine, "0.1.4", "b19a89c1476c7c57afb5f9314aed5960b5bc95d5277de4cb5ee8e1d1616ce379", [:mix], [], "hexpm", "be3324cc454a42d80951cf6023b9954e9ff27c6daa255483b3e8d608670303f5"},
|
||||
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
|
||||
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
|
||||
"igniter": {:hex, :igniter, "0.7.2", "81c132c0df95963c7a228f74a32d3348773743ed9651f24183bfce0fe6ff16d1", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "f4cab73ec31f4fb452de1a17037f8a08826105265aa2d76486fcb848189bef9b"},
|
||||
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||
"jsonpatch": {:hex, :jsonpatch, "2.3.1", "49c380f458debbd2bc6e256daeab1081dc89624288f3d77ea83952229388d316", [:make, :mix], [], "hexpm", "06c3e4fff3574cc54d335041f6322fe1b72756e396dd472615ce350d3dd5e758"},
|
||||
"lazy_html": {:hex, :lazy_html, "0.1.10", "ffe42a0b4e70859cf21a33e12a251e0c76c1dff76391609bd56702a0ef5bc429", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "50f67e5faa09d45a99c1ddf3fac004f051997877dc8974c5797bb5ccd8e27058"},
|
||||
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
|
||||
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.3", "4252d5d4098da7415c390e847c814bad3764c94a814a0b4245176215615e1035", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "953297c02582a33411ac6208f2c6e55f0e870df7f80da724ed613f10e6706afd"},
|
||||
"mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
|
||||
"mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"},
|
||||
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
|
||||
"nodejs": {:hex, :nodejs, "3.1.0", "904c07b81a7b6077af35784df32ab36c62bd2b96edb91bfd04c157c21956cfa5", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1", [hex: :poolboy, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.7", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "a6b4480f3f266abb5927be8afacfc7809feefd7d1337fa3ce957d0b98eeeae52"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.0", "cbed113bdc203e2ced75859011fe7e71eeebb6259cefa54de810d9c7048b5e22", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8526139d4bd79ec97c5c3c8e69f6cd663597f782756cec874ba7da5429c93e34"},
|
||||
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
|
||||
"nodejs": {:hex, :nodejs, "3.1.3", "8693fae9fbefa14fb99329292c226df4d4711acfa5a3fa4182dd8d3f779b30bf", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1", [hex: :poolboy, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.7", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e7751aad77ac55f8e6c5c07617378afd88d2e0c349d9db2ebb5273aae46ef6a9"},
|
||||
"owl": {:hex, :owl, "0.13.0", "26010e066d5992774268f3163506972ddac0a7e77bfe57fa42a250f24d6b876e", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "59bf9d11ce37a4db98f57cb68fbfd61593bf419ec4ed302852b6683d3d2f7475"},
|
||||
"phoenix": {:hex, :phoenix, "1.8.4", "0387f84f00071cba8d71d930b9121b2fb3645197a9206c31b908d2e7902a4851", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c988b1cd3b084eebb13e6676d572597d387fa607dab258526637b4e6c4c08543"},
|
||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.7.0", "75c4b9dfb3efdc42aec2bd5f8bccd978aca0651dbcbc7a3f362ea5d9d43153c6", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "1d75011e4254cb4ddf823e81823a9629559a1be93b4321a6a5f11a5306fbf4cc"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.15", "58137e648fca9da56d6e931c9c3001f895ff090291052035f395bc958b82f1a5", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "888dd8ea986bebbda741acc65aef788c384d13db91fea416461b2e96aa06a193"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.25", "abc1bdf7f148d7f9a003f149834cc858b24290c433b10ef6d1cbb1d6e9a211ca", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b8946e474799da1f874eab7e9ce107502c96ca318ed46d19f811f847df270865"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
||||
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
|
||||
"plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
|
||||
"phoenix_vite": {:hex, :phoenix_vite, "0.4.1", "16fc8b4acc7d4e26fab2bcfb10d125392fcfb5a4ba05dd3aea7f2bec048c5e71", [:mix], [{:bun, ">= 1.5.1 and < 2.0.0-0", [hex: :bun, repo: "hexpm", optional: true]}, {:igniter, "~> 0.6", [hex: :igniter, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "f2bdb1802bc82f2fa93b24606cd25ebdd389bcf2afc55af804f0af3377410f0d"},
|
||||
"plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
|
||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||
"req": {:hex, :req, "0.5.17", "0096ddd5b0ed6f576a03dde4b158a0c727215b15d2795e59e0916c6971066ede", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0b8bc6ffdfebbc07968e59d3ff96d52f2202d0536f10fef4dc11dc02a2a43e39"},
|
||||
"rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"},
|
||||
"sourceror": {:hex, :sourceror, "1.11.0", "df2cdaffdc323e804009ff50b50bb31e6f2d6e116d936ccf22981f592594d624", [:mix], [], "hexpm", "6e26f572bdfc21d7ad397f596b4cfbbf31d7112126fe3e902c120947073231a8"},
|
||||
"spitfire": {:hex, :spitfire, "0.3.8", "4151d539b11eab51903fafcf0eed50d64247ce732fcba24680f5428db406c5f6", [:mix], [], "hexpm", "4328ee4af65d41ea1a7874808e36c1c7fc4a7dafb932f006c07aa1847e0c9dd5"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
||||
"websock": {:hex, :websock, "0.4.3", "184ac396bdcd3dfceb5b74c17d221af659dd559a95b1b92041ecb51c9b728093", [:mix], [], "hexpm", "5e4dd85f305f43fd3d3e25d70bec4a45228dfed60f0f3b072d8eddff335539cf"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.4.5", "30038a3715067f51a9580562c05a3a8d501126030336ffc6edb53bf57d6d2d26", [:mix], [{:bandit, "~> 0.6", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.4", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "1d9812dc7e703c205049426fd4fe0852a247a825f91b099e53dc96f68bafe4c8"},
|
||||
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
|
||||
"text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue