Skip to content

Commit

Permalink
update tailwind mentions, docs & remove code
Browse files Browse the repository at this point in the history
  • Loading branch information
sheerlox committed Nov 24, 2023
1 parent 57be4cb commit 30d708c
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 253 deletions.
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Config

config :nodelix,
version: "3.2.7",
version: "20.10.0",
another: [
args: ["--help"]
]
17 changes: 7 additions & 10 deletions lib/mix/tasks/nodelix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,32 @@ defmodule Mix.Tasks.Nodelix do
use Mix.Task

@moduledoc """
Invokes tailwind with the given args.
Invokes `node` with the given args.
Usage:
$ mix nodelix TASK_OPTIONS PROFILE TAILWIND_ARGS
$ mix nodelix TASK_OPTIONS PROFILE NODE_ARGS
Example:
$ mix nodelix default --config=tailwind.config.js \
--input=css/app.css \
--output=../priv/static/assets/app.css \
--minify
$ mix nodelix default --tls-min-v1.3
If tailwind is not installed, it is automatically downloaded.
Note the arguments given to this task will be appended
If Node.js is not installed, it is automatically downloaded.
The arguments given to this task will be appended
to any configured arguments.
## Options
* `--runtime-config` - load the runtime configuration
before executing command
Note flags to control this Mix task must be given before the
Flags to control this Mix task must be given before the
profile:
$ mix nodelix --runtime-config default
"""

@shortdoc "Invokes tailwind with the profile and args"
@shortdoc "Invokes node with the profile and args"
@compile {:no_warn_undefined, Mix}

@impl true
Expand Down
106 changes: 11 additions & 95 deletions lib/mix/tasks/nodelix.install.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
defmodule Mix.Tasks.Nodelix.Install do
use Mix.Task

alias Nodelix.NodeManager
alias Nodelix.NodeDownloader

@moduledoc """
Installs Tailwind executable and assets.
Installs Node.js.
$ mix nodelix.install
$ mix nodelix.install --if-missing
By default, it installs #{NodeManager.latest_version()} but you
By default, it installs #{NodeDownloader.latest_lts_version()} but you
can configure it in your config files, such as:
config :nodelix, :version, "#{NodeManager.latest_version()}"
config :nodelix, :version, "#{NodeDownloader.latest_lts_version()}"
## Options
Expand All @@ -21,30 +21,9 @@ defmodule Mix.Tasks.Nodelix.Install do
* `--if-missing` - install only if the given version
does not exist
* `--no-assets` - does not install Tailwind assets
## Assets
Whenever Tailwind is installed, a default tailwind configuration
will be placed in a new `assets/tailwind.config.js` file. See
the [tailwind documentation](https://tailwindcss.com/docs/configuration)
on configuration options.
The default tailwind configuration includes Tailwind variants for Phoenix
LiveView specific lifecycle classes:
* phx-no-feedback - applied when feedback should be hidden from the user
* phx-click-loading - applied when an event is sent to the server on click
while the client awaits the server response
* phx-submit-loading - applied when a form is submitted while the client awaits the server response
* phx-submit-loading - applied when a form input is changed while the client awaits the server response
Therefore, you may apply a variant, such as `phx-click-loading:animate-pulse`
to customize tailwind classes when Phoenix LiveView classes are applied.
"""

@shortdoc "Installs Tailwind executable and assets"
@shortdoc "Installs Node.js"
@compile {:no_warn_undefined, Mix}

@impl true
Expand All @@ -54,7 +33,7 @@ defmodule Mix.Tasks.Nodelix.Install do
{opts, base_url} =
case OptionParser.parse_head!(args, strict: valid_options) do
{opts, []} ->
{opts, NodeManager.default_base_url()}
{opts, NodeDownloader.default_base_url()}

{opts, [base_url]} ->
{opts, base_url}
Expand All @@ -64,92 +43,29 @@ defmodule Mix.Tasks.Nodelix.Install do
Invalid arguments to nodelix.install, expected one of:
mix nodelix.install
mix nodelix.install 'https://github.com/tailwindlabs/tailwindcss/releases/download/v$version/tailwindcss-$target'
mix nodelix.install 'https://nodejs.org/dist/v$version/node-v$version-$target'
mix nodelix.install --runtime-config
mix nodelix.install --if-missing
""")
end

if opts[:runtime_config], do: Mix.Task.run("app.config")

if opts[:if_missing] && latest_version?() do
if opts[:if_missing] && latest_lts_version?() do
:ok
else
if Keyword.get(opts, :assets, true) do
File.mkdir_p!("assets/css")
tailwind_config_path = Path.expand("assets/tailwind.config.js")

prepare_app_css()
prepare_app_js()

unless File.exists?(tailwind_config_path) do
File.write!(tailwind_config_path, """
// See the Tailwind configuration guide for advanced usage
// https://tailwindcss.com/docs/configuration
let plugin = require('tailwindcss/plugin')
module.exports = {
content: [
'./js/**/*.js',
'../lib/*_web.ex',
'../lib/*_web/**/*.*ex'
],
theme: {
extend: {},
},
plugins: [
require('@tailwindcss/forms'),
plugin(({addVariant}) => addVariant('phx-no-feedback', ['&.phx-no-feedback', '.phx-no-feedback &'])),
plugin(({addVariant}) => addVariant('phx-click-loading', ['&.phx-click-loading', '.phx-click-loading &'])),
plugin(({addVariant}) => addVariant('phx-submit-loading', ['&.phx-submit-loading', '.phx-submit-loading &'])),
plugin(({addVariant}) => addVariant('phx-change-loading', ['&.phx-change-loading', '.phx-change-loading &']))
]
}
""")
end
end

if function_exported?(Mix, :ensure_application!, 1) do
Mix.ensure_application!(:inets)
Mix.ensure_application!(:ssl)
end

Mix.Task.run("loadpaths")
NodeManager.install(base_url)
NodeDownloader.install(base_url)
end
end

defp latest_version?() do
defp latest_lts_version?() do
version = Nodelix.configured_version()
match?({:ok, ^version}, NodeManager.bin_version())
end

defp prepare_app_css do
app_css =
case File.read("assets/css/app.css") do
{:ok, str} -> str
{:error, _} -> ""
end

unless app_css =~ "tailwind" do
File.write!("assets/css/app.css", """
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
#{String.replace(app_css, ~s|@import "./phoenix.css";\n|, "")}\
""")
end
end

defp prepare_app_js do
case File.read("assets/js/app.js") do
{:ok, app_js} ->
File.write!("assets/js/app.js", String.replace(app_js, ~s|import "../css/app.css"\n|, ""))

{:error, _} ->
:ok
end
match?({:ok, ^version}, NodeDownloader.bin_version())
end
end
74 changes: 20 additions & 54 deletions lib/nodelix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,56 @@ defmodule Nodelix do
use Application
require Logger

alias Nodelix.NodeManager
alias Nodelix.NodeDownloader

@moduledoc """
Nodelix is an installer and runner for [tailwind](https://tailwindcss.com/).
Nodelix is an installer and runner for [Node.js](https://nodejs.org/).
## Profiles
You can define multiple tailwind profiles. By default, there is a
You can define multiple nodelix profiles. By default, there is a
profile called `:default` which you can configure its args, current
directory and environment:
config :nodelix,
version: "#{NodeManager.latest_version()}",
version: "#{NodeDownloader.latest_lts_version()}",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
--version
),
cd: Path.expand("../assets", __DIR__),
]
## Nodelix configuration
There are two global configurations for the tailwind application:
There are two global configurations for the nodelix application:
* `:version` - the expected tailwind version
* `:version` - the expected Node.js version
* `:cacerts_path` - the directory to find certificates for
https connections
* `:path` - the path to find the tailwind executable at. By
default, it is automatically downloaded and placed inside
the `_build` directory of your current app
Overriding the `:path` is not recommended, as we will automatically
download and manage `tailwind` for you. But in case you can't download
it (for example, GitHub behind a proxy), you may want to
set the `:path` to a configurable system location.
For instance, you can install `tailwind` globally with `npm`:
$ npm install -g tailwindcss
On Unix, the executable will be at:
NPM_ROOT/tailwind/node_modules/tailwind-TARGET/bin/tailwind
On Windows, it will be at:
NPM_ROOT/tailwind/node_modules/tailwind-windows-(32|64)/tailwind.exe
Where `NPM_ROOT` is the result of `npm root -g` and `TARGET` is your system
target architecture.
Once you find the location of the executable, you can store it in a
`MIX_TAILWIND_PATH` environment variable, which you can then read in
your configuration file:
config :nodelix, path: System.get_env("MIX_TAILWIND_PATH")
"""

@doc false
def start(_, _) do
unless Application.get_env(:nodelix, :version) do
Logger.warn("""
tailwind version is not configured. Please set it in your config files:
Node.js version is not configured. Please set it in your config files:
config :nodelix, :version, "#{NodeManager.latest_version()}"
config :nodelix, :version, "#{NodeDownloader.latest_lts_version()}"
""")
end

configured_version = configured_version()

case NodeManager.bin_version() do
case NodeDownloader.bin_version() do
{:ok, ^configured_version} ->
:ok

{:ok, version} ->
Logger.warn("""
Outdated tailwind version. Expected #{configured_version}, got #{version}. \
Outdated Node.js version. Expected #{configured_version}, got #{version}. \
Please run `mix nodelix.install` or update the version in your config files.\
""")

Expand All @@ -95,10 +63,10 @@ defmodule Nodelix do
end

@doc """
Returns the configured tailwind version.
Returns the configured Node.js version.
"""
def configured_version do
Application.get_env(:nodelix, :version, NodeManager.latest_version())
Application.get_env(:nodelix, :version, NodeDownloader.latest_lts_version())
end

@doc """
Expand All @@ -109,15 +77,13 @@ defmodule Nodelix do
def config_for!(profile) when is_atom(profile) do
Application.get_env(:nodelix, profile) ||
raise ArgumentError, """
unknown tailwind profile. Make sure the profile is defined in your config/config.exs file, such as:
unknown nodelix profile. Make sure the profile is defined in your config/config.exs file, such as:
config :nodelix,
version: "#{NodeManager.latest_version()}",
version: "#{NodeDownloader.latest_lts_version()}",
#{profile}: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
--version
),
cd: Path.expand("../assets", __DIR__)
]
Expand Down Expand Up @@ -147,7 +113,7 @@ defmodule Nodelix do
stderr_to_stdout: true
]

NodeManager.bin_path()
NodeDownloader.bin_path()
|> System.cmd(args ++ extra_args, opts)
|> elem(1)
end
Expand All @@ -157,13 +123,13 @@ defmodule Nodelix do
end

@doc """
Installs, if not available, and then runs `tailwind`.
Installs, if not available, and then runs `node`.
Returns the same as `run/2`.
"""
def install_and_run(profile, args) do
unless File.exists?(NodeManager.bin_path()) do
NodeManager.install()
unless File.exists?(NodeDownloader.bin_path()) do
NodeDownloader.install()
end

run(profile, args)
Expand Down
Loading

0 comments on commit 30d708c

Please sign in to comment.