I am working on React web app and to deployed it I used create-react-app. There is a file called registerServiceWorker.js which takes care of initializing the service worker. I want to cache some files on install event however the self.addEventListener('install', event gives me the error "Unexpected use of 'self' no-restricted-globals". I manage to get rid of that by changing self to window, however the install event is never being fired. How to use this "build in" service worker in React? Or can I create the other service worker?
After struggling with this myself, I finally figured out the following pieces of information:
the serviceWorker.js file in the default CRA project is not the same sort of service-worker.js file described by the PWA documentation from Chrome and Mozilla. That's not where the self.addEventListener statements go. They go into the file referenced by CRA's serviceWorker.js, specified by the string
const `swUrl = ${process.env.PUBLIC_URL}/service-worker.js`
By default, that service-worker.js is a file that you cannot access or modify! You will need to create your own service-worker.js file in the /public folder and point swUrl to it instead. It should point to the location as a string, statically, which means it will not get integrated as part of the build process and self will correctly refer to the module instead of the global context.
I found the simple solution. This utility is perfect for that: https://github.com/bbhlondon/cra-append-sw.
cra-append-sw
Utility tool to append custom code to ServiceWorker created by Create
React App.
It allows to keep the default CRA configuration (no ejecting). It
simply appends custom code to the ServiceWorker file created by CRA
build scripts. By default, it bundles the code using very basic
Webpack+Babel configuration (this can be omitted; see options).
Installation
$ npm install cra-append-sw --save
Usage
"start": "react-scripts start && cra-append-sw --mode dev
./custom-sw.js",
"build": "react-scripts build && cra-append-sw
./custom-sw.js",
Related
I'm in WSL2, and my react app does not update any changes at all, only updates when re-running "npm start"
I've tried "npm install react-dotenv" and creating an .env file with
FAST_REFRESH=false
CHOKIDAR_USEPOLLING=true
doesn't work
tried in the package.json
"start": "CHOKIDAR_USEPOLLING=true react-scripts start"
doesn't work
any suggestions? I don't even mind manually refreshing the browser, it's just that it won't update unless I restart the whole thing.
You do not have to install an additional dotenv package since Create-React-App already supports environment variables natively. However if you use environment variables, you need to prefix them with REACT_APP. e. g. REACT_APP_MY_VARIABLE.
Also note: Whenever you update an environment variable you have to restart the app.
Take a look at the official CRA docs.
Now for the reloading problem. There are a couple of possible solutions:
Add a .env file to your project without third party package and
define a variable named FAST_REFRESH=false. (CRA advanced
configuration)
If you are using a Virtual Machine try adding CHOKIDAR_USEPOLLING=true to your .env file.
There is another common problem in CRA ^17.0.1 with hot reloading (Github issue - Hot Reload stopped working with React "^17.0.1")
if (module.hot) module.hot.accept();
Finally (and this is the most likely solution in my opinion) try to move your project folder to somewhere, where npm can automatically recompile in WSL. E. g. move project from your desktop to your actual home directory.
I'm trying to intercept fetch in my React app with the code from this answer
window.addEventListener('fetch', event => { console.log("FETCH CAPTURED"); } );
But I never see the FETCH CAPTURED log. Is it possible to intercept fetch not in service worker?
'fetch' is a supported event / argument by the ServiceWorker#addEventListener method. It does not seem to be an event that has any meaning to the ElementTarget#addEventListener method, which is the method invoked when you call document.addEventListener. Here is a list of supported methods.
You'd need to use cra-append-sw to append your code to the Service Worker automatically.
From the documentation:
Utility tool to append custom code to ServiceWorker created by Create React App.
It allows to keep the default CRA configuration (no ejecting). It simply appends custom code to the ServiceWorker file created by CRA build scripts. By default, it bundles the code using very basic Webpack+Babel configuration (this can be omitted; see options).
Usage:
$ cra-append-sw [options] <file>
Usage with create-react-app:
"start": "react-scripts start && cra-append-sw --mode dev ./custom-sw.js",
"build": "react-scripts build && cra-append-sw ./custom-sw.js",
You can also add your code manually in the generated file (without using cra-append-sw), but you'd need to do this every time you want to build your project.
I have a working application consisting multiple components created using create-react-app, each component is a separate app in itself again created using create-react-app.
All the components are ejected so that I could integrate it together.
Now, I want to publish the components to NPM/Private repository but as per CRA deployment guide, it doesn’t support publishing of CRA based components directly out of the box, it suggests using nwb, but I couldn’t figure out how to use nwb to publish ‘existing’ components.
I have also looked at the one of the medium post where it suggests using the babel-cli to generate the dist/build files but that’s failing for some babel configuration which works well otherwise.(sorry, don’t have link at the moment as I am posting this from cellphone).
Any help is appreciated.
You can do it by using babel-cli npm package which will compile your react application code and then you can publish it using npm publish command, the detailed steps are as follows.
Install the babel-cli package in your create-react-app using npm install babel-cli command.
Create .babelrc file and add following contents to use "react-app" preset provided by babel.
{
"presets": [["react-app"]],
}
Add distribute command in package.json using following code, this command compiles the code from src folder to dist folder. Generally, I do not include my test files in published library so the --ignore argument skips the tests files like *spec.js and *test.js, this argument is optional and you can remove --ignore spec.js,test.js if you would like to include test files in your published library. The --source-maps argument includes the source maps for the included source files :
"distribute": "set NODE_ENV=production&&babel src --out-dir dist --copy-files --ignore spec.js,test.js --source-maps"
Execute the command npm run distribute which will generate the files in dist folder.
Set private: false in package.json to make available for publish
Set main file of your distributed package using following command, in my case I directly use App.js
"main": "dist/App.js"
Add following code for publishing the package and provide repository related details
"publishConfig": {
"registry": ""
}
You can use npm run publish command to distribute your react app source code as library.
I switched to ReactJS from pure JS for my web frontend. I made my dev workflow slower. It used to be that I edit a file, refresh browser and it's there. But now, I have to run "npm run build" and wait for a few seconds before refreshing browser.
Is there a way I can do it without building? Or is there a way I can choose not to build a minified JS to save time?
1. Use webpack watch mode to build automatically.
Add --watch param to the script that starts your build
"start": "webpack --watch"
2. Hot module replacement
You can configure webpack to use hot module replacement, which basically puts your code in live edit mode and you don't have to refresh you browser to get the changes. Configuration might be tricky but will save you a lot of time.
For more info, refer official docs - Hot Module Replacement
3. Use create-react-app
If you are just starting your project, use create-react-app to generate the react boilerplate. It comes with built-in hot module replacement and optimal confguration for both development and production.
Navigate to a new dir and run
npx create-react-app your-project-name
This will create a new directory with the name you provided and everything else from there will be straight forward.
More info here - create-react-app
So create-react-app includes service worker functionality by default, which is lovely - all my static assets get cached for offline use out of the box. Cool, but now I want to take things a bit further and use indexedDB to cache some dynamic content.
Problem is, there's no service-worker.js file to modify. It gets generated during the build process.
Is there a way to add additional logic without ejecting create-react-app or redoing all the nice static caching stuff?
As you've observed, create-react-app's config is locked down, and the service worker logic is entirely defined in the config.
If you'd rather not eject but you want some customization, another option is to modify the create-react-app build process to explicitly call the sw-precache CLI after the normal build has completed, overwriting the service-worker.js that create-react-app generates by default. Because this involves modifying your local package.json, it doesn't require ejecting first.
There's some info on this approach here, and the general idea is modifying your npm scripts to look something like:
"build": "react-scripts build && sw-precache --config=sw-precache-config.js"
With sw-precache-config.js configured based on your needs, but including
swFilePath: './build/service-worker.js'
to ensure that the built-in service-worker.js is overwritten.
I had the same problem and without doing eject, I could replace the default service-worker with workbox-generated one to add runtime caching webfonts, api calls, etc.
install workbox-build
prepare src/sw-template.js to add your registerRoute calls
prepare /build-sw.js to copy workbox file to 'build' folder and injectManifest
modify package.json scripts to run above build-sw.js
modify src/registerServiceWorker.js to replace the default one
You can find detailed file changes here.