Skip to content

__webpack_public_path__ does not work if entrypoint uses ES6-style imports #2776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
agilgur5 opened this issue Jul 16, 2016 · 19 comments
Closed

Comments

@agilgur5
Copy link

agilgur5 commented Jul 16, 2016

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]
@harmony7
Copy link

harmony7 commented Jul 16, 2016

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.

@agilgur5
Copy link
Author

@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)

@harmony7
Copy link

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().

@agilgur5
Copy link
Author

@harmony7 yea that's what I'm currently doing (thanks for the suggestion though!), it's not the prettiest solution as it means I need to create separate files for each of my entrypoints that uses __webpack_public_path__. The broken symmetry with publicPath (and broken symmetry with require in a codebase that uses ES6 imports) is fairly unintuitive on top of that. It feels really hacky right now as I have 4 entrypoints.

Broken symmetry/intuition in build tools IMO warrants an eventual solution

@sokra
Copy link
Member

sokra commented Jul 17, 2016

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

@Jessidhia
Copy link
Member

@sokra (just a clarification) is that always guaranteed to work, or just a quirk of how webpack builds the imports?

@sokra
Copy link
Member

sokra commented Jul 19, 2016

I think this should be guaranteed by the ES6 spec.

@harmony7
Copy link

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']

@ojacobson
Copy link

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.

@agoldis
Copy link

agoldis commented Feb 10, 2017

@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.

@twhid
Copy link

twhid commented May 3, 2017

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

@webpack-bot
Copy link
Contributor

This issue had no activity for at least half a year.

It's subject to automatic issue closing if there is no activity in the next 15 days.

@webpack-bot
Copy link
Contributor

Issue was closed because of inactivity.

If you think this is still a valid issue, please file a new issue with additional information.

@xiao8cn
Copy link

xiao8cn commented Apr 27, 2018

window.webpack_public_path why not use

agilgur5 added a commit to agilgur5/front-end-base that referenced this issue May 29, 2018
- to read from the back-end's set public path to be set in template

- add publicPath to all entrypoints first so that it occurs before
  the ES6 module hoisting of any entrypoint
  - see also webpack/webpack#2776
@fadomire
Copy link

fadomire commented Sep 26, 2018

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)

}

@rrubiorr81
Copy link

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?

@MartinYounghoonKim
Copy link

@rrubiorr81 Did you solved it ?

@vreddy448
Copy link

// 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

@talentdev010
Copy link

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

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

No branches or pull requests