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

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

Closed
agilgur5 opened this Issue Jul 16, 2016 · 17 comments

Comments

Projects
@agilgur5

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

This comment has been minimized.

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

This comment has been minimized.

agilgur5 commented Jul 16, 2016

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

@bebraw bebraw added the enhancement label Jul 16, 2016

@harmony7

This comment has been minimized.

harmony7 commented Jul 16, 2016

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

This comment has been minimized.

agilgur5 commented Jul 16, 2016

@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

This comment has been minimized.

Member

sokra commented Jul 17, 2016

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

This comment has been minimized.

Collaborator

Kovensky commented Jul 18, 2016

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

@sokra

This comment has been minimized.

Member

sokra commented Jul 19, 2016

I think this should be guaranteed by the ES6 spec.

@harmony7

This comment has been minimized.

harmony7 commented Jul 20, 2016

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

This comment has been minimized.

ojacobson commented Jul 21, 2016

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

This comment has been minimized.

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

This comment has been minimized.

twhid commented May 3, 2017

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

@webpack-bot

This comment has been minimized.

webpack-bot commented Mar 30, 2018

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

This comment has been minimized.

webpack-bot commented Apr 14, 2018

Issue was closed because of inactivity.

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

@xiao8cn

This comment has been minimized.

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

(feat): add dynamic public path
- 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

This comment has been minimized.

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

This comment has been minimized.

rrubiorr81 commented Oct 3, 2018

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

This comment has been minimized.

MartinYounghoonKim commented Oct 16, 2018

@rrubiorr81 Did you solved it ?

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