How do I add cache-control response headers to index.html and static JS bundles created by Webpack in Springboot application? - reactjs

Basically, I have springboot application serving my index.html and other static JS files which includes(runtime, vendor, main) chunks created during the production build by Webpack. How do I set cache-control settings for index.html and chunks separately so that index.html won't be cached and chunks will be cached on the client-side? Currently, I have my resources under static folder like the following:
├── static
│ ├── index.html
| |-- bundles
│ │ ├── main.js
│ │ ├── vendors.js
│ │ ├── runtime.js
`
Basically, I am aiming for long-term caching of static assets on the client-side.

I interpret your question as asking how you can control this in Spring.
I think the better way to achieve what you want is to let Webpack output the different chunk-names so that they are cached for a long time (or until you deploy a new version of a chunk), not by specifically setting cache related headers for each filename.
The Webpack caching documentation recommends outputting the different chunk filenames to also include the contenthash.
output: {
path: path.join(__dirname, "build"),
filename: "bundle.[contenthash].js",
}
This will name your current bundle.js to something like bundle.7b4c86b268840bec8c4d.js. The first time a browser visits your site it will cache that chunk for a long time, typically a year but it depends on your configuration.
When you make changes to whatever code goes into bundle.[contenthash].js, the value of contenthash will change and the browser will cache that new version of your site/bundle since the filename doesn't match the cached bundle filename any more.
For more information, please refer to the aforementioned Webpack caching documentation

Related

Vercel - Deploy Flask Backend + React Frontend

I have a webapp that has React frontend with a Flask backend. I want to deploy this application onto a tool called Vercel. Can someone point me to an example tutorial/setup/example Github Repository that accomplishes this task
As I know, you can't deploy the Flask back-end on Vercel. I'm not familiar with Flusk, but I checked right now and you can deploy your Flusk back-end server on railway.app. Then hit from your front-end that you can deploy on Vercel.
It took me a while to figure this out as well, even though Flask usage is technically "documented" in the official docs. You need something like this:
your_app_root/
└── api/
├── function1/
│ └── index.py
├── function2/
│ └── index.py
└── index.py
#!index.py
from flask import Flask, Response
app = Flask(__name__)
#app.route("/", defaults={"path": ""})
#app.route("/<path:path>")
def catch_all(path):
# Everything above this line should look the same for each
# index.py. Modify lines below this to have different logic
# for different routes.
return Response(
"<h1>Flask</h1><p>You visited: /%s</p>" % (path), mimetype="text/html"
)
Basically, each function is going to be a separate Flask app. So you cannot do any routes within the Flask api with #app.route. It needs to all be folder based because Vercel is doing the routing.

Heroku "content not from webpack is served from /app/public" despite using all default create-react-app config

I'm deploying a pretty basic front-end only React app (essentially a static site) to Heroku via an auto-deploy integration with Github. I've done this before with a more complicated app and had no issues. But now I'm getting the following output in my logs when I deploy:
2020-05-02T11:18:53.190530+00:00 app[web.1]: [34mℹ[39m
[90m「wds」[39m: webpack output is served from
2020-05-02T11:18:53.190635+00:00 app[web.1]: [34mℹ[39m
[90m「wds」[39m: Content not from webpack is served from /app/public
2020-05-02T11:18:53.190727+00:00 app[web.1]: [34mℹ[39m
[90m「wds」[39m: 404s will fallback to /
2020-05-02T11:18:53.190910+00:00 app[web.1]: Starting the development
server...
2020-05-02T11:18:53.190912+00:00 app[web.1]:
2020-05-02T11:18:53.287654+00:00 heroku[web.1]: State changed from
starting to crashed
When I first got this, the statement was accurate. I had a few images that I was loading like src='/image.jpg'. But I moved all assets that I'm actually using in my app into src/images and am importing them as components now. I've gone over every file in my src directory four times and there are no longer any references to files in the public directory.
I haven't done any custom Webpack configuration, it's all default CRA. So why does it still throw this error and how do I resolve it?
Project hierarchy:
├── src
│ └── index.js
│ └── app.js (etc)
│ └── images (this is where I am importing any images into my components now)
├── public
│ ├── index.html
│ ├── favicon.jpg
│ │── manifest.json
│ └── robots.txt
├── package.json
├── package-lock.json
├── .gitignore
webpack.config.js
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
? 'source-map'
: false
: isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment &&
require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(Boolean),
output: {
// The build folder.
path: isEnvProduction ? paths.appBuild : undefined,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: isEnvDevelopment,
// There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files.
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
// webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: paths.publicUrlOrPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction
? info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
// Prevents conflicts when multiple webpack runtimes (from different apps)
// are used on the same page.
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
// this defaults to 'window', but by setting it to 'this' then
// module chunks which are built will work in web workers as well.
globalObject: 'this',
},
So, I got a Solution, Heroku uses nodejs buildpack as default. You'll need to add that of CRA(Create react App).
First, check the build pack you're using heroku buildpacks -a <appname>
then change to CRA buildpack heroku buildpacks:set mars/create-react-app -a <appname>
Then redeploy.
You can read this article for more configuration
Heroku uses default build pack as heroku/nodejs.Need too changes your buildpack configuration in your heroku app settings.
You can use add below git url as build pack for react app
https://github.com/mars/create-react-app-buildpack
You can add object "engines" inside package.json (version node & npm using build your app)
"engines": {
"node": "10.15.3",
"npm": "6.14.5"
}
***check version : node -v & npm -v
P/s: It's working with me.

Aws-Amplify: manifest.json and env.json loading index.html

The React App my am building has a manifest.json and a env.json as follows,
However, when I publish the website using AWS-Amplify to a S3 bucket, the manifest.json and env.json loads my index.html instead. Everything is working as it should in localhost but in production we are having the previous issue even though we can get other files as icons and robot.txt.
The content of our public folder is the next:
asset-manifest.json
browserconfig.xml
ec4c4f981671b5dee24ab5f541f07720.png
ef7c6637c68f269a882e73bcb57a7f6a.woff2
env.json <----- loading index.html
icons
index.html
main-5fbcf0b95e5bf6891f54.js
main-5fbcf0b95e5bf6891f54.js.LICENSE.txt
manifest.json. <----- loading index.html
robots.txt. <------ working
service-worker.js
The amplify.yml file looks as:
version: 0.1
frontend:
phases:
preBuild:
commands:
- npm install
build:
commands:
- NODE_ENV=$MY_ENV_SELECTOR node ./node_modules/webpack/bin/webpack.js --mode production --env=prod
artifacts:
baseDirectory: dist
files:
- '**/*'
cache:
paths:
- node_modules/**/*
It looks like it is serving us the index.html because it is not finding the requested files, but we do not have a clue about why this is happening.
We hope anyone can help us with this problem.
I may have found the answer, working for me.
So I am building a Single Page App (SPA) using React and React-router.
I had to put in a redirect rule to manage the way the router works. As per the amplify docs.
Source address: </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>
Target address: /index.html
Type: 200 (Rewrite)
Seems like this is also pushing the request for manifest.json to go to index.html
I solved this by adding another rule to my amplify console:
Source address: /manifest.json
Target address: /manifest.json
Type: 200 (Rewrite)
Would be interested to know if this works for anyone else.
I found the problem.
Basically Amplify has a redirect functionality that we needed to configure for serving this files.
Thanks to everyone!

Proper app.yaml handlers configuration for Google App Engine for a static html website

Here is the file structure of my website:
public
│ 404.html
│ app.yaml
│ index.html
│ index.xml
│ prereqs.zip
│ sitemap.xml
│ sof2018.py
|
├───categories
│ index.html
│ index.xml
├───css
│ styles.css
├───home
│ index.html
├───js
│ scripts.js
├───prerequisites
│ index.html
├───scripts
│ │ index.html
│ │ index.xml
│ │
│ ├───page
│ │ └───1
│ │ index.html
│ │
│ └───sof2018
│ index.html
├───tags
│ index.html
│ index.xml
└───usage
index.html
Basically I need to ensure the following:
if any folder is called with trailing slash (say /scripts/page/1/ or /home/), it should look for index.html inside that folder
if any folder is called without trailing slash (say /scripts/page/1 or /home), it should look for index.html inside that folder
if any file (say /css/styles.css or /prereqs.zip) is called, it should return the file
The way to differentiate between files and folders could be to simply to check if there is a period(.) since all my files have extensions. Though I guess someone else might benefit with a solution that handles extension-less files also.
I have tried a number of different regexes, all of them seem to missing out some case or the other. Also tried all the solutions proposed in previous questions on stackoverflow on pretty much the same thing.
I'm not looking for an app.yaml tailor-made for my website, that can be done by manually dealing with each of the folders, cases, etc.
I'm looking for a general solution that would work exactly how a traditional web host would work, since I'm guessing that would benefit others as well. Then I'll be free to add/change content/structure without having to update app.yaml every time.
P.S. In all honesty, google should have themselves provided the solution, but they haven't. I'm guessing even proper web devs aren't regex masters.
P.S.2 The website is made using the Hugo static site generator. I can confirm it is working on a traditional web host (GoDaddy). Also I don't know enough html/css/js to tell for sure what is the actual internal working of the site; if required I can provide the source files.
You cannot achieve all of this on (standard environment) GAE with a completely static website. That's because you have no way of telling ahead of time (i.e. when creating the app.yaml config) if /some/path/item is a file or a folder and thus /some/path/item or /some/path/item/index.html should respectively be returned.
It's not a matter of writing the right regex, it's a matter of wanting 2 different outcomes for the same regex.
To achieve what you want you need the app to check the condition at runtime and make the decision - not a static site anymore.
If you drop your 2nd bullet you can achieve the rest with this:
- url: /(.*)/
static_files: public/\1/index.html
upload: public/.*/index.html
- url: /(.*)$
static_files: public/\1
upload: public/.*
If you have a way of differentiating files from folders you may be able to come up with a scheme. For example by specifying that all filenames must have extensions (and directories cannot have . in their names), then you can do something like this:
# /optional/path/folder/ - serve index.html inside
- url: /(.*)/
static_files: public/\1/index.html
upload: public/.*/index.html
# /optional/path/name.extension => files - serve them
- url: /((.*\/)*[^\/]+\.[^\/]+)$
static_files: public/\1
upload: public/.*
# anything else is a folder - serve index.html inside
- url: /(.*)$
static_files: public/\1/index.html
upload: public/.*/index.html

My Axios call is returning a 404 error, React/Express

I am using React and Express to try and post an Article to MongoDB after clicking a button.
**server.js**
app.use(express.static("public"));
app.post("/articles/:id", function(request, response){
console.log(request.body);
});
and
**home.jsx**
addToFavorites = article => {
console.log(article);
this.state.savedArticles.push(article);
this.setState(this.state.savedArticles);
axios.post("/articles/" + article.id, {
title: article.title,
summary: article.summary,
writer: article.writer,
date: article.pub_date,
url: article.link
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
The console prints out the article so it is not undefined and the call catches the following error :
Error: Request failed with status code 404
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
Reading other posts, people have mentioned that the path does not exist, but I'm not sure what that means.
Any help would be greatly appreciated :)
UPDATE :
My main issue was just that I did not run node server.js before yarn start. I am new to React so I did not know that this was important.
Including the proxy in package.json was also important.
If you are running your express server on PORT: 8080,
Then add below line in package.json
"proxy": "http://localhost:8080"
Instead of working in development build ,you can create a Production build.
Rendering development build js files on UI takes a hell of a time as compared to production version which is very compact, compressed for better user experience and loading on UI.
In production mode the code runs on your client's machine, so this makes rendering of file on end user's browser very quick and performance enhancing.
Steps to change from development build to production build:
Hit ctrl + c in the terminal to exit from development build.
In your project directory To create a production build, use npm run build.
After the successful compilation of the above command, use serve -s build to deploy a static server.
If you see this output in the terminal
│ Serving! │
│ │
│ - Local: http://localhost:5000 │
│ - On Your Network: http://172.16.2.1:5000 │
│ │
You have successfully compiled the production build!

Resources