Search code examples
javascriptreactjsnpmwebpackassets

Include assets from webpack bundled npm package


I've been banging my head over this for a while, and am wondering if it's even possible to begin with. Thanks for any help with this!

The npm package

I've got an npm package which is basically a library of React components. This library has embedded stylesheets, which references assets like fonts and images from the CSS. These are then all bundled using webpack into my-package.js.

The config for this looks like:

var path = require('path');

module.exports = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['babel-loader'],
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        loader: "style-loader!css-loader"
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
        loader: 'file-loader'
      },
      {
        test: /\.styl$/,
        loader: 'style-loader!css-loader!stylus-loader'
      }
    ]
  },
  entry: [
    './lib/components/index.js',
    './lib/index.styl'
  ],
  output: {
    path: path.join(__dirname, 'build/'),
    filename: 'my-package.js'
  }
}

With ./lib/components/index.js looking like:

import '../index.styl';
import MyComponent from './my-component.js';

export {
  MyComponent
}

So far, so good.

The application

Now in another code base I've got the main application, which install this npm package.

My application root requires this package...

import MyPackage from 'my-package';

And is then itself webpack bundled and loaded onto the browser. All the scripts and style blocks are bundled correctly, however the styles which reference the assets are using the relative url from the npm package itself, therefore giving me 404s from the application.

console errs

Is there any way to tell webpack to resolve these images from node_modules/my-package/build/[webpack-generated-name].jpg ?

My application's webpack config looks like this:

var path = require('path'),
    webpack = require('webpack');

module.exports = {
  devtool: '#eval-source-map',
  entry: [
    'my-package',
    'webpack/hot/only-dev-server',
    './app/index.js',
  ],
  output: {
    path: path.join(__dirname, 'build/static'),
    filename: 'bundled.js',
    publicPath: '/',
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  resolve: {
    extensions: ['', '.js']
  },
  resolveLoader: {
    'fallback': path.join(__dirname, 'node_modules')
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['react-hot', 'babel'],
        exclude: /node_modules/,
        include: __dirname
      },
      {
        test: /\.css?$/,
        loader: "style-loader!css-loader",
        include: __dirname
      },
      {
        test: /\.(jpg|jpeg|ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
        loader: 'file-loader'
      },
      {
        test: /\.styl$/,
        loader: 'style-loader!css-loader!stylus-loader'
      }
    ]
  }
};

Solution

  • Figured out a way around this.

    In my application's webpack config I added a plugin (recommended by @Interrobang) which copies the static assets from the node_module/my-package into the app server's public path:

    var TransferWebpackPlugin = require('transfer-webpack-plugin');
    
    ...
    plugins: [
      new TransferWebpackPlugin([
        { from: 'node_modules/my-package/assets', to: path.join(__dirname, 'my/public') }
      ])
    ]
    ...
    

    These will then be made accessible by calling the asset name: localhost:XXXX/my-image.jpg. The server here is basically looking at /my/public/my-image.jpg if you've set it up correctly.

    I'm using Express, so I just had to define app.use(express.static('my/public')) in my app server.