Skip to content

Commit 9ac4e9d

Browse files
committed
Release 0.4.2
1 parent d08b215 commit 9ac4e9d

File tree

6 files changed

+80
-126
lines changed

6 files changed

+80
-126
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,4 @@ volt-*.tar
2626
/node_modules/
2727
/npm.lock
2828

29-
# Generated Tailwind runtime (regenerate with: mix volt.vendor.tailwind)
30-
/priv/tailwind.js
3129

CHANGELOG.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 0.4.2
4+
5+
- Fix fresh installs for Tailwind support by removing the generated `priv/tailwind.js` workflow
6+
- Assemble the Tailwind runtime on first use from the `tailwindcss` package in the `npm_ex` cache
7+
- Bump QuickBEAM to 0.8.0 and npm_ex to 0.5.1
8+
39
## 0.4.1
410

511
### TypeScript Assets
@@ -12,13 +18,10 @@ inline Elixir heredocs to separate TypeScript files in `priv/ts/`.
1218

1319
- `mix volt.js.check` — run oxfmt format check and oxlint via npx
1420
- `mix volt.js.fmt` — format TypeScript assets via npx
15-
- `mix volt.npm` — install JS tooling deps (tailwindcss, etc.) via npm_ex
16-
- `mix volt.vendor.tailwind` — regenerate `priv/tailwind.js` from installed tailwindcss
1721

1822
### Tailwind Vendoring
1923

20-
`priv/tailwind.js` is now generated from the `tailwindcss` npm package by
21-
`mix volt.vendor.tailwind` instead of being maintained by hand. The runtime
24+
The Tailwind runtime is now assembled from the `tailwindcss` npm package at runtime using the npm_ex cache. The runtime
2225
shows a clear error if the file is missing.
2326

2427
### Build Improvements

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ CLI flags override config values for one-off use.
6868
Install maintainer JS tooling when needed:
6969

7070
```bash
71-
mix volt.npm
72-
mix volt.vendor.tailwind
7371
mix volt.js.check
7472
mix volt.js.fmt
7573
```
@@ -242,7 +240,7 @@ Hooks: `resolve/2`, `load/1`, `transform/2`, `render_chunk/2` — all optional.
242240

243241
## Tailwind CSS
244242

245-
Volt compiles Tailwind CSS natively at runtime. The vendored runtime at `priv/tailwind.js` is generated with `mix volt.vendor.tailwind` and should not be edited by hand.
243+
Volt compiles Tailwind CSS natively at runtime and installs the Tailwind compiler into the npm_ex cache on first use.
246244

247245
[Oxide](https://hex.pm/packages/oxide_ex) scans your source files in parallel for candidate class names, then the Tailwind v4 compiler (running in [QuickBEAM](https://hex.pm/packages/quickbeam)) generates the CSS. [LightningCSS](https://hex.pm/packages/vize) handles minification.
248246

lib/mix/tasks/volt.vendor.tailwind.ex

Lines changed: 0 additions & 94 deletions
This file was deleted.

lib/volt/tailwind.ex

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Volt.Tailwind do
2020

2121
use GenServer
2222

23-
defp bundle_path, do: Application.app_dir(:volt, "priv/tailwind.js")
23+
@tailwind_version "^4.2.2"
2424

2525
def start_link(opts \\ []) do
2626
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
@@ -69,7 +69,7 @@ defmodule Volt.Tailwind do
6969
defp ensure_runtime(%{runtime: nil} = state) do
7070
{:ok, rt} = QuickBEAM.start()
7171
{:ok, _} = QuickBEAM.eval(rt, "globalThis.process = {env: {NODE_ENV: 'production'}};")
72-
{:ok, _} = QuickBEAM.eval(rt, read_bundle!())
72+
{:ok, _} = QuickBEAM.eval(rt, runtime_source())
7373

7474
scanner =
7575
if state.sources != [] do
@@ -149,6 +149,7 @@ defmodule Volt.Tailwind do
149149

150150
@impl true
151151
def terminate(_reason, %{runtime: nil}), do: :ok
152+
152153
def terminate(_reason, %{runtime: rt}) do
153154
QuickBEAM.stop(rt)
154155
:ok
@@ -192,25 +193,74 @@ defmodule Volt.Tailwind do
192193
}
193194
end
194195

195-
defp read_bundle! do
196-
path = bundle_path()
197-
198-
case File.read(path) do
199-
{:ok, contents} ->
200-
contents
201-
202-
{:error, :enoent} ->
203-
raise """
204-
Missing generated Tailwind runtime at #{path}.
196+
defp runtime_source do
197+
NPM.install(%{"tailwindcss" => @tailwind_version}, __skip_project_check__: true)
205198

206-
Regenerate it with:
199+
nm_dir = NPM.node_modules_dir!()
200+
tw_dir = Path.join(nm_dir, "tailwindcss")
201+
source = File.read!(Path.join([tw_dir, "dist", "lib.js"]))
202+
theme = File.read!(Path.join(tw_dir, "theme.css"))
203+
preflight = File.read!(Path.join(tw_dir, "preflight.css"))
204+
utilities = File.read!(Path.join(tw_dir, "utilities.css"))
207205

208-
mix volt.npm
209-
mix volt.vendor.tailwind
210-
"""
206+
wrap_runtime(source, theme, preflight, utilities)
207+
end
211208

212-
{:error, reason} ->
213-
raise File.Error, reason: reason, action: "read file", path: path
214-
end
209+
defp wrap_runtime(source, theme, preflight, utilities) do
210+
"""
211+
var TW = (() => {
212+
var module = { exports: {} };
213+
var exports = module.exports;
214+
#{source}
215+
return {
216+
compileCss: async function(inputCss, candidates) {
217+
var css = inputCss == null ? '@import "tailwindcss";' : inputCss;
218+
var compiler = await module.exports.compile(css, {
219+
from: 'app.css',
220+
loadStylesheet: async function(id) {
221+
if (id === 'tailwindcss') {
222+
return {
223+
base: '.',
224+
content: '@import "tailwindcss/theme.css" layer(theme);\\n@import "tailwindcss/preflight.css" layer(base);\\n@import "tailwindcss/utilities.css" layer(utilities);'
225+
};
226+
}
227+
228+
if (id === 'tailwindcss/theme.css') {
229+
return { base: '.', content: module.exports.Features ? requireAsset('theme') : '' };
230+
}
231+
232+
if (id === 'tailwindcss/preflight.css') {
233+
return { base: '.', content: requireAsset('preflight') };
234+
}
235+
236+
if (id === 'tailwindcss/utilities.css') {
237+
return { base: '.', content: requireAsset('utilities') };
238+
}
239+
240+
throw new Error('Unsupported stylesheet: ' + id);
241+
}
242+
});
243+
244+
return compiler.build(candidates || []);
245+
}
246+
};
247+
248+
function requireAsset(kind) {
249+
if (kind === 'theme') {
250+
return #{Jason.encode!(theme)};
251+
}
252+
253+
if (kind === 'preflight') {
254+
return #{Jason.encode!(preflight)};
255+
}
256+
257+
if (kind === 'utilities') {
258+
return #{Jason.encode!(utilities)};
259+
}
260+
261+
return '';
262+
}
263+
})();
264+
"""
215265
end
216266
end

mix.exs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Volt.MixProject do
22
use Mix.Project
33

4-
@version "0.4.1"
4+
@version "0.4.2"
55
@source_url "https://github.com/elixir-volt/volt"
66

77
def project do
@@ -10,7 +10,6 @@ defmodule Volt.MixProject do
1010
version: @version,
1111
elixir: "~> 1.17",
1212
start_permanent: Mix.env() == :prod,
13-
1413
deps: deps(),
1514
aliases: aliases(),
1615
dialyzer: [plt_add_apps: [:mix]],
@@ -61,7 +60,7 @@ defmodule Volt.MixProject do
6160
"ex_dna",
6261
"dialyzer"
6362
],
64-
setup: ["deps.get", "volt.vendor.tailwind"],
63+
setup: ["deps.get"],
6564
ci: ["lint", "cmd MIX_ENV=test mix test"]
6665
]
6766
end
@@ -70,7 +69,7 @@ defmodule Volt.MixProject do
7069
[
7170
licenses: ["MIT"],
7271
links: %{"GitHub" => @source_url},
73-
files: ~w[lib priv/tailwind.js mix.exs README.md LICENSE]
72+
files: ~w[lib mix.exs README.md LICENSE]
7473
]
7574
end
7675

0 commit comments

Comments
 (0)