vuejs-templates / webpack

A full-featured Webpack + vue-loader setup with hot reload, linting, testing & css extraction.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Better publicPath in webpack.conf

zhangxin840 opened this issue · comments

Setting publicPath of webpack.conf to '/' is unnecessary. This will break the app if served form local file system, or a PhoneGap package.

@zhangxin840 I believe that was originally added because it was required for code splitting. Have you checked that code splitting still works when it's not set?

I'm a bit new to the whole SPA/JS/WebPack/modern webdev kerfuffle, could I be of help somehow? Building with build.assetsPublicPath set to './' the default template (also adding the component) works just fine and all scripts seem to be built correctly and load. Is that example too simple to test what you believe may break @chrisvfritz ?

@chrisvfritz I set assetsPublicPath to '' and nothing goes wrong(at least in the project).

publicPath != assetsPublicPath

without an absolute public path, webpack fails to load split chunks when the url has changed (e.g. from using vue.router).

@LinusBorg Regardless it fixes the problem. I now am able to run my application over file:// with no issues. Everything builds just fine, I can serve the files just fine.

Yes, but we are not discussing assetPublicPath here.

@LinusBorg I think you're losing sight of the problem in favor of the details. In this case @zhangxin840 mentioned the problem explicitly. Changing assetsPublicPath to './' (instead of publicPath) solves the problem and everything seems to work on my end just fine afterwards, which was @chrisvfritz's worry.

In any case, how would I go about reproducing the problem you mentioned? Do you mean LiveReload breaks? Because the change is only applied to the build script, not dev.

when you use vue-router (or change the url history any other way), a relative publicpath (and most likely, also assetPublicPath will break your build.

At least I personally experienced that webpack will try to fetch chunks (from code splitting) relative to the current URL if public path is not absolute - which will fail if you are not in the root.

I use vue-router in my project. I have not touched publicPath, only assetPublicPath. As I said, everything builds and works just fine.

have you used code-splitting?

@LinusBorg I'm using ES6 modules. They compile together just fine.

@LinusBorg This is still a bug and should be reopened. In config/index.js changing build.assetsPublicPath to './' and leaving dev.assetsPublicPath fixes serving over file:/// protocol while at the same time allowing the npm run dev webserver to keep working.

Everything builds correctly in both situations. The files in dist can be used both over file and tested hosting them with python -m http.server and npm's http-server package with no issues found.

I haven't seen an example using code-splitting to test wether it breaks or not. But not working under Cordova is as much an issue.

This is still a bug

I fail to see why a config setting's default value should be considered a bug, just because it does not fit your specific usecase. If you need another value, change the config setting, that's what it is for.

Everything builds correctly in both situations.

Did you test with vue-router? Because relative asset Paths will break paths to your assets when using vue-router in history mode, which is a very popular usecase (or manipulate history API any other way): When you navigate from '/' to '/users', an asset's path will change with it, i.e. from './logo.png' will now point to './users/logo.npg' - and the file won't exist at that path, of course.

It's not "my" usecase. It's the default config breaking the file:/// protocol. Whenever it started doing that it became a bug. Not to mention that this not only affects Cordova (currently the only way to deploy Vue as a mobile application, at least until Weex starts supporting it) but pretty sure also affects Electron, another huge platform for cross-platform desktop development.

I'm using vue-router and just tested history mode with nginx. Works perfectly with assetsPublicPath set to './'.

When you build for production, it even tells you that the result is not intended to be used from file://.

https://github.com/vuejs-templates/webpack/blob/master/template/build/build.js#L14

It's not a bug. It's a default value that you have to change if you want to do something that the default is not intended for.

And, as explained at the very beginning of this issue, an absolute path is required for code splitting. That's a fact.

If you need a relative path for cordova, no problem . Change the setting, done.

I'd say with quite some confidence that the file:/// protocol is a bigger standard than code-splitting and therefore has more merit as a default.

But even if the default is not changed, even if there's a consensus among all devs that Electron, Cordova, the Principle Of Least Astonishment and standard local development all together matter less than code-splitting, shouldn't it be acknowledged in some place beside this issue (like the message shown on build you mentioned or an alternative build script that supports the norm of file:/// working) that there's a way to build without breaking the mentioned standard?

The question which is the bigger standard is not as important as the question what the default purpose of the template is.

Which is single file web applications, potentially big ones, which need code splitting (we advertise for it in various locations of our docs).

This template is simply not meant for mobile applications first and foremost. (and eg for electron there are templates provided by the community that are far better suited as a starting point than this one)

However,, note in the config can never be a bad idea., so I will reopen this issue for that.

But someone else will have to pick up as I'm on vacation for the next ten days.

I can add that note, though first I'd love to hear what other templates people are using and enjoying for mobile/electron. I'd like to add a few alternatives rather than just saying, "No!" 😄

I ran a simple test on the latest template with code splitting and setting assetsPublicPath to './', and everything seems to work fine. Take a look at https://github.com/asselin/vue-webpack-codesplit-test.

Does this resolve the final concern about changing assetsPublicPath to './' as a default?

Setting assetsPublicPath to './' fixes Cordova, file://, and serving from a higher directory (e.g. building into test/dist and serving test/), so it would be nice to make it the default if it there are no remaining reasons not to.

cc: @LinusBorg @chrisvfritz @mixedCase

Yeah, guess we should change it.

@LinusBorg Is there anything I can do to help get this change in?

We accept PRs :)

@LinusBorg Submitted PR #541 for this issue. Also, could you please take a look at PR #530 at the same time? It fixes a similar type of path issue loading fonts.

Thanks!

@LinusBorg I tested vue-router history mode, and ran into some issues. If the URL is only 1 level deep (e.g. /index.html or /menu), everything works fine. If it's 2+ levels deep (e.g. /user/menu), the relative URLs break.

Having said that, I'd still like to make a case for changing the default.

  1. I checked 3 sites that use history mode: Facebook, Twitter, and Blogger. All 3 sites serve their static assets from absolute URLs from a completely different top level path or domain. For example, all of Twitter's static assets are served from https://abs.twimg.com, and all of Facebook's are served from https://www.facebook.com/rsrc.php/. My suspicion is that they did that so that the app servers don't have to serve static resources, and instead they're served by dedicated web servers and/or a CDN. Since this seems to be common (perhaps best) practice, in production, if you're going to use history mode, you'd wind up changing assetsPublicPath anyway, and not using the default.
  2. I agree with @mixedCase that history mode is used less often than a) serving an app out of a subdirectory (i.e. building to /app/dist and serving /app) b) serving from file:// (especially Cordova)
  3. The template's use of vue-router doesn't enable history mode. I assume this is done because history mode doesn't work unless you configure your webserver correctly. IMO, since history mode isn't enabled by default in the template, it's inconsistent to default assetsPublicPath to '/' so that history mode works. My suggestion is to add a chapter to the documentation "Enabling HTML history mode" that has step by step what to do to make it work (e.g. 1. Change assetsPublicPath 2. Add "mode: 'history'" 3. Configure your server per https://router.vuejs.org/en/essentials/history-mode.html etc.)

Alternatively, if you're concerned about changing the default and breaking support of history mode, how about a question in the template "Enable HTML5 history mode?" that would configure assetsPublicPath to '/' and add mode: 'history' if Yes was selected?

That sounds good so far, but I think there's one testcase still missing:

Lazy-loading a component in a nested route. The reason that this could be a special case is that for lazy-loaded components, styles are not extracted into the seperate .css file - instead they are injected into the page's head section when the component is loaded.

That means that with lazy-loaded routes, you may end up with CSS in your <head> that points to a wrong bakground-image etc.

As I said, paths in webpack can be very tricky... :/

I agree with @mixedCase that history mode is used less often than a) serving an app out of a subdirectory (i.e. building to /app/dist and serving /app) b) serving from file:// (especially Cordova)

  1. To serve from a subdirectory, just change the assetsPath. We should improve the docs for this (no matter what path we take in the end -pun inteded), though, and make it easy to customize it during build with an ENV variable or something.
  2. I don't agree with the sentiment that history mode is used more often. I get nearly zeroi questions about cordova on SO and our forums, and some about subdirectories, but many more about history mode. Also, this template is not built with cordova, electron or any other wrapping technology in mind. It's built for websites first and foremost, and I don't think it would be a good idea to turn it into a "one size fits all" mutant-beast.

That is not to say that we can't switch to relative paths at all - we still have to do some tests.

But if relative paths have problems with lazy-loaded routes and other edge cases, I would rather vote for staying with defaults that work best for a typical webapp, rather than something like cordova, which is not a focus of this template.

@LinusBorg Thanks for the reply. I'll take a look at lazy loaded components with assetsPath set to './' and see what's what.

I agree with you that Cordova isn't a focus for this template; I'm working on a Cordova template that I hope to publish soon.

Thinking about this some more, assuming lazy loaded components work, I think that adding a question at creation time about enabling history mode makes the most sense, that way the generated code is consistent.

I'll let you know what I find soon. Thank you!

assetsPublicPath setting to './' not working on Cordova when enabling vue-router lazy loading feature(webpack code splitting), unable to load file:/// resource, how to solve this?

Please don't highjack issues to ask support questions. I saw you already asked on the forum.

Hi everyone. I also think that this can be somehow improved.
Setting assetsPublicPath: '', allows for local usage, hosting as a static website and as I see in the comments above, cordova apps.
While assetsPublicPath: '/', covers more use-cases it forces to use some sort of web server to serve your website.
I think this stuff should be at least very well explained in the docs so it doesn't create confusion

Side note regarding code splitting: Code splitting works fine when used locally as a static website if the path is set to ''.

You can solve this problem in the following way (If you are use vue-webpack-template):

  1. In your config/index.js in build options change your assetsPublicPath on "" or "./".
  2. Then in build/webpack.base.conf.js do the next trick in your fonts loaders options ("url-loader" or "file-loader"): { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]'), publicPath: process.env.NODE_ENV === 'production' ? '../../' : '/' } },
  3. And it is not necessary to use mode: "history" in vue-router

These settings are very useful for building applications using Cordova/Phonegap

@AbdullaevTimur this finally worked for me! Thank you!
Just so other who the same setup as mine, you can try his points.

My setup:

  • vue-webpack wrapped in cordova

I had the ff issues:

  • working fine when app is ran using webpack-dev-server
  • only the App.vue is displayed , not all my other components called by when ran using www/dist/index.html --> therefore same behavior for the android build and all other Cordova builds.

Now working fine!

I am setting publicPath: "./" but this doesn't work, the generated path is "js/...." and it should be "./js/...." In the documentation section it says this is possible but it doesn't work.