Skip to content
This repository has been archived by the owner on Mar 17, 2021. It is now read-only.

How to deal with relative public path #46

Closed
adcentury opened this issue Nov 13, 2015 · 23 comments
Closed

How to deal with relative public path #46

adcentury opened this issue Nov 13, 2015 · 23 comments

Comments

@adcentury
Copy link

I set a relative public path in outputs

output: {
  path: path.join(__dirname, 'www/static'),
  filename: '[hash].bundle.js',
  publicPath: './'
}

Then the file structure is like

www
  |-- static
          | -- bundle.js
          | -- some-image.png
          | -- some-other-image.png
          | -- style.css
  |-- index.html

When i require image in css, i works fine.

But when i require image in some js, the url is wrong.

const url = require('path/to/some-image.png');
// the url will be 'some-image.png'
// but this url will be used in index.html (through react)

Any one can help me with it? Thanks.

@silvenon
Copy link

Why don't you set it to / instead?

@adcentury
Copy link
Author

Because I want to use these files in cordova app, using '/' will fail.

@export-mike
Copy link

yeah same issue here @adcentury any progress?

@dancoates
Copy link

It isn't a very good solution but you can work around this issue by placing the scripts and css in the www folder with the index.html and setting publicPath : "". That way it doesn't matter if the files are accessed relative to the html or the css.

@adcentury
Copy link
Author

@export-mike The only way I found is to put all files (include html, js, css, images) into the www folder as @dancoates said. By the way, HtmlWebpackPlugin may help with generating html files.

@mummybot
Copy link

Are you using these in a separate app? If so, have you tried setting up your webpack dev server to proxy the other app, that way you can use '/' as your publicPath base but still forward requests to other app e.g.

var buildPath = '/wp-content/themes/mytheme/build/';

var config = {
  entry: [
    'webpack-dev-server/client?http://localhost:8080/',
    'webpack/hot/only-dev-server',
    path.join(__dirname, 'src/index.js')
  ],
  output: {
    path: path.resolve(__dirname, 'wp-content/themes/tpbc/build'),
    filename: 'index.js',
    publicPath: buildPath
  },
  devtool: 'eval-source-map',
  resolve: { alias: {} },
  devServer: {
    contentBase: buildPath,
    proxy: {
      '*': {
        target: externalServerURL,
        bypass: function(req) {
          // Make sure that non-webpack assets have the correct host header so any vhost works correctly.
          if (req.headers && req.headers.accept) {
            // Detect requests that do not contain the build directory
            if (req.url.indexOf(buildPath) === -1) {
              req.headers.host = externalServerURL.split('/')[2];
            }
          }
        }
      }
    }
  },

@dancoates
Copy link

@mummybot at least in my case the other app is a cordova iphone app, so proxying is not an option.

The core of the problem is that CSS loads assets relative to itself, and js loads assets relative to the HTML. So if the CSS isn't in the same place as the HTML then you can't use relative paths.

It would be good to be able to pass a resolving function to the file loader to allow more complex path resolution.

@bigfengyu
Copy link

I meet the same problem,do someone knows how to deal with it now?

@evilguc
Copy link

evilguc commented Jun 16, 2016

Hello. I have faced the same problem trying to pack my web app as "native" ios/android application with Cordova. In my specific case it's a React application with react-router. Web version uses HTML5 History API, so basic relative paths for assets are not work correctly on pages other than "/". But if you use Hash History instead of HTML5 History (which is by the way is recommended for cordova applications, you don't see urls anyway) it seems to work fine.

For more information see this thread: remix-run/react-router#2161

So if it's your case you can set publicPath in webpack config to empty string (so you'll get relative paths) and use Hash History with your router.

@export-mike
Copy link

I have a config that's working with Cordova and code push I can share with
you tomorrow. We're on react, react router

On Thu, 16 Jun 2016, 12:43 Ilya Gutsalyuk, notifications@github.com wrote:

Hello. I have faced the same problem trying to pack my web app as "native"
ios/android application with Cordova. In my specific case it's a React
application with react-router. Web version uses HTML5 History API, so basic
relative paths for assets are not work correctly on pages other than "/".
But if you use Hash History instead of HTML5 History (which is by the way
is recommended for cordova applications, you don't see urls anyway) it
seems to work fine.

For more information see this thread: remix-run/react-router#2161
remix-run/react-router#2161

So if it's your case you can set publicPath in webpack config to empty
string (so you'll get relative paths) and use Hash History with your router.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#46 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AC2Fn6Nl3PAn87DXcYHg0_8xaMs6iodqks5qMTbOgaJpZM4Gh22j
.

@ianks
Copy link

ianks commented Jul 1, 2016

@export-mike can you post that config?

@ianfitzpatrick
Copy link

ianfitzpatrick commented Jul 13, 2016

I'm having the same problem, not using react but vuejs + cordova.

I tried to setting:

assetsPublicPath: '/',

However the resulting cordova index.html file still ends up with entries like:

<script type=text/javascript src=/static/js/app.2a047fb94d3c535a8f2e.js>

My hacky fix is to just write a little shell script (there is probably a proper webpack post-hook way of doing this but I dunno what it is) to replace all instances of /static/ with static/ and that fixed the problem for me. But not exactly elegant.

I crave a better solution, emailed @export-mike to see if he can share his config with us.

Edit:

Welp actually I'm a dork. The webpack template I'm using has separate sections for assetsPublicPath on dev vs. production, and I was only setting it for dev.

When I set it for production like:

assetsPublicPath: '',

I got this kind of output in cordova's index.html file:

<script type=text/javascript src=static/js/app.2a047fb94d3c535a8f2e.js>

Which works fine in Cordova and when I tested in iOS simulator.

@christianmalek
Copy link

Is there a solution for this now?

@coreyching
Copy link

coreyching commented Oct 4, 2016

^ bump. The issue I'm having is using vue.js with webpack.

I bind a html tag like this: <img v-bind:src="resource.img"> to dynamically load an image.

when the client renders the page, the src path is correct, however it is the actual relative path (e.g. "../assets/example.png" etc, instead of the path webpack outputs. Thus, the image creates a 404 because there is no image at "../assets/example.png".

Alternatively, if i hardcode the src <img src="../assets/example.png"> the image loads, and the the src is some path that webpack created, finding the correct image.

@jpmelnik
Copy link

jpmelnik commented Nov 6, 2016

@yES, @dancoates

The core of the problem is that CSS loads assets relative to itself, and js loads assets relative to the HTML. So if the CSS isn't in the same place as the HTML then you can't use relative paths.

{
        test: /\.png$/,
        loader: "file-loader?name=images/[name].[ext]"
      },

I fix it partially with "url-loader", It generate data:image/png;base64

{
        test: /\.png$/,
        loader: "url-loader?name=images/[name].[ext]"
      },

I replace file-loader with url-loader.

My Webpack.config.js dev mode

const path        = require('path');
const webpack     = require('webpack');
const ExtractText = require('extract-text-webpack-plugin');

module.exports = {
  devServer: { inline: false },
  entry: path.join(__dirname, '/src/assets/javascripts/main.js'),
  output: {
    //path: './dist/assets/',
    //filename: './javascripts/[name].js',
    //publicPath: '../',

    path: './dist/',
    publicPath: '/assets/',
    filename: './javascripts/[name].js'

    // path: './dist/assets/',
    // publicPath: '/assets/',
    // filename: './javascripts/[name].js'
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      },
      output: {
        comments: false
      }
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new ExtractText('./stylesheets/main.css', {
      allChunks: true
    })
  ],
  module: {
    loaders: [
      {
        test : /\.js$/,
        include : path.join(__dirname, '/src/assets/javascripts/'),
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      },
      {
        test: /\.css$/,
        loaders: ['style', 'css']
        //loader: "style-loader!css-loader"
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css?sourceMap', 'sass?sourceMap', ExtractText.extract('css!sass')]
      },
      {
        test: /\.(woff|woff2|ttf|eot|svg)(\?[\s\S]+)?$/,
        loader: 'url-loader?limit=10000&name=fonts/[name].[ext]'
      },
      {
        test: /\.png$/,
        loader: "url-loader?name=images/[name].[ext]"
        //loader: "file-loader?name=images/[name].[ext]"
      },
    ]
  }
};

Other alternative with sass/scss using extract-text-webpack-plugin

{
     test: /\.scss$/,
     loaders: ['style', 'css', 'resolve-url', 'sass?sourceMap', ExtractText.extract(['css', 'sass'], {
          publicPath: '../'
     })]
 },

@azz0r
Copy link

azz0r commented Nov 26, 2016

I believe I'm also suffering from the same issue and the above gives me:

fs.js:640
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                 ^

Error: ENOENT: no such file or directory, open '/Users/azz0r/Sites/Personal/wwe-draft-generator/build/static/app.bundle.js'
    at Error (native)
    at Object.fs.openSync (fs.js:640:18)
    at Object.fs.readFileSync (fs.js:508:33)
    at /Users/azz0r/Sites/Personal/wwe-draft-generator/scripts/build.js:31:29

@prewk
Copy link

prewk commented Dec 1, 2016

I'm using publicPath: '' which allows you to set it at runtime with __webpack_public_path__ (as per https://webpack.github.io/docs/configuration.html)

My CSS and JS is loading correctly from the CDN environment I upload them to and point towards with __webpack_public_path__.

If I, however, use file-loader to load a PNG file in a React component, the resulting path will be calculated from some other algorithm, causing the PNG image to be loaded locally from the web server instead of the CDN.

Is file-loader supposed to adhere to __webpack_public_path__?

@bjornstar
Copy link

@prewk I ran into the same problem, webpack/webpack#971 had the clue that got it working for me.

Add a new entry before your other ones and modify __webpack_public_path__ there.

@prewk
Copy link

prewk commented Dec 13, 2016

Thanks, that's exactly how I'm setting it at the moment, though. I ended up not using the file-loader for my problem and going for data-uris instead.

@asuishi
Copy link

asuishi commented Mar 16, 2017

Is there a solution for this now? v1 or v2
require image in css and js

@joshwiens
Copy link
Member

closed in #135 and available in v0.11.0

@danderson00
Copy link

For those reading who are using create-react-app and don't want to eject, this is possible to work around by setting "homepage": "./" in package.json.

@fairking
Copy link

fairking commented Oct 10, 2019

I have solved my problem with the following vue.config.js settings:

module.exports = {
	publicPath: process.env.BASE_URL,
	assetsDir: process.env.BASE_URL
};

I think you can do the same with webpack.config.js as well by changing output.publicPath.
Reference: https://cli.vuejs.org/guide/html-and-static-assets.html#url-transform-rules

You can also do publicPath: process.env.BASE_URL + '/static/'

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests