Chen Yu
Chen Yu

Reputation: 4077

How to automatically load the newly compiled module in the other `iex`?

I have opened one bash terminal for compiling. And open another terminal for iex, the open command is iex -S mix.

My before modified code is as follows:

defmodule Mirror.Imports.Product do
  use Ecto.Schema
  import Ecto.Changeset

 def test do
    IO.inspect("hello world")
  end

After compiled, the code is as follows:

 def test do
    IO.inspect("hello world1")
  end

The compile command in the first terminal is as follows:

mix compile

I found in the second iex, the compiled module is not loaded automatically, and I need to close the iex and open it again.

How to configure it to make newly compiled module loaded automatically in all other iex?

mix.exs file is as follows:

defmodule Mirror.MixProject do
  use Mix.Project

  def project do
    [
      app: :mirror,
      version: "0.1.0",
      elixir: "~> 1.12",
      elixirc_paths: elixirc_paths(Mix.env()),
      # compilers: [:gettext] ++ Mix.compilers(),
      compilers: Mix.compilers(),
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps()
    ]
  end

  # Configuration for the OTP application.
  #
  # Type `mix help compile.app` for more information.
  def application do
    [
      mod: {Mirror.Application, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  # Specifies which paths to compile per environment.
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  # Specifies your project dependencies.
  #
  # Type `mix help deps` for examples and options.
  defp deps do
    [
      {:phoenix, "~> 1.6.10"},
      {:phoenix_ecto, "~> 4.4"},
      {:ecto_sql, "~> 3.6"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 3.0"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_view, "~> 0.17.5"},
      # {:floki, ">= 0.30.0", only: :test},
      {:phoenix_live_dashboard, "~> 0.6"},
      {:esbuild, "~> 0.4", runtime: Mix.env() == :dev},
      {:swoosh, "~> 1.3"},
      {:telemetry_metrics, "~> 0.6"},
      {:telemetry_poller, "~> 1.0"},
      {:gettext, "~> 0.18"},
      {:jason, "~> 1.2"},
      {:plug_cowboy, "~> 2.5"},
      {:nimble_csv, "~> 1.2"},
      {:iconv, "~> 1.0"},
      {:floki, "~> 0.33.0"},
      {:html5ever, "~> 0.13.0"},
      {:fast_html, "~> 2.0"}
      #{:csv, "~> 2.5"}
    ]
  end

  # Aliases are shortcuts or tasks specific to the current project.
  # For example, to install project dependencies and perform other setup tasks, run:
  #
  #     $ mix setup
  #
  # See the documentation for `Mix` for more info on aliases.
  defp aliases do
    [
      setup: ["deps.get", "ecto.setup"],
      "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
      "ecto.reset": ["ecto.drop", "ecto.setup"],
      test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
      "assets.deploy": ["esbuild default --minify", "phx.digest"]
    ]
  end
end

Upvotes: 0

Views: 369

Answers (1)

Everett
Everett

Reputation: 9628

Normally when you start up an iex session, it starts up a separate instance of the app (a node), and that means that each node gets its own memory devoted to it. Any changes to one node do not affect the other. Unless you specifically tell the other node to reload a module from disk, it will keep using the version it has loaded into memory. Each instance remains isolated.

The trick here is to log into a SINGLE node from 2 (or more) different iex sessions. The trick is to specify the --remsh option to connect to a remote node.

In one Terminal

Start the iex session and give it a name using the --sname option:

iex --sname conn1 -S mix

The app will start with something like:

Interactive Elixir (1.13.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(conn1@MacBook-Pro)1>

Pay attention to the iex prompt -- it shows you the node name. conn1@MacBook-Pro in this example.

In the second Terminal

You can now connect to the node running in the 1st Terminal window. You have to give this second node a unique name, so you use the --sname option again, but the power is with the --remsh option. Here is where you specify the node name from the 1st Terminal connection:

iex --sname conn2 --remsh conn1@MacBook-Pro

# or... omit the hostname if you're on the same host
iex --sname conn2 --remsh conn1

When you arrive at the iex prompt in this 2nd connection, you will notice that it shows the short name you specified for the 1st connection:

iex(conn1@MacBook-Pro)1>

Now when you do a recompile operation in one window, the 2nd window will also be affected. Why? Because it's the same node underneath... they are using the same memory.

Note that there is still some separation between the 2 iex sessions. You cannot, for example, define a variable in one window and read it in the other -- this is because both iex sessions are running in separate processes. Inspect the output of self() in both windows: they are different. Remember that Elixir maintains strong isolation between processes, so any variable binding that happens remains scoped to the individual processes.

Upvotes: 2

Related Questions