From bc0d1a5bad7a6a98ce4cd89cfad544b5a23210c7 Mon Sep 17 00:00:00 2001 From: Mitchell Hanberg Date: Mon, 7 Jul 2025 06:54:30 -0400 Subject: [PATCH 1/3] feat!: bun, esbuild Adds support for a `--js` option to add a JavaScript bundler. Also changes the CLI flags and adds a default for the template engine (defaults to eex now) --- README.md | 7 +- lib/mix/tasks/tableau.new.ex | 103 ++++++++++++++---- priv/templates/bun/assets/js/site.js | 0 priv/templates/bun/package.json | 12 ++ priv/templates/eex/lib/layouts/root_layout.ex | 3 +- priv/templates/esbuild/assets/js/site.js | 0 .../templates/heex/lib/layouts/root_layout.ex | 3 +- priv/templates/no_assets/extra/js/site.js | 0 priv/templates/primary/config/config.exs | 43 ++++++-- priv/templates/primary/gitignore | 6 +- priv/templates/primary/mix.exs | 8 +- .../temple/lib/layouts/root_layout.ex | 3 +- 12 files changed, 148 insertions(+), 40 deletions(-) create mode 100644 priv/templates/bun/assets/js/site.js create mode 100644 priv/templates/bun/package.json create mode 100644 priv/templates/esbuild/assets/js/site.js create mode 100644 priv/templates/no_assets/extra/js/site.js diff --git a/README.md b/README.md index 30746cf..21919a0 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,14 @@ mix tableau.new [] Flags ---template Template syntax to use. Options are heex, temple, eex. (required) ---assets Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla) +--template Template syntax to use. Options are heex, temple, eex. (optional, defaults to eex) +--js JS bundler to use. Options are vanilla, bun, esbuild (optional, defaults to vanilla) +--css CSS framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla) --help Shows this help text. --version Shows task version. Example mix tableau.new my_awesome_site --template temple -mix tableau.new my_awesome_site --template eex --assets tailwind +mix tableau.new my_awesome_site --template eex --css tailwind ``` diff --git a/lib/mix/tasks/tableau.new.ex b/lib/mix/tasks/tableau.new.ex index 58a181f..0404a1f 100644 --- a/lib/mix/tasks/tableau.new.ex +++ b/lib/mix/tasks/tableau.new.ex @@ -4,15 +4,16 @@ defmodule Mix.Tasks.Tableau.New do Flags - --template Template syntax to use. Options are heex, temple, eex. (required) - --assets Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla) + --template Template syntax to use. Options are heex, temple, eex. (optional, defaults to eex) + --js JS bundler to use. Options are vanilla, bun, esbuild (optional, defaults to vanilla) + --css Asset framework to use. Options are vanilla, tailwind. (optional, defaults to vanilla) --help Shows this help text. --version Shows task version. Example - mix tableau.new my_awesome_site --template temple - mix tableau.new my_awesome_site --template eex --assets tailwind + mix tableau.new my_awesome_site + mix tableau.new my_awesome_site --template temple --js bun --css tailwind """ @moduledoc @help @shortdoc "Generate a new Tableau website" @@ -25,7 +26,8 @@ defmodule Mix.Tasks.Tableau.New do {opts, argv} = OptionParser.parse!(argv, strict: [ - assets: :string, + js: :string, + css: :string, template: :string, help: :boolean, version: :boolean @@ -33,7 +35,7 @@ defmodule Mix.Tasks.Tableau.New do ) opts = - case Keyword.validate(opts, [:assets, :template, help: false, version: false]) do + case Keyword.validate(opts, [:css, :js, :template, help: false, version: false]) do {:ok, opts} -> opts @@ -56,13 +58,21 @@ defmodule Mix.Tasks.Tableau.New do [app | _] = argv Mix.Generator.create_directory(app) - templates = Path.join(:code.priv_dir(:tableau_new), "templates") + templates = :tableau_new |> :code.priv_dir() |> Path.join("templates") + + css = + if opts[:js] == "bun" and opts[:css] == "tailwind" do + "tailwind-bun" + else + opts[:css] + end assigns = [ app: app, app_module: Macro.camelize(app), template: opts[:template], - assets: opts[:assets] + js: opts[:js], + css: css ] Mix.Generator.copy_template( @@ -84,12 +94,17 @@ defmodule Mix.Tasks.Tableau.New do ) Mix.Generator.create_file(Path.join(app, "_pages/.keep"), "") + Mix.Generator.create_file(Path.join(app, "_wip/.keep"), "") + Mix.Generator.create_file(Path.join(app, "_posts/.keep"), "") + Mix.Generator.create_file(Path.join(app, "_draft/.keep"), "") + Mix.Generator.create_file(Path.join(app, "extra/.keep"), "") for source <- Path.wildcard(Path.join(templates, "primary/**/*.{ex,exs}")) do target = - Path.relative_to(source, Path.join(templates, "primary")) + source + |> Path.relative_to(Path.join(templates, "primary")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) @@ -99,7 +114,8 @@ defmodule Mix.Tasks.Tableau.New do "temple" -> for source <- Path.wildcard(Path.join(templates, "temple/**/*.{ex,exs}")) do target = - Path.relative_to(source, Path.join(templates, "temple")) + source + |> Path.relative_to(Path.join(templates, "temple")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) @@ -108,57 +124,98 @@ defmodule Mix.Tasks.Tableau.New do "heex" -> for source <- Path.wildcard(Path.join(templates, "heex/**/*.{ex,exs}")) do target = - Path.relative_to(source, Path.join(templates, "heex")) + source + |> Path.relative_to(Path.join(templates, "heex")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) end - "eex" -> + template when template in ["eex", nil] -> for source <- Path.wildcard(Path.join(templates, "eex/**/*.{ex,exs}")) do target = - Path.relative_to(source, Path.join(templates, "eex")) + source + |> Path.relative_to(Path.join(templates, "eex")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) end - nil -> + value -> Mix.shell().error(""" - The --template option is required. + Unknown template value: --template=#{value} See help text for more information. """) System.halt(1) + end + + case opts[:js] do + "esbuild" -> + for source <- Path.wildcard(Path.join(templates, "esbuild/**/*.{css,js}")) do + target = + source + |> Path.relative_to(Path.join(templates, "esbuild")) + |> String.replace("app_name", app) + + Mix.Generator.copy_template(source, Path.join(app, target), assigns) + end + + "bun" -> + for source <- Path.wildcard(Path.join(templates, "bun/**/*.{css,js,json}")) do + target = + source + |> Path.relative_to(Path.join(templates, "bun")) + |> String.replace("app_name", app) + + Mix.Generator.copy_template(source, Path.join(app, target), assigns) + end + + js when js in ["vanilla", nil] -> + for source <- Path.wildcard(Path.join(templates, "no_assets/**/*.{js}")) do + target = + source + |> Path.relative_to(Path.join(templates, "no_assets")) + |> String.replace("app_name", app) + + Mix.Generator.copy_template(source, Path.join(app, target), assigns) + end + + js -> + Mix.shell().error(""" + Unknown js value: --js=#{js} + + See help text for more information. + """) - _ -> - Mix.shell().error("Unknown template value: --template=#{opts[:template]}") System.halt(1) end - case opts[:assets] do + case opts[:css] do "tailwind" -> for source <- Path.wildcard(Path.join(templates, "tailwind/**/*.{css,js}")) do target = - Path.relative_to(source, Path.join(templates, "tailwind")) + source + |> Path.relative_to(Path.join(templates, "tailwind")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) end - assets when assets in ["vanilla", nil] -> + css when css in ["vanilla", nil] -> for source <- Path.wildcard(Path.join(templates, "no_assets/**/*.{css}")) do target = - Path.relative_to(source, Path.join(templates, "no_assets")) + source + |> Path.relative_to(Path.join(templates, "no_assets")) |> String.replace("app_name", app) Mix.Generator.copy_template(source, Path.join(app, target), assigns) end - _ -> + css -> Mix.shell().error(""" - Unknown assets value: --assets=#{opts[:assets]} + Unknown css value: --css=#{css} See help text for more information. """) diff --git a/priv/templates/bun/assets/js/site.js b/priv/templates/bun/assets/js/site.js new file mode 100644 index 0000000..e69de29 diff --git a/priv/templates/bun/package.json b/priv/templates/bun/package.json new file mode 100644 index 0000000..2bf0a00 --- /dev/null +++ b/priv/templates/bun/package.json @@ -0,0 +1,12 @@ +{ + "name": "<%= @app %>", + "main": "site.js", + "devDependencies": { + "@types/bun": "latest" + }, + "dependencies": {<%= if @css == "tailwind-bun" do %> + "tailwindcss": "^4.1.0", + "@tailwindcss/cli": "^4.1.0", + "@tailwindcss/typography": "^0.5.16"<% end %> + } +} diff --git a/priv/templates/eex/lib/layouts/root_layout.ex b/priv/templates/eex/lib/layouts/root_layout.ex index 19d5a92..99398cf 100644 --- a/priv/templates/eex/lib/layouts/root_layout.ex +++ b/priv/templates/eex/lib/layouts/root_layout.ex @@ -13,13 +13,14 @@ defmodule <%= @app_module %>.RootLayout do - <%%= [@page[:title], <%= @app_module %>] + <%%= [@page[:title], "<%= @app %>"] |> Enum.filter(& &1) |> Enum.intersperse("|") |> Enum.join(" ") %> + diff --git a/priv/templates/esbuild/assets/js/site.js b/priv/templates/esbuild/assets/js/site.js new file mode 100644 index 0000000..e69de29 diff --git a/priv/templates/heex/lib/layouts/root_layout.ex b/priv/templates/heex/lib/layouts/root_layout.ex index 82a5c8a..c5e3d42 100644 --- a/priv/templates/heex/lib/layouts/root_layout.ex +++ b/priv/templates/heex/lib/layouts/root_layout.ex @@ -13,13 +13,14 @@ defmodule <%= @app_module %>.RootLayout do - <%%= [@page[:title], <%= @app_module %>] + <%%= [@page[:title], "<%= @app %>"] |> Enum.filter(& &1) |> Enum.intersperse("|") |> Enum.join(" ") %> +