Keeping asset and public path different in vue app for CDN - vue-cli

vue has this option publicPath which lets an app to be deployed on subpath: foobar.com/my-path , making links and every asset accessible via it.
From performance standpoint, I want to enable CDN on my application's assets. How can I use the URL specifically for assets (and not the hyperlinks)?
Example:
./my-path/assets/app.js should become https://my-staging-cdn.com/my-path/assets/app.js
./my-path/url-2.html should remain the same
The configuration below allows me to set the path and assets directory, but not able to figure out how to set cdn URL for assets
module.exports = {
publicPath: ‘/my-path/‘,
assetsDir: 'assets'
}
Cannot do:
publicPath: process.env.NODE_ENV === 'production' ? 'https://my-staging-cdn.com/my-path' : '/my-path/', as it will change the URL in application's links too.

Wasn't able to get the CDN working or assets out of the box. I tried other strategies like pre-rendering or Nuxt, but because of huge number of pages, it wasn't an option.
The objective was to get SEO bots to read rendered page, so I circled out on Rendertron and deployed it's instance and put it in my reverse proxy behind the application. This worked.

Related

Serve html directly from Google Cloud Storage and resolve relative links

I have simple html file, that includes css like this:
<link rel="stylesheet" href="./css/style.css" />
I uploaded this html file and css file too google cloud storage, and set permissions to public.
In my application, written in node js, I want to serve this html file when user access my root page.
In my application I have following code:
public async getPublicFile(opts: IGetFileOpts): Promise<File> {
const bucket = this.storage.bucket(opts.bucket);
return bucket.file(path.join(opts.type, opts.fileName));
}
#Get()
public async serveFile(#Res() response: Response) {
const file = await this.storageService.getPublicFile({
organization: organization,
fileName: 'index.html',
type: 'resources',
});
file.createReadStream().pipe(response);
}
This works as expected. It will server index.html from bucket. However, since this html file have relative link to css file, it will not load css file since it cannot find it.
How can I fix this, so that also css file will be served? Currently I am running this on local computer, but it will be deployed to Google Compute Engine.
I found this link for AppEngine https://cloud.google.com/appengine/docs/standard/go/serving-static-files
Here in AppEngine I can define some handlers like this:
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /static
static_dir: public
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto
but as I understand this will not work on local machine.
Also, how do ecommerce companies solves this issues? For example, every shop can have different theme that can be customizable. So I understand that every tenant has own bucket and in tenant bucket, this customizable theme is saved correct? So how I assume that the should have similar issue like me. How do the cope with this situation and how do the handle it?
You are currently trying to reach bucket static css file from an index.html served on your google app engine url. This just can't work out of the box.
There are many options to solve this:
Serve your index.html from the same bucket in public where are your other static files likes css. This has also the benefit of beeing served as CDN which is more efficient. (this is the way I recommand if possible, the only case you cannot do this might be when you want to compute serverside html things in the index.html file before sending it back to the client, but there are great chances this can be done client side)
Build absolute pathes to your css ressources in the index.html "on the fly" or "statically" so the link tag might look like :
<link rel="stylesheet" href="https://bucketurl.com/css/style.css" />
Serve all your content with your app programmatically with a special route that will serve static content by reading files from bucket like you do with your index.html. This should let you keep relative pathes for other static files.

Nuxt Heroku Deployment Problem, It uses localhost instead of the website url

This is my first time deploying a nuxt app to heroku, I've followed the instructions I've found on nuxt guide.
Created the heroku app & added the following configuration:
added the procfile with the following line: web:nuxt start
And it worked, When I go to: https://coupongb-nuxt.herokuapp.com/ the website opened and the products are loaded but it seems the "infinit scrolling with uses $axios plugin isn't working, As well as opening a product page "by clicking a product card".
So I guess it's $axios that's making that error, Seems it's baseURL is localhost:3000 istead of the website domain
So my question is How to make this.$axios.$get(...) point to the website domain instead of localhost:300
You will need to set environment variables for this. https://cli.vuejs.org/guide/mode-and-env.html#environment-variables
Where ever you are configuring Axios have it look at the environment variable to set the baseURL, example:
Axios.defaults.baseURL = process.env.APP_API
Then create your .env files in the root of your directory:
APP_API=https://coupongb-nuxt.herokuapp.com/
Alternatively you can change the baseurl inline whenever you are creating a call to your api. For example
this.$axios.get('/example-path')
would be replaced with
this.$axios({ url: '/example-path', baseURL: 'https://coupongb-nuxt.herokuapp.com' })
Alternatively to Tim´s response.
Add this at the top of your file:
const DEV = process.env.NODE_ENV !== 'production'
This way DEV will be true if enviroment is for development and false if it´s for production.
Below inside your export default object, you add the axios object:
axios: {
baseURL: development ? '' : 'https://your-heroku-url.com/'
}
And thats it, this way you don´t have to write a URL and the base URL every time you use axios.

Angular + node.js, setting the image static path (relative path)

I'm wanting to set the static path with node.js in app.js.
Such as the follow with setting in the public folder:
app.use(express.static(path.join(__dirname, 'public')));
When I use template engines, such as mustache https://mustache.github.io/,
you can set it using a relative path in the template to get a photo a.jpg, like:
<img src="./a.jpg">
When I save a user's photo in the public folder.
In Angular, how do I set the img url relative path from the node.js server folder.
If I save the the full URL in the DB and set the URL in img:
http://120.8.12.8:3000/a.jpg
//or
http://domainname:3000/a.jpg
html:
<img src="http://120.8.12.8:3000/a.jpg">
<img src="http://domainname:3000/a.jpg">
When I change the IP or domain name, the URL will fail.
How can I set it?
I would not save the full path in the database.
Otherwise, I will save information about how to generate the path.
You can have 2 fields in the database, like:
{
"relativePath" : "a.jpg",
"server" : "http://120.8.12.8:3000"
}
After this, and assuming you are consuming the resource from angular, you have several options:
You can directly mix the relativePath and the server in the frontend and create the URL to place in the link
You can hardcode in your angular app what is the "server", and mix that with the relativePath. In this case, in case you migrate the images you just need to modify the frontend
(The best for me). Create an endpoint in the server which gives you what is the host of the image server, call it from your angular app and then create the full link with this response and the relative image path.

ExpressJS static file serve always serves the same file

I have a expressJs setup which looks like this:
// Imports...
const app: express.Application = express();
const port: number = 3001;
const listener = new StatementListenerAPI();
app.use('/listen', listener.getRouter());
app.use('/welcome', router);
if (fs.existsSync('./client')) {
// Running in prod environment with pre built client directory. Serve this.
app.use(express.static('./client'));
}
app.listen(port);
So I have some routers connected to the express app, and at the bottom I declare that the directory client should be served statically. This directory contains an index.html as well as lots of JS, CSS and PNG files. However, no matter which URL I try to access from the express server, it always shows the code of the index.html within the statically served directory. The references to the JS and CSS files used inside the index.html also just return the code of the index.html.
I am using ExpressJS 4.16.3
What am I doing wrong?
Edit: So technically it works if using __dirname + '/client' instead of ./client. What I am now getting is that, when making GET requests from e.g. Postman (therefore "hand-crafting" the HTTP requests), I am always getting the correct results. If I call the resources from within my web browser, it still always shows the website (resolves the index.html). However, now all resources like JS and CSS scripts are being resolved properly, so apperantly Chrome resolves those dependencies properly, I am just wondering why I am still getting the contents of index.html as result when requesting some of the assets or some of the express endpoints via Chrome. API calls via code are working fine, so its only why manual chrome requests show this weird behaviour, at this point I am only asking out of curiosity.
Answer to your original question:
The path supplied to express.static should be relative to the directory from where you launch your node process or an absolute path. To be safe construct an absolute path (ie from the current directory or file). For example:
app.use(express.static(__dirname + '/client'));
Regarding your followup question:
I assume this is because Chrome uses heavy caching and it thinks this folder should return the html file. You can try and reset all caches in Chrome, or just for the page.

Set Base URL for Preact CLI

Using Preact CLI is it possible to set the path where the app will be hosted outside of the root directory?
For instance hosting the app at http://mywebsite.com/relativepath/index.html
You have several problems to solve:
1. Get Webpack to output the correct paths in your html
This is done via creating a preact.config.js in your root folder, and put the following in there
export default (config) => {
config.output.publicPath = '/relativepath/';
};
2. Set your navigation and assets links in your app
The best way to solve it in my opinion is to use a global variable which you can be used in your app. So again, edit the preact.config.js to the following:
export default (config, env, helpers) => {
config.output.publicPath = '/relativepath/';
// use the public path in your app as 'process.env.PUBLIC_PATH'
config.plugins.push(
new helpers.webpack.DefinePlugin({
'process.env.PUBLIC_PATH': JSON.stringify(config.output.publicPath || '/')
})
);
};
3. Routing
When using your preact app, it should be no problem to navigate. However, if you try to load a fresh URL e.g. www.myserver.com/relativepath/mything/9, the server doesn't know that it should load your single page app living at www.myserver.com/relativepath/index.html
You have two options:
a) Server-side routing
Make sure your all the requests to relativepath (including e.g. relativepath/mything/9) will be rewritten to your app's relativepath/index.html (in case of using Apache).
Then your Javascript can process the routes, e.g. preact-router
b) Client-side routing (recommended)
The easier option for enabling reloading of URLs is to use hash urls, thereby avoid going through the server when loading a URL.
Your URLs will look something like www.myserver.com/relativepath/#/mything/9
The server ignores the part after # and only loads (hopefully) /relativepath/index.html
You can use e.g. the preact-router with Hash History to avoid server-side routing, read about it here https://github.com/developit/preact-router#custom-history
I'm proxying from http-proxy-middleware to the preact-cli dev server and these settings worked for me in preact.config.js
export default (config, env, helpers) => {
config.output.publicPath = '/relativepath';
config.devServer.devMiddleware.publicPath = "/relativepath";
};

Resources