dynamically setting __webpack_public_path__ does not work after build in vue application

北战南征 提交于 2021-02-10 21:12:03

问题


I have a vue frontend, and spring boot backend application. My application has multiple instances with different url paths (for example /instance1, /instance2), but uses the same build project - meaning every instances runs the same jar. Also the application serves static files - the index.html of the compiled vue application.

My problem is that the vue application needs to know dynamically from which url path to get all its static files, so for example when i get the index.html of instance1 it need to get all the assets from /instance1/assets

I read many answers to this problem which they all suggested basically to configure dynamically the webpack_public_path global variable like this first answer

so in my vue app I did this:

in main.js file:

import './publicpath'
import Vue from 'vue'

then in publicpath.js file:

__webpack_public_path__ = `/${window.location.pathname.split('/')[1]}/`

The problem with the answer linked above is that it only works for me when I run the application as a dev application (when running npm run serve on vue project). This doesn't work after building the project, and the build index.html is served by spring boot.

I couldn't find any answer that solved this problem so I would really appreciate any help

Thank you!


回答1:


Changing __webpack_public_path__ may not to be enough....

Why

Vue CLI has a publicPath option:

By default, Vue CLI assumes your app will be deployed at the root of a domain, e.g. https://www.my-app.com/. If your app is deployed at a sub-path, you will need to specify that sub-path using this option. For example, if your app is deployed at https://www.foobar.com/my-app/, set publicPath to '/my-app/'

This value is used in multiple places:

  1. To configure Webpack - set it's output.publicPath option.

The value is important both at build time and runtime.

At runtime it is made available as a global JS variable __webpack_public_path__ and used (by Webpack) when creating URL's for any module requests (loading dynamic JS chunks, referencing images etc.)

At build time, it is also used for creating URL's but this time for the assets which are needed to load your app into the browser - all the <link> and <script> tags responsible to load all JavaScript and CSS of your app. Those are directly injected into the index.html as hardcoded strings

  1. The value is made available as an ENV variable process.env.BASE_URL usable inside your code. This variable is very useful

For example Vue-router, also requires some configuration to work correctly when the app is not hosted in server root (because its responsible for creating URL's for <router-link>). This is most of the time done using this line in it's config: base: process.env.BASE_URL

Or you may need to configure base url for Axios to make API calls...

All of this works thanks to Webpack's DefinePlugin. And really important thing to understand is how it works. Anytime you use process.env.BASE_URL in your code, Webpack replaces that string with configured value during build time (ie. there is no variable process.env.BASE_URL know at runtime)

How

From all the above it should be clear now that just replacing the value of __webpack_public_path__ at runtime as suggested by linked answer is just not enough. So what else is needed?

  1. Do not use process.env.BASE_URL anywhere in your code. Using __webpack_public_path__ instead should be enough to solve this problem

  2. Much bigger problem are the links in index.html generated during build time. Those are clearly not affected by __webpack_public_path__ variable. Only option I see here is to set publicPath for production build to some unique value and instead of serving index.html as a static file, serve it as dynamic response - reading file from the disk, replacing original publicPath value with correct value (for the specific deployment) and serving the result

Alternatives

  1. First and obvious alternative is just to setup multiple CI/CD pipelines, configure publicPath for each using ENV variables and build separate package for each instance

  2. Second alternative is hinted in Vue CLI documentation

The value (publicPath) can also be set to an empty string ('') or a relative path (./) so that all assets are linked using relative paths. This allows the built bundle to be deployed under any public path, or used in a file system based environment like a Cordova hybrid app.

The point is if your site uses relative link without leading slash, it should be interpreted by the browser as a path relative to the current path (source) and as a result, you can deploy under any public path...

The decision is yours as only you know the details needed to make one...



来源:https://stackoverflow.com/questions/65915610/dynamically-setting-webpack-public-path-does-not-work-after-build-in-vue-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!