Set Base URL for Preact CLI - preact

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";
};

Related

Is there any dynamic way of changing the proxy target in React JS (or any other Front-end JS), without restarting the application?

Is there any dynamic way of changing the proxy target in React JS, without restarting the application?
I have multiple node JS servers in the local intranet (which Uses Private IPs, with No concept of deploying using public IP).
And I have one GUI using React JS, which will handle/manage multiple node JS servers.
Using one proxy settings configuration in package.json serves only one NodeJS server, If I update package.json with the next target in proxy, I need to restart the app again.
Is there any way to handle this?
First of all, it seems to be a bad idea to do so. You should have a stable / static proxy. Changing the proxy dynamically will cause many issues in your application.
you will have to handle n/w issues
you will have to handle white-listing/black-listing issues
assets loading issues and many other.
Still, if you want to try:
https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually
Check this URL.
This code worked for React 16.8.13
delete "proxy": {***} from package.json file
type npm install http-proxy-middleware
create the file src/setupProxy.js
-insert the code as following:
src/setupProxy.js
const {createProxyMiddleware} = require('http-proxy-middleware');
module.exports = (app) => {
app.use(
createProxyMiddleware('/endpoint/*', {
target: 'http://address/',
secure: false,
}),
);
};
src/proxy-config.properties
end.point='/endpoint/*'
target='http://address/'
secure=false
And then, you need to change the above code to get the current proxy from a file / DB as follows.
With some code, check whether the proxy is working or not
If not, get new proxy from the file/DB
With you NODE code (or manually), keep changing the proxy-config.properties file.

node Vue.js different code scenario if run in dev mode

I have Vue.JS front app with nodeJS backend based on expressJS. ExpressJS also used as web server for statically built Vue.JS app
Front app communicates with express backend via rest and websocket. It uses url host from window.location instance and easily communicates with backend
In production mode, when built application in static expressJS server area, everything work perfect
In dev mode, Vue use it's own web server, and backend urls based on window.location are incorrect because no expresJS on same host and port.
So my question is it possible change some code blocks if running in dev mode ?
Like something this :
if( devmode)
{
const url = "http://somebackendhost/rest"
}
else {
const url = location.host ....
}
}
I will assume you are developing your Vue app using Vue CLI
Changing app behavior depending on environment
In Vue CLI you can use Environment Variables
if(process.env.NODE_ENV === "development")
{
}
This works thanks to Webpack's Define plugin and big advantage is that process.env.NODE_ENV is replaced at build time by the real value. So in production build Webpack will see just if("production" === "development") {} and happily removes the code in optimization phase because it knows this can never be true
Better solution
But I would not use this approach for your problem. Using different API server (not same as the server used for serving Vue SPA) can easily lead to CORS problems
Exactly for this use case, Vue CLI (and Webpack Dev server used under the hood) supports proxying
vue.config.js
module.exports = {
devServer: {
proxy: {
'^/api': {
target: 'http://localhost:58300/',
ws: true, // websockets
changeOrigin: true,
}
}
},
},
This config makes Vue Dev server to proxy any request to /api to other server running at http://localhost:58300/ (your node/express app) and change the origin (so browser thinks response came from the dev server)
All of this can be done without Vue CLI but you will need to set it up by yourself in Webpack config...
The problem
You can't access this information from your browser.
But there are three solutions:
Solution #1
On compilation time create a variable in code which defines devmode (const devmode = true;)
Solution #2
Because your bundler can minify your variable names or changing the scope for security reasons, may be the situation where you can't access it.
So second solution is to define devmode in your localStorage.
Solution #3
Third solution is almost the best.
If you are developing, you are probably accessing your web app via localhost.
location.hostname will return the name of host, so you can make something like:
const devmode = location.hotname == 'localhost';
Best solution
Do not do this. Develop a fully working web app using local REST API and define the URL of REST API in some variable, so when you are preparing your production app, you or compiler just changes the URL adress variable in code of your REST API.
Why is this the best solution?
Because it do not impacts your end-user's performance and they will be loading less code, which is the best practise.
Post Scriptum
Don't forget to remove all devmode codepaths when compiling production version!

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.

Keeping asset and public path different in vue app for CDN

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.

npm start - developing React app - any way to set 'base href' or forward traffic to my back-end?

I am modifying existing React application which uses the relative URLs e.g.: /server/fetchRouteInfo.
The react app runs in context of a hostname e.g.: local.website.com, so it all works nicely as URLs get resolved to: local.website.com/server/...
I've found the npm start convenient to use to develop this React application. The problem is because of npm, my front-end app gets hosted under: localhost:3000, so the relative URLs no longer resolve to correct back-end and external resources.
What's the best way to connect my front-end app to desired back-end?
I've tried to use HTML <base href="local.website.com"> but it breaks the npm internal calls e.g. to static.js.
I know that I could modify the relative URLs to full absolute, but that's not the way I want to go.
Perhaps there is a way to forward / proxy-pass any traffic that goes to npm to my endpoint? In other words if there is request like: localhost:3000/server/... it would get internally proxied to: local.website.com/server/....
What's the common way to solve my problem, namely how to connect front-end to external back-end given the front-end uses relative URLs.
You can set the proxy in package.json. Just add one more parameter proxy with the desired value.
For more information, please refer to Proxying in Development
On React page there is proxy section: https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually
Looking up the component Github: https://github.com/chimurai/http-proxy-middleware
There is a way to provide custom filter.
Instructions:
Install component: npm install --save-dev http-proxy-middleware
Create file: src/setupProxy.js with this config
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
var filter = function(pathname) {
if (pathname.match('^/static')) {
return false;
}
return !pathname.match('^/$');
};
app.use(
proxy(filter,{
target: 'https://local.backend',
changeOrigin: true
})
);
};
npm start
This will redirect all traffic, except the: / (this is where my React app is served) and starting with /static (some NPM JavaScript).
I am not sure if it's the easiest way or not. I would've been easier if there is dedicated namespace e.g.: /api that you could use.
There was a caveat though. If you first need to login to your back-end which sets session cookies, those cookies won't persist if you use: localhost:3000 path (the localhost is not valid domain for cookies to be set).
My workaround was to add the entry in: /etc/hosts and create bogus domain.
127.0.0.1 local.host then use: local.host:3000 endpoint.
Another issue you might encounter if the session cookie is: Secure, that means that it won't be set for unencrypted protocols. Simply start the npm with https support: HTTPS=true npm start and contact using: https://local.host:3000 endpoint.

Resources