webpack: `__webpack_public_path__` does not work if entrypoint uses ES6-style imports

I’m submitting a bug report Webpack version: 1.13.1 Please tell us about your environment: Ubuntu 14.04

Current behavior: Entrypoint file:

__webpack_public_path__ = SETTINGS.STATIC_URL + 'build/'
require('navbar/navbar.es6')

If I use import 'navbar/navbar.es6' instead, the images that are loaded inside of navbar.es6 (via import imageName from 'img/filepath.png') do not have the public_path prepended to them. When I use the above require('navbar/navbar.es6'), it works fine. CommonJS imports work but ES6-style ones do not when dynamically setting __webpack_public_path__

Expected/desired behavior: There should be no difference between ES6 and CommonJS modules

  • Browser: Chrome 50
  • Language: [ES6/7]

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 19 (5 by maintainers)

Commits related to this issue

Most upvoted comments

// entry.js
import "./public-path.js"
import "app";
// public-path.js
__webpack_public_path__ = "..."

Am I wrong to think that this would be much simpler if publicPath could take a function?

I’ve found that you can load the public-path.js file in @sokra 's example by adding to the entry array in webpack.config.js. Then it’s much less intrusive.

entry: ['./public-path.js', './entry.js']

Hi. My name is Kirill Borodavkin. I appied for this job on freelancer.com. Looking forward to hearing from you.

@ojacobson i bumped into the same problem and drafted this solution https://github.com/agoldis/webpack-require-from I needed to be able to switch webpack public path at runtime and fine tune how files are loaded from CDN. While you can override the __webpack_public_path__ manually, sometimes it isn’t enough.

// entry.js
import "./public-path.js"
import "app";
// public-path.js
__webpack_public_path__ = "..."

this is not working in my case. path is not setting for image and css files

Is it worth defining a plugin extension point to allow developers to reprogram how public paths are computed, for cases where the config file default isn’t sufficient? I wanted this in the context of Aerobatic, where an HTML preprocessor outside of my control modifies my pages to add a CDN base URL as a global variable, well after webpack has finished running.

ES6 says that import statements are always hoisted (brought to the top of the current module). This means that the following are equivalent:

__webpack_public_path__ = "asdf";
import foo from "foo";
import foo from "foo";
__webpack_public_path__ = "asdf";

They are always treated as though you had the second version.

This is part of the ES6 spec and has nothing to do with Webpack.

Since the import statement will occur before the assignment to __webpack_public_path__, it (as well as all the imports that in turn would happen during the importing of that file) will happen before the public path has been updated.

Therefore, your desired behavior would require you to use require(). Anyone correct me if I’m wrong.

One way you can work around this (sort of) is like this:

main.js

import 'navbar/navbar.es6';
/* ... The rest of your program ...*/

entry.js

__webpack_public_path__ = SETTINGS.STATIC_URL + 'build/';
require('./main');

Use entry.js as your webpack entry point. If you want to use import everywhere else then you can; entry.js would be the only point in the code where you need a require().

For anyone making a lib consumed by other app and who wants to set public path at runtime via options passed from consumer to lib, here is what i ended up doing

// entry file
export default options => {

    __webpack_public_path__ = options.publicPath || '/'

    const App = require('./app')

    return new App.default(options)

}

I’ve tried all this suggestion and others but none of them are working for me. I have a similar problem, where i need to load mu chunks from a different origin. Currently using CRA -create-react-app-, i have in my entry file:

index.js

import './src/containers/async/build';
import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import store from './store'
import App from './containers/app'

import './index.css'

const target = document.querySelector('#root');

render(
    <Provider store={store}>
        <React.Fragment>
            <App/>
        </React.Fragment>
    </Provider>,
    target
);

in src/containers/async/build.js

__webpack_public_path__ = 'http://my-server-assets.com';

Am i missing something?

@harmony7 ohh, didn’t even think that hoisting could be the root cause of that problem, thanks for the tip!

To have symmetry with the publicPath configuration, I would assume that webpack would read that line first before anything else. To achieve that kind of symmetry, I would guess that webpack would have to hoist __webpack_public_path__ to the top of the module after any loaders run (not sure what that might involve)