Reputation: 1053
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
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
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
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
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