nesimtunc

nesimtunc

No static assets found on production using Docker Containers

Hi,

elixir -v
Erlang/OTP 23 [erts-11.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Elixir 1.10.3 (compiled with Erlang/OTP 22)

And my deps.

mix deps.get             
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  bamboo 1.5.0
  bamboo_smtp 2.1.0
  certifi 2.5.2
  connection 1.0.4
  cowboy 2.8.0
  cowlib 2.9.1
  csv 2.3.1
  db_connection 2.2.2
  decimal 1.8.1
  ecto 3.4.6
  ecto_sql 3.4.5
  file_system 0.2.8
  gen_smtp 0.15.0
  gettext 0.18.1
  hackney 1.16.0
  idna 6.0.1
  jason 1.2.1
  metrics 1.0.1
  mime 1.4.0
  mimerl 1.2.0
  parallel_stream 1.0.6
  parse_trans 3.3.0
  phoenix 1.5.4
  phoenix_ecto 4.1.0
  phoenix_html 2.14.2
  phoenix_live_dashboard 0.2.7
  phoenix_live_reload 1.2.4
  phoenix_live_view 0.14.4
  phoenix_pubsub 2.0.0
  plug 1.10.4
  plug_cowboy 2.3.0
  plug_crypto 1.1.2
  postgrex 0.15.5
  pow 1.0.20
  ranch 1.7.1
  ssl_verify_fun 1.1.6
  telemetry 0.4.2
  telemetry_metrics 0.5.0
  telemetry_poller 0.5.1
  unicode_util_compat 0.5.0

mix.exs:

defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :myapp,
      version: "0.1.0",
      elixir: "~> 1.7",
      elixirc_paths: elixirc_paths(Mix.env()),
      compilers: [:phoenix, :gettext] ++ 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: {MyApp.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.5.3"},
      {:phoenix_pubsub, "~> 2.0"},
      {:phoenix_ecto, "~> 4.1"},
      {:ecto_sql, "~> 3.4"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.2.0"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:pow, "~> 1.0.20"},
      {:bamboo, "~> 1.5"},
      {:bamboo_smtp, "~> 2.1.0"},
      {:csv, "~> 2.3.1"}
    ]
  end

  # Aliases are shortcuts or tasks specific to the current project.
  # For example, to create, migrate and run the seeds file at once:
  #
  #     $ mix ecto.setup
  #
  # See the documentation for `Mix` for more info on aliases.
  defp aliases do
    [
      "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
      "ecto.reset": ["ecto.drop", "ecto.setup"],
      test: ["ecto.create --quiet", "ecto.migrate", "test"]
    ]
  end
end

config/releases.exs

import Config

database_url =
  System.get_env("DATABASE_URL") ||
    raise """
    environment variable DATABASE_URL is missing.
    For example: ecto://USER:PASS@HOST/DATABASE
    """

secret_key_base =
  System.get_env("SECRET_KEY_BASE") ||
    raise """
    environment variable SECRET_KEY_BASE is missing.
    You can generate one by calling: mix phx.gen.secret
    """

config :logger, :console,
  level: :info,
  format: "$time $metadata[$level] $message\n",
  metadata: [:request_id]

config :myapp, MyApp.Repo,
  # ssl: true,
  url: database_url,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

config :myapp, MyAppWeb.Endpoint,
  http: [
    port: String.to_integer(System.get_env("PORT") || "4000"),
    transport_options: [socket_opts: [:inet6]]
  ],
  url: [host: System.get_env("HOST"), port: 80],
  server: true,
  cache_static_manifest: "priv/static/cache_manifest.json",
  secret_key_base: secret_key_base,
  check_origin: [System.get_env("HOST")]

This is not my first production release for Phoenix but I upgraded the the project to the versions above.
I followed latest Deployment Documentation: https://hexdocs.pm/phoenix/releases.html#containers

Here’s my webpack.config file

const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = (env, options) => ({
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: false
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  entry: {
    './js/app.js': ['./js/app.js'].concat(glob.sync('./vendor/**/*.js'))
  },
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, '../priv/static/js')
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader'
      }
    }, {
      test: /\.s?css$/,
      use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: '../css/app.scss' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
  ]
});

Here’s my DockerFile

FROM elixir:1.9.4-alpine as build

# install build dependencies

RUN apk add --update git build-base nodejs npm yarn python

# prepare build dir

RUN mkdir /app

WORKDIR /app

# install hex + rebar

RUN mix local.hex --force && \

mix local.rebar --force

# set build ENV

ENV MIX_ENV=prod

# install mix dependencies

COPY mix.exs mix.lock ./

COPY config config

RUN mix do deps.get, deps.compile

# build assets

COPY assets/package.json assets/package-lock.json ./assets/

RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error

COPY priv priv

COPY assets assets

RUN npm run --prefix ./assets deploy

RUN mix phx.digest

# compile and build release

COPY lib lib

# uncomment COPY if rel/ exists

# COPY rel rel

RUN mix do compile, release

# prepare release image

FROM alpine:3.9 as app

RUN apk add --update bash openssl

RUN apk add --no-cache ncurses-libs

RUN mkdir /app

WORKDIR /app

COPY entrypoint.sh ./

COPY --from=build /app/_build/prod/rel/myapp ./

RUN chown -R nobody: /app

USER nobody

EXPOSE 4004

ENV HOME=/app

CMD ["bash", "/app/entrypoint.sh"]

and entrypoint.sh file

# File: my_app/entrypoint.sh

#!/bin/bash

# docker entrypoint script.

bin="/app/bin/myapp"

# start the elixir application

exec "$bin" "start"

exec "$bin" "eval MyApp.Release.migrate"

which is create an docker container image and accessible from outside however there’s no static files found. So, the web site is pure html without theme, images etc.

I can’t find what’s wrong?

Marked As Solved

nesimtunc

nesimtunc

no… here’s how I solved, before get rid off the webpack, I gave up sass, so converted everything to css, remove the saas loader and all good.

latest webpack.config.js

const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = (env, options) => ({
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: false,
        parallel: true,
        sourceMap: false
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  entry: {
    './js/app.js': ['./js/app.js'].concat(glob.sync('./vendor/**/*.js'))
  },
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, '../priv/static/js')
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader'
      }
    }, {
      test: /\.css$/i,
      use: [MiniCssExtractPlugin.loader, 'css-loader']
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: './css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
    new CopyWebpackPlugin([{ from: 'css/', to: '../css/' }]),
  ]
});

Now all good!

P.S.: Next time I’ll avoid to use webpack at all, even though it has great benefits, but just another headache.

Where Next?

Popular in Questions Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New

We're in Beta

About us Mission Statement