Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ Add `live_debugger` to your list of dependencies in `mix.exs`:
end
```

For full experience we recommend adding below line to your application root layout. It attaches `meta` tag and LiveDebugger scripts in dev environment enabling browser features and integration with Chrome DevTools Extension.

```elixir
# lib/my_app_web/components/layouts/root.html.heex

<head>
<%= Application.get_env(:live_debugger, :live_debugger_tags) %>
</head>
```

After you start your application LiveDebugger will be running at a default port `http://localhost:4007`.

> [!WARNING]
Expand All @@ -34,23 +44,16 @@ List of browser features:
- Debug button
- Components highlighting (coming soon!)

Some features require injecting JS into the debugged application. To achieve that you need to turn them on in the config and add LiveDebugger scripts to your application root layout.
Some features require injecting JS into the debugged application. You can disable them in your config.

```elixir
# config/dev.exs

config :live_debugger, browser_features?: true
```
# Disables all browser features and does not inject LiveDebugger JS
config :live_debugger, browser_features?: false

```elixir
# lib/my_app_web/components/layouts/root.html.heex

<head>
<%= if Application.get_env(:live_debugger, :browser_features?) do %>
<script id="live-debugger-scripts" src={Application.get_env(:live_debugger, :assets_url)}>
</script>
<% end %>
</head>
# Disables only debug button
config :live_debugger, debug_button?: false
```

### Content Security Policy
Expand All @@ -67,14 +70,14 @@ In `router.ex` of your Phoenix app, make sure your locally running Phoenix app c

## Igniter

LiveDebugger has [Igniter](https://github.com/ash-project/igniter) support - an alternative for standard mix installation. It'll automatically add LiveDebugger scripts to `root.html.heex` and enable browser features in your `config/dev.exs` after you use the below command.

Make sure that added dependency is `:dev` only.
LiveDebugger has [Igniter](https://github.com/ash-project/igniter) support - an alternative for standard mix installation. It'll automatically add LiveDebugger dependency and modify your `root.html.heex` after you use the below command.

```bash
mix igniter.install live_debugger
```

Make sure that added dependency is `:dev` only.

## Optional configuration

```elixir
Expand Down
53 changes: 41 additions & 12 deletions assets/js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,42 @@ function getSessionId() {
}
}

function handleMetaTagError() {
const message = `
LiveDebugger meta tag not found!
If you have recently bumped LiveDebugger version, please update your layout according to the instructions in the GitHub README.
You can find it here: https://github.com/software-mansion/live-debugger#installation
`;

throw new Error(message);
}

function debugButtonEnabled() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.hasAttribute('debug-button');
} else {
handleMetaTagError();
}
}

function highlightingEnabled() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.hasAttribute('highlighting');
}
}

function getLiveDebuggerBaseURL() {
return document
.getElementById('live-debugger-scripts')
.src.replace('/assets/live_debugger/client.js', '');
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.getAttribute('url');
} else {
handleMetaTagError();
}
}

function getSessionURL(baseURL) {
Expand All @@ -31,20 +63,17 @@ function getSessionURL(baseURL) {
return `${baseURL}/${session_path}`;
}

window.getLiveDebuggerURL = function () {
const baseURL = getLiveDebuggerBaseURL();
const sessionURL = getSessionURL(baseURL);

return sessionURL;
};

window.document.addEventListener('DOMContentLoaded', function () {
const baseURL = getLiveDebuggerBaseURL();
const sessionURL = getSessionURL(baseURL);

initDebugButton(sessionURL);
if (debugButtonEnabled()) {
initDebugButton(sessionURL);
}

initHighlight();
if (highlightingEnabled()) {
initHighlight();
}

// Finalize
console.info(`LiveDebugger available at: ${baseURL}`);
Expand Down
3 changes: 0 additions & 3 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ if config_env() == :dev do
]
]

config :live_debugger, server: true

config :live_debugger, browser_features?: true
config :live_debugger, experimental_features: :all
end

Expand Down
5 changes: 1 addition & 4 deletions dev/layout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ defmodule LiveDebuggerDev.Layout do
</script>
<script src="/assets/phoenix_live_view/phoenix_live_view.js">
</script>
<%= if Application.get_env(:live_debugger, :browser_features?) do %>
<script id="live-debugger-scripts" src={Application.get_env(:live_debugger, :assets_url)}>
</script>
<% end %>
<%= Application.get_env(:live_debugger, :live_debugger_tags) %>
<script>
// Set global hooks and uploaders objects to be used by the LiveSocket,
// so they can be overwritten in user provided templates.
Expand Down
53 changes: 45 additions & 8 deletions devtools/devtools.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,52 @@
function getLiveDebuggerSessionURL() {
return new Promise((resolve, reject) => {
chrome.devtools.inspectedWindow.eval(
"getLiveDebuggerURL()",
(result, isException) => {
if (isException) {
reject(isException);
} else {
resolve(result);
const script = `
(function() {
function getSessionId() {
let el;
if ((el = document.querySelector('[data-phx-main]'))) {
return el.id;
}
if ((el = document.querySelector('[id^="phx-"]'))) {
return el.id;
}
if ((el = document.querySelector('[data-phx-root-id]'))) {
return el.getAttribute('data-phx-root-id');
}
return null;
}

function handleMetaTagError() {
throw new Error("LiveDebugger meta tag not found!");
}

function getLiveDebuggerBaseURL() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');
if (metaTag) {
return metaTag.getAttribute('url');
} else {
handleMetaTagError();
}
}

function getSessionURL(baseURL) {
const session_id = getSessionId();
const session_path = session_id ? \`transport_pid/\${session_id}\` : '';
return \`\${baseURL}/\${session_path}\`;
}

const baseURL = getLiveDebuggerBaseURL();
return getSessionURL(baseURL);
})();
`;

chrome.devtools.inspectedWindow.eval(script, (result, isException) => {
if (isException || !result) {
reject(new Error("Error fetching LiveDebugger session URL"));
} else {
resolve(result);
}
);
});
});
}

Expand Down
23 changes: 19 additions & 4 deletions devtools/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<style>
body {
margin: 0;
background-color: rgb(241 245 249);
background-color: #f1f5f9;
}
iframe {
border: none;
Expand All @@ -21,7 +21,7 @@
#error-info svg {
width: 48px;
height: 48px;
color: rgb(76 43 138);
color: #ef4444;
}
#error-info div {
font-weight: 600;
Expand All @@ -33,6 +33,14 @@
max-width: 70%;
margin: 0;
}
a {
color: #001a72;
text-decoration: none;
}
a:hover {
color: #33498b;
text-decoration: none;
}
</style>
</head>
<body>
Expand All @@ -59,8 +67,15 @@
</svg>
<div>Debugger disconnected</div>
<p>
Couldn't find url. Ensure you've turned on browser features in the
config and added LiveDebugger scripts to your application root layout.
Couldn't find LiveDebugger url - please update your root layout
according to the instructions in the GitHub README.
<br />
You can find it
<a
target="_blank"
href="https://github.com/software-mansion/live-debugger#installation"
>here</a
>
</p>
</div>

Expand Down
59 changes: 42 additions & 17 deletions lib/live_debugger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,8 @@ defmodule LiveDebugger do
def start(_type, _args) do
config = Application.get_all_env(@app_name)

default_adapter = default_adapter()
ip = Keyword.get(config, :ip, @default_ip)
ip_string = ip |> :inet.ntoa() |> List.to_string()
port = Keyword.get(config, :port, @default_port)

endpoint_config =
[
http: [ip: ip, port: port],
secret_key_base: Keyword.get(config, :secret_key_base, @default_secret_key_base),
live_view: [signing_salt: Keyword.get(config, :signing_salt, @default_signing_salt)],
adapter: Keyword.get(config, :adapter, default_adapter),
live_reload: Keyword.get(config, :live_reload, []),
server: Keyword.get(config, :server, false)
]

Application.put_env(@app_name, LiveDebugger.Endpoint, endpoint_config)
Application.put_env(@app_name, :assets_url, "http://#{ip_string}:#{port}/#{@assets_path}")
put_endpoint_config(config)
put_live_debugger_tags(config)

children = [
{Phoenix.PubSub, name: LiveDebugger.PubSub},
Expand Down Expand Up @@ -62,4 +47,44 @@ defmodule LiveDebugger do
{:error, _} -> Phoenix.Endpoint.Cowboy2Adapter
end
end

defp put_endpoint_config(config) do
endpoint_config =
[
http: [
ip: Keyword.get(config, :ip, @default_ip),
port: Keyword.get(config, :port, @default_port)
],
secret_key_base: Keyword.get(config, :secret_key_base, @default_secret_key_base),
live_view: [signing_salt: Keyword.get(config, :signing_salt, @default_signing_salt)],
adapter: Keyword.get(config, :adapter, default_adapter()),
live_reload: Keyword.get(config, :live_reload, []),
server: true
]

Application.put_env(@app_name, LiveDebugger.Endpoint, endpoint_config)
end

defp put_live_debugger_tags(config) do
ip_string = config |> Keyword.get(:ip, @default_ip) |> :inet.ntoa() |> List.to_string()
port = Keyword.get(config, :port, @default_port)

browser_features? = Keyword.get(config, :browser_features?, true)
debug_button? = Keyword.get(config, :debug_button?, true)
highlighting? = Keyword.get(config, :highlighting?, true)

live_debugger_url = "http://#{ip_string}:#{port}"
live_debugger_assets_url = "http://#{ip_string}:#{port}/#{@assets_path}"

assigns = %{
url: live_debugger_url,
assets_url: live_debugger_assets_url,
browser_features?: browser_features?,
debug_button?: debug_button?,
highlighting?: highlighting?
}

tags = LiveDebugger.Components.Config.live_debugger_tags(assigns)
Application.put_env(@app_name, :live_debugger_tags, tags)
end
end
29 changes: 29 additions & 0 deletions lib/live_debugger/components/config.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule LiveDebugger.Components.Config do
@moduledoc """
Renders the LiveDebugger config meta tag and the browser features script.
It is meant to be injected to the debugged application layout.
"""

use Phoenix.Component

attr(:url, :string, required: true)
attr(:assets_url, :string, required: true)
attr(:browser_features?, :boolean, default: true)
attr(:debug_button?, :boolean, default: true)
attr(:highlighting?, :boolean, default: true)

def live_debugger_tags(assigns) do
~H"""
<meta
name="live-debugger-config"
url={@url}
debug-button={@debug_button?}
highlighting={@highlighting?}
/>
<%= if @browser_features? do %>
<script src={@assets_url}>
</script>
<% end %>
"""
end
end
2 changes: 1 addition & 1 deletion lib/live_debugger/components/tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule LiveDebugger.Components.Tree do
<div class={["w-full overflow-y-auto flex flex-col", @class]}>
<div class="flex items-center justify-between">
<div class="shrink-0 font-medium text-secondary-text px-6 py-3"><%= @title %></div>
<%= if Application.get_env(:live_debugger, :browser_features?) && LiveDebugger.Feature.enabled?(:highlighting) do %>
<%= if LiveDebugger.Feature.enabled?(:highlighting) do %>
<.toggle_switch label="Highlight" checked={@highlight?} phx-click="toggle-highlight" />
<% end %>
</div>
Expand Down
Loading