Adding background image throws a module load error

When I add background-image: url(…/images/my-image.png) to phoenix.css, the image displays correctly but the console shows an error

Uncaught Error: Module build failed: ModuleParseError: Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
    at handleParseError (c:\projects\Phoenix\filmhub\assets\node_modules\webpack\lib\NormalModule.js:364:19)

This also happens with a brand new project so I know it’s not a change I made.

I also tried using background-image: url("<%= Routes.static_path(@conn, “/images/my-image.png”) %>"); but that doesn’t work at all.

I am new to phoenix so I’m not sure what else to try, what is the correct way to display background images in phoenix? Thanks

Hi,

body {
  background-image: url('/images/my-image.png');
}

<%= %> tags only works inside eex templates.

1 Like

Hello and welcome!

In the thread how-to-put-background-picture-to-phoenix-html-page you should find the answer to your question.

Yes, I have tried this. Like I said the images shows up when I put background-image: url(’…/images/my-picture.png’) but there is an error in the developer tools console.
Is there any way to get rid of this error

I have looked at this, the problem isn’t displaying the image, the problem is that while the image displays there is an error in the console.

sorry, you clearly reported it.

Hmm, a strange character somewhere in the background-image in the css ? maybe from a cut&paste ?

No, I have tried several images, it doesn’t make any difference. I have tried creating a new mix project and the error appears as soon as I add a background image.

Can you share your configuration for Webpack?

It’s just the default config file - I haven’t changed anything

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: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
  ]
});

This may be because you need url-loader to process the image. In your assets folder run:

npm i -D url-loader

Then add this line to the rules array inside your Webpack configuration:

//...
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }

I tried this but there is a different error now

Uncaught Error: Module build failed: ModuleBuildError: Module build failed: Error: Cannot find module 'file-loader'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
    at Function.Module._load (internal/modules/cjs/loader.js:508:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (c:\projects\Phoenix\filmhub\assets\node_modules\v8-compile-cache\v8-compile-cache.js:161:20)

file-loader is the default fallback loader when the file exceeds the specified limit.

  • install file-loader so that the fallback works
  • increase the specified limit to be large enough so that your image will get processed (or remove it altogether).
1 Like

Thanks for the suggestion. I don’t really know anything about webpack so I’m not sure if I’m following your advice correctly. Installing file-loader just gave me an error of

Failed to load resource: the server responded with a status of 404 (Not Found)

The image size was well below the limit for url-loader but I increased it anyway and it made no difference.

{
  loader: 'url-loader',
  options: {
    limit: 16384
  }
}

I have no errors displaying images if I link to them on a template, it is only when I use background-image in css that there is an error.

I have this problem even if I create a new mix project - is this an issue with Phoenix or could it be something on my end?

Just tried this on a vanilla Phoenix install.

/* This file is for your main application css. */
@import "./phoenix.css";
body {
  background-image: url("/images/phoenix.png");
  background-position: bottom;
  background-repeat: no-repeat;
}

works without any change to the stock webpack config:

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: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
  ]
});

So as suggested before - hand-type the image path into the app.css and see what happens.

package.json

{
  "repository": {},
  "license": "MIT",
  "scripts": {
    "deploy": "webpack --mode production",
    "watch": "webpack --mode development --watch"
  },
  "dependencies": {
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "babel-loader": "^8.0.0",
    "copy-webpack-plugin": "^4.5.0",
    "css-loader": "^2.1.1",
    "mini-css-extract-plugin": "^0.4.0",
    "optimize-css-assets-webpack-plugin": "^4.0.0",
    "uglifyjs-webpack-plugin": "^1.2.4",
    "webpack": "4.4.0",
    "webpack-cli": "^2.0.10"
  }
}
3 Likes

I have been hand typing the image path. As I said the image displays but there is an error in the console

See attached screenshot error image

Actually never mind thanks, it has started working properly for me. I have no idea why but it must have been something wrong on my computer.

1 Like

This saved my day. I have been struggling to show a background-image to my page. I was getting “invalid property” error. Until, after several days investigating, googling, etc, I found this post. Nowhere else I found any mention to using “/image/…” as the url. I was always pointing to my “…/static/images/…”.