Issue generating Service worker with sw-precache in react - reactjs

I have created a react app using create-react-app.
Then I decided I need to edit/update the service worker code as per my need.
I am trying to build the app now using sw-precache (as its supposed to help building the custom service worker and automatically refer to the hashed static files).
This is the config I am using in 'sw-precache-config.js' -
module.exports = {
staticFileGlobs: [
'build/static/css/**.css',
'build/static/js/**.js',
'index.html',
'/'
],
swFilePath: './build/serviceWorker.js',
templateFilePath: './service-worker.tmpl',
stripPrefix: 'build/',
handleFetch: false,
runtimeCaching: [{
urlPattern: /this\\.is\\.a\\.regex/,
handler: 'networkFirst'
}]
}
This is the build command in my package.json -
"build": "react-scripts build && sw-precache --config=sw-precache-config.js",
However, I am facing two issues after the build -
Even though I have mentioned in the config file that the service worker name should be 'serviceWorker.js', the build process is generating two service worker files -
serviceWorker.js and service-worker.js
In the generated serviceWorker.js (build by the build script), 'index.html' file is not being mentioned in the precache (so the service worker is not caching index.html as intended)-
var precacheConfig =
[["static/css/main.d35a7300.chunk.css","5cf96316c6919194ba6eb48522a076f0"],["static/js/1.6105a37c.chunk.js","ae3537cefdcf8ee5758c3af13aab4568"],["static/js/main.4857c4da.chunk.js","9d6cc8fb962129f3e8bc459c85d39297"],["static/js/runtime~main.229c360f.js","3b44b5daad3fcbefa8b355dfbc3d9630"]];
Please let me know if I can clarify anything else.

Replace index.html in staticFileGlobs with build/index.html
You are getting two service worker files because the name you are specifying: serviceWorker.js is different from the default name CRA goes with: service-worker.js
Change your swFilePath to service-worker.js and that should fix it.

Related

React/vite app with base URL that does not apply to static links in the main HTML file

I have a question, around base urls. I have a React/Vite application that will get deployed into a webserver that hosts many other web-properties, and as part of this, all web-properties include shared JS and CSS. These shared JS/CSS are all served off the root do the domain (ex. https://www.my-domain.com/assets/shared.js). These includes are just hard coded into my main HTML file (usually index.html, but in my case root.html)
My React app however is served from https://www.my-domain.com/apps/catalog/root.html.
If i run my app locally with just npm run dev, everything works - but but my app is served off the root. I thought the right way to have this all run off my /apps/catalog/ based URL was to run all my vite commands with --base=/apps/catalog which seems to almost work; the problem is it rewrites thee static shared includes, which break them, since theyre expected to be served off the root.
I think, i need to figure out how to mark specific includes as not being effected by the base URL rewrite? Or, is there a better way to approach this?
My HTML file w/ the static includes of the "shared" assets. I dont want to hardcode the "real" domain in the src URLs since then my local proxy can't trap them and grab them serverside preventing CORS issues.
// /src/root.html
<html>
<head>
<!-- served from: https://www.my-domain.com/assets/shared.js -->
<script src="/assets/shared.js"/>
<!-- served from: https://www.my-domain.com/api/shared.js -->
<script src="/api/shared.js"/>
.. etc ..
</head>
<div id="app"></div>
</html>
My vite.config.js where i start to try to introduce the notion of a base url (and a non-index.html named "main" file)
The local proxy so these static includes resolved without CORS issues, for local dev (it proxies these static assets out to the Shared host, and everything works well locally).
// src/vite.config.js
export default defineConfig({
plugins: [react()],
build: {
assetsDir: 'static-assets',
rollupOptions: {
input: {
app: './root.html',
},
},
},
base: '/apps/catalog/',
server: {
open: '/root.html',
proxy: {
'^/assets/.*|^/api/.*': {
target: 'https://www.my-domain.com',
changeOrigin: true
}
}
}
})
And my package.json where i tried to also set the base URL.
// package.json scripts
"dev": "vite --base=/apps/catalog/",
"build": "vite build --base=/apps/catalog/"
I had the same problem with Laravel 9 + vite v3.2.5.
I fixed it (after hours) with the experimental renderBuiltUrl:
import {defineConfig, loadEnv} from 'vite';
// load env variables to get base url
process.env = Object.assign(process.env, loadEnv('production', process.cwd(), ''));
export default defineConfig({
// ...
experimental: {
renderBuiltUrl(filename) {
// here we set the base url. You might have to change this for react:
return process.env.APP_URL + '/build/' + filename;
}
}
}
Note the warning in the documentation:
This feature is experimental, the API may change in a future minor without following semver. Please always pin Vite's version to a minor when using it.

PM2 serve SPA build folder. It works but has tons of errors like "Error while serving ... ENOENT: no such file or directory..."

The problem is that the logs are flooded, but it works fine.
The build folder contains the build from React using CRA (Create React App).
So from the PM2 Docs I have this:
ecosystem.config.js
module.exports = {
name: "projectName",
script: "serve",
watch: true,
env: {
NODE_ENV: "production",
PM2_SERVE_PATH: './build',
PM2_SERVE_PORT: 5001,
PM2_SERVE_SPA: 'true',
PM2_SERVE_HOMEPAGE: './index.html'
},
}
I'm using PM2 serve command.
Command to start PM2 process:
pm2 start
Errors
Only happens when I enter for the first time or when I reload.
Error while serving /.../projectName/build/routeX with content-type text/plain : ENOENT: no such file or directory, open '/.../projectName/build/routeX'
I think you have to find the nature of those requests leading to an error. If they are originated from your app, then you have either to put away what causes that request or let something to be in that place inside of your build folder (depends on request's reason). If they are originated not from your app, then you should figure out where they come from. "Network" Tab of DevTools should help you in both cases
This issue is fixed in pm2 v5.2.0
https://github.com/Unitech/pm2/pull/5272

Service worker not found (404) on deployment: React-Django-Heroku

I'm trying to get my first service worker registered on a Heroku app. Front end has been built using create-react-app, backend uses Django on the same server. I've made a basic "hello world" service worker which works in development, but gives a 404 error in production. I think I might be misunderstanding the basic file system that I'm using in production.
My file system on my local directory essentially looks like this:
root
- public
- index.html
- sw.js
static
- manifest.json
- src
- app.js
- serviceWorker.js
...
serviceWorker.js checks the browser and then attempts to register the service worker:
...
navigator.serviceWorker
.register(`${process.env.PUBLIC_URL}/sw.js`)
.then(registration => {
...
//process.env.PUBLIC_URL returns http://localhost:3000/ in development, and https://www.mydomain.app/ in production
sw.js just contains dummy code:
self.addEventListener('install', function(event) {
console.log("Hello World")
})
When this is deployed to Heroku, yarn build packages everything into a build directory, which looks like:
build
- index.html
- sw.js
- service-worker.js // added automatically by web-pack
- asset-manifest.json // added automatically by web-pack
- precache-manifest.xyz.js // added automatically by web-pack
- static
- css
- js
- manifest.json
In production, this fails to find the file sw.js during the register() function. The same error is happening with the auto-generated service-worker.js, where it works in development but not in production (404):
"TypeError: Failed to register a ServiceWorker for scope ('https://www.mydomain.app/') with script ('https://www.mydomain.app/sw.js'): A bad HTTP response code (404) was received when fetching the script."
I think my use of PUBLIC_URL is correct, as it works in development and production to find manifest.json at<link rel="manifest" href="%PUBLIC_URL%/static/manifest.json" />. I've checked the file system by using heroku run bash and everything seems to be in the right place, what am I missing?
Found the answer here, maybe this will help someone else.
I needed to serve the sw.js file as a view with django urls:
from django.views.generic.base import TemplateView
urlpatterns = [
...
path('sw.js', TemplateView.as_view(template_name="sw.js",
content_type='application/javascript'), name='sw.js'),
...
]

where does /static/js folder come from?

I'm new to React, just a question on the bundle js files produced by webpack.
Currently when I I run my app, and I check chrome dev tool, I found 0.chunk.js, bundle.js, main.chunk.js are under localhost/static/js, I don't have static folder in my react app, so where does /static/js folder come from? was it create by chrome?
Those files are generated by webpack.
To specify, you can run command npm run eject then you can see a folder named scripts.
In this folder, first let's check file start.js where run when you run npm start.
const devServer = new WebpackDevServer(compiler, serverConfig);
It using WebpackDevServer create a dev server run on your local to host your app, so you can access app through localhost:3000. Next let's check compiler parameter.
const compiler = createCompiler({
appName,
config,
devSocket,
urls,
useYarn,
useTypeScript,
webpack,
});
Inspect config you can see it created from configFactory
const config = configFactory('development');
Check configFactory you can see it is a function return server configuration as an object include property named output.
output: {
...
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',
}
Here is what you are looking for.

Create-React-App build - "Uncaught SyntaxError: Unexpected token <"

I realize this question has been asked multiple times but nothing has worked for me...
I'm trying to create a static build of a create-react-app project but I'm getting the following errors:
Uncaught SyntaxError: Unexpected token < 1.ca81c833.chunk.js:1
Uncaught SyntaxError: Unexpected token < main.7ced8661.chunk.js:1
Due to these files being minified, I'm not sure where to begin in debugging them.
Per other SO responses, here are some things I've tried:
//Original index.html file, which gets included in the built file:
<script type="text/babel" src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
//package.json
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
//.babelrc file
{
"presets": ["react", "es2015", "stage-1"]
}
Not sure if this is relevant, but I have this on my express server, which I believe is standard:
if (process.env.NODE_ENV === "production") {
app.use(express.static('client/built'));
app.get("*", (req, res) => {
res.sendFile(require('path')
.resolve(__dirname, 'client', 'build', 'index.html'));
})
}
Assuming it's actually a JSX issue, the whole thing is very confusing - shouldn't create-react-app be handling JSX automatically?
UPDATE: I just posted this question but already have a relevant update. I'm able to serve the page statically through pm2 by running pm2 serve build so I think the issue may be with my server configuration.
Thanks this helped me a lot.
Just wanting to add to this with an example from a Create-React-App project that had the same solution:
I received the same error after deploying to heroku.
Uncaught SyntaxError: Unexpected token < after serve -s build
For me the problem was in the packages.json file. The "homepage" parameter i gave was incorrect. Changing this to the correct heroku URL solved the issue.
"homepage": "https://myapp.herokuapp.com/"
Hope this addition is helpful.
I ended up finding an answer here: https://github.com/facebook/create-react-app/issues/1812
I trimmed down the full solution from above, but I changed:
app.use(express.static('client/build'));
app.get("*", (req, res) => {
res.sendFile(require('path')
.resolve(__dirname, 'client', 'build', 'index.html'));
})
to:
const root = require('path').join(__dirname, 'client', 'build')
app.use(express.static(root));
app.get("*", (req, res) => {
res.sendFile('index.html', { root });
})
It's definitely a bit strange to me that the first block didn't work. I assume it has something to do with the relative links in my React project since I do get an index.html file delivered to browser, despite getting the error. Maybe a completely static file would work with the first block, but I'd be interested to know if that's accurate.
just remove
"homepage": "your app url "
from package.json to fix it
Remove the "homepage": "app-url" from package.json. Absence of homepage in package.json will assume that it will be hosted at the server root, or you will serve the build with serve -s build.
And Yes, specifying homepage will be helpful when you are going to deploy the App in a sub-directory of the server root.
To host your app on the IIS with the name somedomain.net and your solution already has a Web API project.
You will map the solution folder with the main Web app i.e., somedomain.net
You will convert the Web API project to Application from IIS.
Then you will convert the build folder of React App to web App just like Web API
To make front-end App working specify the "homepage": "somedomain.net/React-Project/Client-App/build"
I created a build version of react app using "npm run build".
I have a server (node/express).
I wanted to include the build in server side and deploy to heroku. What i did is copied build folder to server root folder and used code in server side startup file:
app.get('/*', function (req, res, next) {
if (!req.path.includes('api'))
res.sendFile(path.join(__dirname, 'build', 'index.html'));
else next();
});
I was getting the same error. So i just set the path for static contents at starting:
var app = express();
//here below
app.use(express.static(path.join(__dirname, 'build')));
And my static index.html was served fine and was able to find resources css and js.
I had faced the same issue when deploying my react build to production. After spending hours trying to figure out what went wrong on a previously working code, I figured out a mistake I made in deployment.
I hadn't copied the folder static inside build to the server because I used scp build/* to copy the build folder in place of scp -r build/*.
I understand that this is not the exact answer to the question asked here. But I had tried out almost all possible options from answers given by experts here before I noticed the error I was making.
Hence, adding this here as a pointer to anyone facing similar issue to verify the deployment steps as well.
UPDATE:
Recently I need to deploy create-react-app project to subpath of client's domain which is http://example.com/foo/bar
This approach is using Nginx, React-Router.
Add PUBLIC_URL to .env file.
+ PUBLIC_URL=/foo/bar
Add basename to <BrowserRouter>.
- <BrowserRouter>
+ <BrowserRouter basename={process.env.PUBLIC_URL}>
Change your Nginx config.
location /foo/bar {
alias /path/to/build;
try_files $uri /$uri /foo/bar/index.html;
}
Here is a create-react-app document about how to build with .env:
Customizing Environment
Hope this solution helps!
Ran into the same issue when I want to deploy the static build of a create-react-app project to my linux server.
I solved with this issue comment on cra's github and the cra's official document about how to deploy production build.
For example:
I want to put the production build website under something like http://example.com/foo/bar.
When I deploy without changing any default settings, I will get this "Uncaught SyntaxError: Unexpected token <" error and nothing shows up on the screen.
Here is the solution:
Add homepage parameter to your package.json.
+ "homepage": "/foo/bar"
Add "/foo/bar" to all of your static resources in css which will be like:
.dummyimage {
- content: url('/dummyimage.jpg');
+ content: url('/foo/bar/dummyimage.jpg');
}
Add "/foo/bar" to all of your links and routes.
- linkTo: '/contact'
+ linkTo: '/foo/bar/contact'
Changing a little of your serve program's code, in node.js/express it will be like:
- app.use(express.static(path.join(__dirname, '/build')));
+ app.use('/foo/bar/', express.static(path.join(__dirname, '/build')));
Build again.
Deploy build/ to the server.
Restart your serve program, like node.js/express.
Problem solved!!
Hope this solution is helpful.
Just remove homepage key in package.json and also don't forgot to remove the basename in BrowserRouter, if you're using the react router.
That's it. It's working
i have faced kind of same issue when i want deploy my react app to github-pages :-
its need's follow few guidelines
Repository name should be in small latter
If project name same as repo name that usefull
addd {
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
} on package.json
add homepage script at the starting of the package.json
{
"homepage": "http://[Username].github.io/[reponame]",
"name": "--",
"version": "--",
"private": boolean,
}
As most of us have already suggested removing homepage property from package.json
Let me explain, why it worked in my case:
Earlier I had setup my project to be hosted on Github pages and as a result, it had homepage property set to something like "https://shubhamshd.github.io/supplyChainApp"
However as there are known navigational errors mainly related to BrowserRouter package on Github-pages, I had to switch to other hosting platforms.
And as I forgot to remove the homepage property, deployment did not work on any of the platforms like Vercel or Netlify.
It was after long hours of search and trial, that I finally stumbled upon this thread, specifically the #Shashwat Gupta and finally managed to resolve it by removing the unwanted homepage property.
If you are deploying your client to S3, when deploying with react-deploy-s3, assign the distribution-id from CloudFront
react-deploy-s3 deploy \
--access-key-id XXXXXXXXXXXXXXXXX \
--secret-access-key XXXXXXXXXXXXXXXXXXXXXXXX \
--bucket XXXXXXX \
--region us-east-1 \
--distribution-id XXXXXXXXXXXXX <---

Resources