Packages
phoenix_kit
1.7.43
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/install/js_integration.ex
defmodule PhoenixKit.Install.JsIntegration do
@moduledoc """
Handles automatic JavaScript integration for PhoenixKit installation.
This module provides functionality to:
- Add PhoenixKit JS import for hooks and interactive features
- Update liveSocket hooks configuration automatically
- Ensure idempotent operations (safe to run multiple times)
- Provide fallback instructions if automatic integration fails
## Import Strategy
PhoenixKit JavaScript is imported directly from the deps directory, similar to CSS.
This means updates to PhoenixKit automatically include updated JavaScript without
needing to run `phoenix_kit.update`.
The import path is relative to your app.js location:
- `assets/js/app.js` → `import "../../deps/phoenix_kit/priv/static/assets/phoenix_kit.js"`
- `priv/static/assets/app.js` → `import "../../../deps/phoenix_kit/priv/static/assets/phoenix_kit.js"`
"""
use PhoenixKit.Install.IgniterCompat
@phoenix_kit_js_marker "// PhoenixKit JS - DO NOT REMOVE"
# Import paths based on app.js location
@import_path_from_assets_js "../../deps/phoenix_kit/priv/static/assets/phoenix_kit.js"
@import_path_from_priv_assets "../../../deps/phoenix_kit/priv/static/assets/phoenix_kit.js"
@doc """
Automatically integrates PhoenixKit JavaScript with the parent app's app.js.
## Parameters
- `igniter` - The igniter context
## Returns
Updated igniter with JS integration applied automatically.
"""
def add_automatic_js_integration(igniter) do
js_paths = [
"assets/js/app.js",
"priv/static/assets/app.js"
]
IO.puts("\n🔍 Looking for app.js in: #{inspect(js_paths)}")
case find_app_js(js_paths) do
{:ok, js_path} ->
IO.puts("✅ Found app.js at: #{js_path}")
integrate_js_automatically(igniter, js_path)
{:error, :not_found} ->
IO.puts("❌ app.js not found in any expected location")
add_manual_integration_instructions(igniter)
end
end
@doc """
Checks what PhoenixKit JS integration already exists in content.
Returns a map with detected integrations.
"""
def check_existing_integration(content) do
%{
phoenix_kit_marker: String.contains?(content, @phoenix_kit_js_marker),
phoenix_kit_import: has_phoenix_kit_import?(content),
phoenix_kit_hooks: String.contains?(content, "PhoenixKitHooks")
}
end
# Find the main app.js file in common locations
defp find_app_js(paths) do
case Enum.find(paths, &File.exists?/1) do
nil -> {:error, :not_found}
path -> {:ok, path}
end
end
# Determine the correct import path based on app.js location
defp get_import_path(js_path) do
if String.starts_with?(js_path, "priv/") do
@import_path_from_priv_assets
else
@import_path_from_assets_js
end
end
# Build the full import statement
defp build_import_statement(js_path) do
import_path = get_import_path(js_path)
~s|import "#{import_path}"|
end
# Automatically integrate JS with PhoenixKit requirements
defp integrate_js_automatically(igniter, js_path) do
import_statement = build_import_statement(js_path)
igniter
|> Igniter.update_file(js_path, &add_smart_js_integration(&1, import_statement))
|> add_integration_success_notice(js_path)
rescue
e ->
IO.warn("Failed to automatically integrate JS: #{inspect(e)}")
add_manual_integration_instructions(igniter)
end
# Smart integration that handles all cases within Igniter context
def add_smart_js_integration(source, import_statement \\ nil) do
content = source.content
# First, fix any old vendor-based import paths to use deps
content = fix_old_import_paths(content)
existing = check_existing_integration(content)
if existing.phoenix_kit_marker or existing.phoenix_kit_import do
# Already integrated (with correct path), no changes needed
Rewrite.Source.update(source, :content, content)
else
# Add PhoenixKit JS integration
# Use provided import statement or default to assets/js path
import_stmt = import_statement || ~s|import "#{@import_path_from_assets_js}"|
updated = add_phoenix_kit_js(content, import_stmt)
Rewrite.Source.update(source, :content, updated)
end
end
# Fix old vendor-based import paths to use deps directory
defp fix_old_import_paths(content) do
# Pattern matches old vendor-based imports like:
# import "./vendor/phoenix_kit"
# import "./vendor/phoenix_kit.js"
old_vendor_pattern = ~r/import\s+["'][^"']*vendor\/phoenix_kit[^"']*["']/
# Pattern matches old deps-based imports with wrong paths
old_deps_pattern =
~r/import\s+["'][^"']*deps\/phoenix_kit\/priv\/static\/assets\/phoenix_kit[^"']*["']/
content
|> maybe_replace_pattern(old_vendor_pattern, ~s|import "#{@import_path_from_assets_js}"|)
|> maybe_replace_pattern(old_deps_pattern, ~s|import "#{@import_path_from_assets_js}"|)
end
defp maybe_replace_pattern(content, pattern, replacement) do
if String.match?(content, pattern) do
String.replace(content, pattern, replacement)
else
content
end
end
# Add PhoenixKit JS import and update hooks
defp add_phoenix_kit_js(content, import_statement) do
lines = String.split(content, "\n")
# Find last import line to insert after
last_import_idx = find_last_import_index(lines)
{before, after_lines} = Enum.split(lines, last_import_idx + 1)
import_lines = [
"",
@phoenix_kit_js_marker,
import_statement
]
new_lines = before ++ import_lines ++ after_lines
content_with_import = Enum.join(new_lines, "\n")
# Update hooks in liveSocket if possible
update_livesocket_hooks(content_with_import)
end
# Find the index of the last import statement
defp find_last_import_index(lines) do
lines
|> Enum.with_index()
|> Enum.filter(fn {line, _} -> String.match?(line, ~r/^import\s/) end)
|> List.last()
|> case do
{_, idx} -> idx
nil -> 0
end
end
# Try to add PhoenixKitHooks spread to existing hooks configuration
defp update_livesocket_hooks(content) do
cond do
# Already has PhoenixKitHooks - no changes needed
String.contains?(content, "PhoenixKitHooks") ->
content
# Pattern: hooks: Hooks (simple variable reference)
String.match?(content, ~r/hooks:\s*Hooks[,\s\n}]/) ->
String.replace(
content,
~r/hooks:\s*Hooks([,\s\n}])/,
"hooks: { ...window.PhoenixKitHooks, ...Hooks }\\1"
)
# Pattern: hooks: {} or hooks: { ... } (object literal)
String.match?(content, ~r/hooks:\s*\{/) ->
String.replace(
content,
~r/hooks:\s*\{/,
"hooks: { ...window.PhoenixKitHooks, "
)
# No hooks configuration found - add notice for manual update
true ->
content
end
end
# Check if PhoenixKit import already exists
defp has_phoenix_kit_import?(content) do
phoenix_kit_patterns = [
~r/import\s+["'][^"']*phoenix_kit[^"']*["']/,
~r/import\s+["'][^"']*vendor\/phoenix_kit["']/,
~r/import\s+["'][^"']*deps\/phoenix_kit[^"']*phoenix_kit\.js["']/
]
Enum.any?(phoenix_kit_patterns, &String.match?(content, &1))
end
# Success notice
defp add_integration_success_notice(igniter, js_path) do
import_path = get_import_path(js_path)
notice = """
✅ PhoenixKit JS Integration Complete!
• Updated #{js_path} with PhoenixKit import
• Import path: #{import_path}
• Drag-and-drop and other interactive features are now enabled!
📦 JavaScript updates automatically with package updates (no phoenix_kit.update needed)
"""
Igniter.add_notice(igniter, notice)
end
# Fallback instructions if automatic integration fails
defp add_manual_integration_instructions(igniter) do
notice = """
⚠️ Could not automatically locate app.js file.
Please manually add the following to your app.js (after other imports):
#{@phoenix_kit_js_marker}
import "#{@import_path_from_assets_js}"
Then update your liveSocket hooks:
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { ...window.PhoenixKitHooks, ...Hooks },
// ... other options
})
Common locations: assets/js/app.js, priv/static/assets/app.js
Note: If your app.js is at priv/static/assets/app.js, use:
import "#{@import_path_from_priv_assets}"
"""
Igniter.add_warning(igniter, notice)
end
end