2

I have followed the Angular2 webpack tutorial, but seems like the app cannot load any image. This is the directory structure of my app:

...

/dist/
/src/assets/images/
/src/assets/css/

...

And this is the webpack configuration on file config/webpack.common.js:

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');

module.exports = {
  entry: {
    'polyfills': './src/polyfills.ts',
    'vendor': './src/vendor.ts',
    'app': './src/main.ts'
  },

  resolve: {
    extensions: ['.ts', '.js']
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        loaders: [{
          loader: 'awesome-typescript-loader',
          options: { configFileName: helpers.root('src', 'tsconfig.json') }
        } , 'angular2-template-loader']
      },
      {
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file-loader?name=assets/[name].[hash].[ext]'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw-loader'
      }
    ]
  },

  plugins: [
    // Workaround for angular/angular#11580
    new webpack.ContextReplacementPlugin(
      // The (\\|\/) piece accounts for path separators in *nix and Windows
      /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
      helpers.root('./src'), // location of your src
      {} // a map of your routes
    ),

    new webpack.optimize.CommonsChunkPlugin({
      name: ['app', 'vendor', 'polyfills']
    }),

    new HtmlWebpackPlugin({
      template: 'src/index.html'
    })
  ]
};

Now if I try to add some image to the templates:

<img src="/assets/images/hp-logo.png">

I am always getting the following error during compilation (when running npm start):

ERROR in ./src/app/templates/dashboard.component.html
Module not found: Error: Can't resolve './assets/images/hp-logo.png' in '/frontend/src/app/templates'
 @ ./src/app/templates/dashboard.component.html 1:582-620
 @ ./src/app/components/dashboard.component.ts
 @ ./src/app/modules/app.module.ts
 @ ./src/main.ts
 @ multi (webpack)-dev-server/client?http://localhost:3000 ./src/main.ts

I guess it has something to do with the file-loader but after trying different configuration I couldn't get it to work.

Somebody can help me out on this one?

Ander
  • 5,093
  • 7
  • 41
  • 70

2 Answers2

4

You should write the image path relative to the template location. If your template is e.g. at /src/module1/template.html then your image location should be

<img src="../assets/images/hp-logo.png">
smnbbrv
  • 23,502
  • 9
  • 78
  • 109
  • 2
    I would not agree with you. Your solution will maybe work in the dev environment, but in production will not when webpack create chunk files. – Igor Janković Mar 02 '17 at 08:05
  • have you tried it? It will indeed work in production without any problem because every image request is resolved by HTML loader and webpack will put all the images to the path which is configured in the `file-loader`. Your solution is adding more complexity and is absolutely unnecessary – smnbbrv Mar 02 '17 at 08:10
  • 1
    Yes I did. For me, it works only in both environments. – Igor Janković Mar 02 '17 at 08:11
  • Worked perfectly in dev and production, I guess that's because both keep the same structure? Thanks @smnbbrv! – Ander Mar 02 '17 at 08:15
  • @IgorJanković you probably use inline templates. This does not enable html loader, so it does not resolve the images and a problem like yours occures. Try putting the html in a separate file and using require('...html') still as an inline template string and it will be processed correctly. – smnbbrv Mar 02 '17 at 08:22
  • 1
    @Ander no, they don't keep the same structure. Webpack automatically gets all images from your HTML (if you use it correctly ofc) and puts them in a folder which is configured here: `loader: 'file-loader?name=assets/[name].[hash].[ext]'` and updates your template to use this URL instead of using the original one – smnbbrv Mar 02 '17 at 08:26
  • 1
    @smrnbbrv Ooooh. Yes, you are right, I'm using inline templates. I didn't think about it. Thanks ;) – Igor Janković Mar 02 '17 at 08:26
  • 1
    @IgorJanković then your solution is the only one of course. Maybe there is some specific loader to handle this case... I still think if HTML chunk is quite big (and if you use images it usually is) it still worth putting it in a separate file – smnbbrv Mar 02 '17 at 08:29
  • 1
    @IgorJanković if you also learned something then +1 might be a good thing? :D – smnbbrv Mar 02 '17 at 08:39
3

Try adding:

 new CopyWebpackPlugin([{
     from: 'src/assets',
     to: 'assets',
 }, {
     from: 'src/meta',
 },])

to the webpack.common.js inside plugins array.

Igor Janković
  • 5,494
  • 6
  • 32
  • 46