Simplify asset building (#3459)

* Add tailwind and esbuild

* Remove unused images

* Move unprocessed assets to priv directory

* Fix applyTheme script

* Remove autoprefixer

* Update bundlemon

* Remove babel config

* Revert "Remove autoprefixer"

This reverts commit fc60c31c73.

* Make dashboard react file work

* Fix app.css imports

* Remove autoprefixer

* Add back in robots.txt

* Go back to css/ and js/ folders as opposed to assets/

* Bundle embed.host.js and embed.content.js

* Add components folder to live reload paths

* Remove bundlemon

* Use mix assets task in Dockerfil

* Add assets setup to CONTRIBUTING.md
This commit is contained in:
Uku Taht 2023-11-01 16:27:29 +02:00 committed by GitHub
parent 463697661c
commit cfe81d6d3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 737 additions and 12437 deletions

View File

@ -28,10 +28,4 @@ jobs:
- run: npm install --prefix ./tracker - run: npm install --prefix ./tracker
- run: npm run lint --prefix ./assets - run: npm run lint --prefix ./assets
- run: npm run check-format --prefix ./assets - run: npm run check-format --prefix ./assets
- run: npm run deploy --prefix ./assets
- run: npm run deploy --prefix ./tracker - run: npm run deploy --prefix ./tracker
- name: Run BundleMon
run: npm run bundlemon --prefix ./assets
env:
BUNDLEMON_PROJECT_ID: "619e0b6ad4a54a00089861ac"
CI_COMMIT_SHA: ${{github.event.pull_request.head.sha || github.sha}} # important!

3
.gitignore vendored
View File

@ -35,7 +35,8 @@ npm-debug.log
# Since we are building assets from assets/, # Since we are building assets from assets/,
# we ignore priv/static. You may want to comment # we ignore priv/static. You may want to comment
# this depending on your deployment strategy. # this depending on your deployment strategy.
/priv/static/ /priv/static/css
/priv/static/js
/priv/version.json /priv/version.json
# Files matching config/*.secret.exs pattern contain sensitive # Files matching config/*.secret.exs pattern contain sensitive

View File

@ -18,8 +18,9 @@ Make sure Docker, Elixir, Erlang and Node.js are all installed on your developme
4. Run `mix run priv/repo/seeds.exs` to seed the database. Check the [Seeds](#Seeds) section for more. 4. Run `mix run priv/repo/seeds.exs` to seed the database. Check the [Seeds](#Seeds) section for more.
5. Run `npm ci --prefix assets` to install the required client-side dependencies. 5. Run `npm ci --prefix assets` to install the required client-side dependencies.
6. Run `npm ci --prefix tracker` to install the required tracker dependencies. 6. Run `npm ci --prefix tracker` to install the required tracker dependencies.
7. Run `npm run deploy --prefix tracker` to generate tracker files in `priv/tracker/js` 7. Run `mix assets.setup` to install Tailwind and Esbuild
8. Run `mix download_country_database` to fetch geolocation database 8. Run `npm run deploy --prefix tracker` to generate tracker files in `priv/tracker/js`
9. Run `mix download_country_database` to fetch geolocation database
3. Run `make server` or `mix phx.server` to start the Phoenix server. 3. Run `make server` or `mix phx.server` to start the Phoenix server.
4. The system is now available on `localhost:8000`. 4. The system is now available on `localhost:8000`.

View File

@ -19,8 +19,7 @@ WORKDIR /app
# install build dependencies # install build dependencies
RUN apk add --no-cache git nodejs yarn python3 npm ca-certificates wget gnupg make gcc libc-dev && \ RUN apk add --no-cache git nodejs yarn python3 npm ca-certificates wget gnupg make gcc libc-dev && \
npm install npm@latest -g && \ npm install npm@latest -g
npm install -g webpack
COPY mix.exs ./ COPY mix.exs ./
COPY mix.lock ./ COPY mix.lock ./
@ -41,8 +40,8 @@ COPY tracker ./tracker
COPY priv ./priv COPY priv ./priv
COPY lib ./lib COPY lib ./lib
RUN npm run deploy --prefix ./assets && \ RUN npm run deploy --prefix ./tracker && \
npm run deploy --prefix ./tracker && \ mix assets.deploy && \
mix phx.digest priv/static && \ mix phx.digest priv/static && \
mix download_country_database && \ mix download_country_database && \
# https://hexdocs.pm/sentry/Sentry.Sources.html#module-source-code-storage # https://hexdocs.pm/sentry/Sentry.Sources.html#module-source-code-storage

View File

@ -1,6 +0,0 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}

View File

@ -1,15 +0,0 @@
{
"baseDir": "../priv/",
"reportOutput": ["github"],
"files": [
{
"path": "static/js/*.js"
},
{
"path": "static/css/app.css"
},
{
"path": "tracker/js/plausible.js"
}
]
}

View File

@ -1,12 +1,11 @@
/* purgecss start ignore */ @import "tailwindcss/base";
@tailwind base; @import "flatpickr/dist/flatpickr.min.css";
@tailwind components; @import "./modal.css";
@import "./loader.css";
/* purgecss end ignore */ @import "./tooltip.css";
@import "modal.css"; @import "./flatpickr.css";
@import "loader.css"; @import "tailwindcss/components";
@import "tooltip.css"; @import "tailwindcss/utilities";
@import "flatpickr.css";
[x-cloak] { display: none; } [x-cloak] { display: none; }
@ -65,8 +64,6 @@ blockquote {
} }
} }
@tailwind utilities;
.light-text { .light-text {
color: #F0F4F8; color: #F0F4F8;

View File

@ -1,6 +1,5 @@
import "../css/app.css"
import "flatpickr/dist/flatpickr.min.css"
import "./polyfills/closest" import "./polyfills/closest"
import "./apply-theme"
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch' import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
import Alpine from 'alpinejs' import Alpine from 'alpinejs'
import "./liveview/live_socket" import "./liveview/live_socket"

View File

@ -2,10 +2,10 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import 'url-search-params-polyfill'; import 'url-search-params-polyfill';
import Router from './router' import Router from './dashboard/router'
import ErrorBoundary from './error-boundary' import ErrorBoundary from './dashboard/error-boundary'
import * as api from './api' import * as api from './dashboard/api'
import * as timer from './util/realtime-update-timer' import * as timer from './dashboard/util/realtime-update-timer'
timer.start() timer.start()

View File

@ -12,7 +12,7 @@ import Devices from './stats/devices'
import Behaviours from './stats/behaviours' import Behaviours from './stats/behaviours'
import ComparisonInput from './comparison-input' import ComparisonInput from './comparison-input'
import { withPinnedHeader } from './pinned-header-hoc'; import { withPinnedHeader } from './pinned-header-hoc';
import { statsBoxClass } from '.'; import { statsBoxClass } from './index';
function Historical(props) { function Historical(props) {
const tooltipBoundary = React.useRef(null) const tooltipBoundary = React.useRef(null)

View File

@ -10,7 +10,7 @@ import Locations from './stats/locations'
import Devices from './stats/devices' import Devices from './stats/devices'
import Behaviours from './stats/behaviours' import Behaviours from './stats/behaviours'
import { withPinnedHeader } from './pinned-header-hoc'; import { withPinnedHeader } from './pinned-header-hoc';
import { statsBoxClass } from '.'; import { statsBoxClass } from './index';
class Realtime extends React.Component { class Realtime extends React.Component {
render() { render() {

12955
assets/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,12 @@
"version": "1.4.0", "version": "1.4.0",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"scripts": { "scripts": {
"deploy": "webpack --mode production",
"watch": "webpack --mode development --watch",
"format": "prettier --write {css,js}/**", "format": "prettier --write {css,js}/**",
"check-format": "prettier --check {css,js}/**", "check-format": "prettier --check {css,js}/**",
"lint": "eslint js/**", "lint": "eslint js/**",
"bundlemon": "bundlemon" "bundlemon": "bundlemon"
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.4",
"@babel/preset-react": "^7.13.13",
"@headlessui/react": "^1.7.10", "@headlessui/react": "^1.7.10",
"@heroicons/react": "^2.0.11", "@heroicons/react": "^2.0.11",
"@juggle/resize-observer": "^3.3.1", "@juggle/resize-observer": "^3.3.1",
@ -24,24 +19,16 @@
"@tailwindcss/typography": "^0.4.1", "@tailwindcss/typography": "^0.4.1",
"abortcontroller-polyfill": "^1.7.3", "abortcontroller-polyfill": "^1.7.3",
"alpinejs": "^3.13.1", "alpinejs": "^3.13.1",
"autoprefixer": "^10.4.15",
"babel-loader": "^8.2.2",
"chart.js": "^3.3.2", "chart.js": "^3.3.2",
"chartjs-plugin-datalabels": "^2.2.0", "chartjs-plugin-datalabels": "^2.2.0",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"copy-webpack-plugin": "^9.0.0",
"css-loader": "^5.2.6",
"css-minimizer-webpack-plugin": "^3.2.0",
"datamaps": "^0.5.9", "datamaps": "^0.5.9",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"iframe-resizer": "^4.3.2", "iframe-resizer": "^4.3.2",
"mini-css-extract-plugin": "^1.6.0",
"phoenix": "^1.7.2", "phoenix": "^1.7.2",
"phoenix_html": "^3.3.1", "phoenix_html": "^3.3.1",
"phoenix_live_view": "^0.18.18", "phoenix_live_view": "^0.18.18",
"postcss": "^8.4.31",
"postcss-loader": "^6.1.1",
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-flatpickr": "3.10.5", "react-flatpickr": "3.10.5",
@ -50,15 +37,10 @@
"react-popper": "^2.3.0", "react-popper": "^2.3.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-transition-group": "^4.4.2", "react-transition-group": "^4.4.2",
"tailwindcss": "^3.3.3", "url-search-params-polyfill": "^8.1.1"
"terser-webpack-plugin": "^5.1.2",
"url-search-params-polyfill": "^8.1.1",
"webpack": "5.88.1",
"webpack-cli": "^4.7.0"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"bundlemon": "^1.4.0",
"eslint": "^7.2.0", "eslint": "^7.2.0",
"eslint-config-prettier": "^7.0.0", "eslint-config-prettier": "^7.0.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
@ -68,8 +50,7 @@
"eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-hooks": "^4.2.0",
"stylelint": "^14.1.0", "stylelint": "^14.1.0",
"stylelint-config-prettier": "^9.0.3", "stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^24.0.0", "stylelint-config-standard": "^24.0.0"
"webpack-bundle-analyzer": "^4.4.2"
}, },
"name": "assets" "name": "assets"
} }

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -3,11 +3,9 @@ const plugin = require('tailwindcss/plugin')
module.exports = { module.exports = {
content: [ content: [
'./js/**/*.js', "./js/**/*.js",
'../lib/plausible_web/templates/**/*.html.eex', "../lib/*_web.ex",
'../lib/plausible_web/templates/**/*.html.heex', "../lib/*_web/**/*.*ex"
'../lib/plausible_web/live/**/*.ex',
'../lib/plausible_web/components/**/*.ex',
], ],
safelist: [ safelist: [
// PlausibleWeb.StatsView.stats_container_class/1 uses this class // PlausibleWeb.StatsView.stats_container_class/1 uses this class

View File

@ -1,48 +0,0 @@
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = (env, options) => ({
optimization: {
minimizer: [
new TerserPlugin(),
new CssMinimizerWebpackPlugin()
]
},
entry: {
'app': ['./js/app.js'],
'dashboard': ['./js/dashboard/mount.js'],
'embed.host': ['./js/embed.host.js'],
'embed.content': ['./js/embed.content.js']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../priv/static/js')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
}
]
},
externals: { moment: 'moment' },
plugins: [
new MiniCssExtractPlugin({filename: '../css/[name].css'}),
new CopyWebpackPlugin({patterns: [{from: 'static/', to: '../' }]}),
new webpack.ProvidePlugin({
ResizeObserver: ['@juggle/resize-observer', 'ResizeObserver'] // https://caniuse.com/?search=ResizeObserver
})
]
});

View File

@ -21,6 +21,26 @@ config :logger, :console,
# Use Jason for JSON parsing in Phoenix # Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason config :phoenix, :json_library, Jason
config :esbuild,
version: "0.17.11",
default: [
args:
~w(js/app.js js/dashboard.js js/embed.host.js js/embed.content.js --bundle --target=es2017 --loader:.js=jsx --outdir=../priv/static/js),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
config :tailwind,
version: "3.3.3",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/css/app.css
),
cd: Path.expand("../assets", __DIR__)
]
config :ua_inspector, config :ua_inspector,
database_path: "priv/ua_inspector", database_path: "priv/ua_inspector",
remote_release: "66d80de32fbb265941f4d7941fadc19097375097" remote_release: "66d80de32fbb265941f4d7941fadc19097375097"

View File

@ -6,14 +6,8 @@ config :plausible, PlausibleWeb.Endpoint,
code_reloader: true, code_reloader: true,
check_origin: false, check_origin: false,
watchers: [ watchers: [
node: [ esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
"node_modules/webpack/bin/webpack.js", tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},
"--mode",
"development",
"--watch",
"--watch-options-stdin",
cd: Path.expand("../assets", __DIR__)
],
npm: [ npm: [
"run", "run",
"deploy", "deploy",
@ -23,12 +17,7 @@ config :plausible, PlausibleWeb.Endpoint,
live_reload: [ live_reload: [
patterns: [ patterns: [
~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$}, ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
~r{lib/plausible_web/views/.*(ex)$}, ~r"lib/plausible_web/(controllers|live|components|templates|views|plugs)/.*(ex|heex)$"
~r{lib/plausible_web/templates/.*(eex)$},
~r{lib/plausible_web/templates/.*(heex)$},
~r{lib/plausible_web/controllers/.*(ex)$},
~r{lib/plausible_web/plugs/.*(ex)$},
~r{lib/plausible_web/live/.*(ex)$}
] ]
] ]

View File

@ -31,7 +31,7 @@ defmodule PlausibleWeb.Endpoint do
at: "/", at: "/",
from: :plausible, from: :plausible,
gzip: false, gzip: false,
only: ~w(css images js favicon.ico robots.txt) only: ~w(css js images favicon.ico robots.txt)
) )
plug(Plug.Static, plug(Plug.Static,

View File

@ -15,7 +15,6 @@
<title><%= assigns[:title] || "Plausible · Simple, privacy-friendly alternative to Google Analytics" %></title> <title><%= assigns[:title] || "Plausible · Simple, privacy-friendly alternative to Google Analytics" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/> <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= render("_tracking.html", assigns) %> <%= render("_tracking.html", assigns) %>
<script type="text/javascript" data-pref="<%= @conn.assigns[:theme] || (@conn.assigns[:current_user] && @conn.assigns[:current_user].theme) %>" src="<%= Routes.static_path(@conn, "/js/applyTheme.js") %>"></script>
</head> </head>
<body class="flex flex-col bg-gray-50 dark:bg-gray-850" style="<%= if !@conn.assigns[:embedded], do: "height: 100%;" %> <%= if @conn.assigns[:background], do: "background-color: #{@conn.assigns[:background]}" %>"> <body class="flex flex-col bg-gray-50 dark:bg-gray-850" style="<%= if !@conn.assigns[:embedded], do: "height: 100%;" %> <%= if @conn.assigns[:background], do: "background-color: #{@conn.assigns[:background]}" %>">
<%= if !@conn.assigns[:embedded] do %> <%= if !@conn.assigns[:embedded] do %>
@ -33,6 +32,6 @@
<% else %> <% else %>
<%= render("_footer.html", assigns) %> <%= render("_footer.html", assigns) %>
<% end %> <% end %>
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script> <script type="text/javascript" data-pref="<%= @conn.assigns[:theme] || (@conn.assigns[:current_user] && @conn.assigns[:current_user].theme) %>" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</body> </body>
</html> </html>

View File

@ -14,7 +14,6 @@
<title><%= assigns[:title] || "Plausible · Web analytics" %></title> <title><%= assigns[:title] || "Plausible · Web analytics" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/> <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= render("_tracking.html", assigns) %> <%= render("_tracking.html", assigns) %>
<script type="text/javascript" data-pref="<%= @conn.assigns[:current_user] && @conn.assigns[:current_user].theme %>" src="<%= Routes.static_path(@conn, "/js/applyTheme.js") %>"></script>
</head> </head>
<body class="flex flex-col h-full bg-gray-100 dark:bg-gray-900"> <body class="flex flex-col h-full bg-gray-100 dark:bg-gray-900">
<div class="w-full my-8 text-center"> <div class="w-full my-8 text-center">
@ -34,6 +33,6 @@
© <%= DateTime.utc_now().year() %> Plausible Analytics. All rights reserved. © <%= DateTime.utc_now().year() %> Plausible Analytics. All rights reserved.
</p> </p>
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script> <script type="text/javascript" data-pref="<%= @conn.assigns[:theme] || (@conn.assigns[:current_user] && @conn.assigns[:current_user].theme) %>" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</body> </body>
</html> </html>

10
mix.exs
View File

@ -124,16 +124,22 @@ defmodule Plausible.MixProject do
{:zxcvbn, git: "https://github.com/techgaun/zxcvbn-elixir.git"}, {:zxcvbn, git: "https://github.com/techgaun/zxcvbn-elixir.git"},
{:open_api_spex, "~> 3.18"}, {:open_api_spex, "~> 3.18"},
{:joken, "~> 2.5"}, {:joken, "~> 2.5"},
{:paginator, git: "https://github.com/duffelhq/paginator.git"} {:paginator, git: "https://github.com/duffelhq/paginator.git"},
{:esbuild, "~> 0.7", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev}
] ]
end end
defp aliases do defp aliases do
[ [
setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"], "ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate", "test", "clean_clickhouse"], test: ["ecto.create --quiet", "ecto.migrate", "test", "clean_clickhouse"],
sentry_recompile: ["compile", "deps.compile sentry --force"] sentry_recompile: ["compile", "deps.compile sentry --force"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
"assets.build": ["tailwind default", "esbuild default"],
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
] ]
end end

View File

@ -36,6 +36,7 @@
"elixir_make": {:hex, :elixir_make, "0.7.6", "67716309dc5d43e16b5abbd00c01b8df6a0c2ab54a8f595468035a50189f9169", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5a0569756b0f7873a77687800c164cca6dfc03a09418e6fcf853d78991f49940"}, "elixir_make": {:hex, :elixir_make, "0.7.6", "67716309dc5d43e16b5abbd00c01b8df6a0c2ab54a8f595468035a50189f9169", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5a0569756b0f7873a77687800c164cca6dfc03a09418e6fcf853d78991f49940"},
"envy": {:hex, :envy, "1.1.1", "0bc9bd654dec24fcdf203f7c5aa1b8f30620f12cfb28c589d5e9c38fe1b07475", [:mix], [], "hexpm", "7061eb1a47415fd757145d8dec10dc0b1e48344960265cb108f194c4252c3a89"}, "envy": {:hex, :envy, "1.1.1", "0bc9bd654dec24fcdf203f7c5aa1b8f30620f12cfb28c589d5e9c38fe1b07475", [:mix], [], "hexpm", "7061eb1a47415fd757145d8dec10dc0b1e48344960265cb108f194c4252c3a89"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"esbuild": {:hex, :esbuild, "0.7.1", "fa0947e8c3c3c2f86c9bf7e791a0a385007ccd42b86885e8e893bdb6631f5169", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "66661cdf70b1378ee4dc16573fcee67750b59761b2605a0207c267ab9d19f13c"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"ex_cldr": {:hex, :ex_cldr, "2.37.2", "c45041534ec60af367c4c1af02a608576118044fe3c441c782fd424061d6b517", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "c8467b1d5080716ace6621703b6656cb2f9545572a54b341da900791a0cf92ba"}, "ex_cldr": {:hex, :ex_cldr, "2.37.2", "c45041534ec60af367c4c1af02a608576118044fe3c441c782fd424061d6b517", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "c8467b1d5080716ace6621703b6656cb2f9545572a54b341da900791a0cf92ba"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.0", "aadd34e91cfac7ef6b03fe8f47f8c6fa8c5daf3f89b5d9fee64ec545ded839cf", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0521316396c66877a2d636219767560bb2397c583341fcb154ecf9f3000e6ff8"}, "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.0", "aadd34e91cfac7ef6b03fe8f47f8c6fa8c5daf3f89b5d9fee64ec545ded839cf", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0521316396c66877a2d636219767560bb2397c583341fcb154ecf9f3000e6ff8"},
@ -131,6 +132,8 @@
"siphash": {:hex, :siphash, "3.2.0", "ec03fd4066259218c85e2a4b8eec4bb9663bc02b127ea8a0836db376ba73f2ed", [:make, :mix], [], "hexpm", "ba3810701c6e95637a745e186e8a4899087c3b079ba88fb8f33df054c3b0b7c3"}, "siphash": {:hex, :siphash, "3.2.0", "ec03fd4066259218c85e2a4b8eec4bb9663bc02b127ea8a0836db376ba73f2ed", [:make, :mix], [], "hexpm", "ba3810701c6e95637a745e186e8a4899087c3b079ba88fb8f33df054c3b0b7c3"},
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"}, "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"tailwind": {:hex, :tailwind, "0.2.1", "83d8eadbe71a8e8f67861fe7f8d51658ecfb258387123afe4d9dc194eddc36b0", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "e8a13f6107c95f73e58ed1b4221744e1eb5a093cd1da244432067e19c8c9a277"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"}, "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"},

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB