Ryan Miller
Ryan Miller

Reputation: 1053

Dynamic publicPath When Rendering Pages with Vue SSR

We're happy users of Vue and its server-side rendering module, Vue SSR. One of the requirements of my project is that we be able to dynamically adjust Webpack's publicPath at runtime, so that we can obtain assets from our different CDNs (we have two, one for test and one for prod).

We are able to accomplish this easily on the client-side using the __webpack_public_path__ free variable, and you can also override the publicPath within the SSR client manifest for asset URLs injected into the <head>.

Yet we continue to have issues with asset URLs that are housed directly within our templates and are rendered by SSR. For example, imagine if we had the following image within our tag:

<img src="~@/test.png" />

Our goal is that, on both the server and the client, we could adjust that URL to be prefixed how we please via publicPath. There doesn't seem to be a way to dynamically update the publicPath once the vue-ssr-server-manifest.json has been generated, the resulting URL ends up being something relative like /static/test.png or whatever we original cited in our Webpack config.

Per our project constraints, it's not possible to rebuild our SSR bundle, so we need to do this at runtime. We've tried adding placeholder values as our publicPath, e.g. __CUSTOM_WEBPACK_PUBLIC_PATH__, and replacing them in the server bundle at runtime, but that ends up being ineffective since publicPath is also embedded in other Webpack generated files.

Wondering if there is a cleaner way to achieve what we need directly via Vue SSR, or if this is something we just can't configure at runtime. Thanks for reading!

Upvotes: 4

Views: 2042

Answers (4)

arpeggie
arpeggie

Reputation: 45

Similar problem occurred in my project, and finally I worked it out.

Ryan's answer really helps, but there is one thing I want to clear up. __webpack_public_path__ is a LOCAL variable in webpack bundled code, which means __webpack_public_path__ and global.__webpack_public_path__ is not the same. You need to do something like

__webpack_public_path__ = process.env.ASSET_PATH;

to specify public path (https://webpack.js.org/guides/public-path/#on-the-fly FYI).

Last, please make sure your process.env.ASSET_PATH is not undefined, maybe you have to set it manually to global in your server code.

global.process.env.ASSET_PATH = process.env.ASSET_PATH;

Upvotes: 0

Akter Hossain
Akter Hossain

Reputation: 91

We faced similar type of problems in our webapp as well. BTW, we implemented a CDN plugin for vue.

export const CDNPlugin = {
  install(Vue, { CDN, assetsManifest }) {
    Vue.prototype.$cdn = {
      ...CDN,
      asset(name) {
        return `${CDN.baseUrl}${assetsManifest[name]}`;
      },
      resource(filepath) {
        return `${CDN.baseUrl}/resources/${filepath}`;
      }
    };
  }
};

Install this plugin both of your ssr and csr file.

Vue.use(CDNPlugin, {
  CDN: { baseUrl: 'https://my.static.cdn.com' },
  assetsManifest: yourAssetManifestObject,
});

And the usage of this CDN plugin inside vue template is as below

<img :src="$cdn.asset('relative/path/to/asset/style.css')">

If you think it is helping a bit, then I can share more regarding our implementation.

Upvotes: 1

Lomax
Lomax

Reputation: 231

I spent an entire day trying to figure this out. In the end I used this:

https://github.com/agoldis/webpack-require-from

Worked like a charm, client side and server. Be aware you need to set a global.MY_BASE_URL in your node/server somewhere AND you need to inject a window.MY_BASE_URL somewhere in your HTML. Then just configure webpack.

plugins.push(new WebpackRequireFrom({variableName: 'MY_BASE_URL'}));

Upvotes: 0

Ryan Miller
Ryan Miller

Reputation: 1053

Late follow-up here, but we eventually solved this issue.

We found that setting __webpack_public_path__ globally in our Node.js process did result in the correct public path being applied to our assets in our server bundle.

Once that global is present both on the window (e.g. client-side), and globally in the node process (e.g. server-side), things started working as we wanted.

Upvotes: 2

Related Questions