So, I want to make a PWA for one of my CRA projects. The app has a different wallpaper everytime it loads, which it gets through an API. But since PWAs are supposed to have offline support, I wanted to have a fallback wallpaper which is cached. Or, even better the last result from the API is cached and returned till the user is offline. Something of a StaleWhileRevalidate strategy. But I can't figure out how to achieve this without ejecting from create-react-app. Any ideas?
Thanks
Ok, I figured it out myself. In case anyone else needs this, you can create a file named add_to_precache.js in your project's root directory and add the following code to it:
let fs = require('fs');
let build_dir = "./build";
let precache_re = /precache-manifest\.[a-zA-Z0-9]*\.js/
let urls_to_add = [
/*
Path to files you want to add relative to build directory. Along with any other homepage value you have. Eg: "/app/background.jpg"
*/
]
function generate_revision(){
var chars = "abcdefghijklmnopqrstuvwxyzABCDEEFGHIJKLMNOPQRSTUVWXYZ0123456789".split('');
var revision = '';
for(let i=0;i<24;i++){
revision += chars[Math.round(Math.random() * 62)];
}
return revision;
}
fs.readdir(build_dir, (err, files) => {
for(let file of files){
if(precache_re.test(file)){
let cont = fs.readFileSync(build_dir + '/' + file).toString()
cont = cont.slice(0, cont.length - 4)
urls_to_add.forEach((url) => {
cont += `,\n {\n "url": "${url}",\n "revision": "${generate_revision()}"\n }`
})
cont += `\n]);`
fs.writeFileSync(build_dir + '/' + file, cont);
break;
}
}
})
And then modify your package.json from
//....
"scripts": {
//....
"build": "react-scripts build"
//...
}
//...
}
to
//....
"scripts": {
//....
"build": "react-scripts build && node add_to_precache"
//...
}
//...
}
And you are done. It will do the trick when building the application
Related
It is my first project in that I'm using electron, I'm dealing with a few problems creating standalone publish from the project.
Here's my electron main.js file:
const path = require("path");
const electron = require("electron");
const isDev = require("electron-is-dev");
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const url = require("url");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({ show: false });
// cm: open app in fullscreen mode
mainWindow.maximize();
mainWindow.show();
// cm: remove default menu bar
mainWindow.setMenuBarVisibility(false);
if (isDev) {
mainWindow.loadURL(
"http://localhost:3000"
);
} else {
mainWindow.loadFile("./dist/index.js");
}
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on("closed", function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed.
app.on("window-all-closed", function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
And my package.json scripts are:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron": "electron .",
"package-win": "electron-packager . IranFMCG --overwrite --platform=win32 --arch=ia32 --icon=assets/icons/win/icon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"IranFMCG\"",
},
Everything is fine when the react application is running and I'm using "npm run electron" but after running "npm run package-win" and after that when I'm running exe file I am facing errors.
I think that is because I'm not running react app anymore, but I want to use react build files is it possible?
Hi i am trying to create a simple node app on google app standard app engine using this terraform code. This code used to work before but today i was trying to restart the whole project and re-deploy everything again and i see that i am getting an error.
compute_engine.tf
resource "google_app_engine_standard_app_version" "nodetest" {
version_id = "v1"
service = "mainApp"
runtime = "nodejs10"
instance_class = "B1"
basic_scaling {
max_instances = 1
}
entrypoint {
shell = "node test.js"
}
deployment {
files {
name = google_storage_bucket_object.object.name
source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
}
}
delete_service_on_destroy = true
depends_on = [
google_project_service.appengine_api
]
}
resource "google_storage_bucket" "bucket" {
project = var.project_id
name = var.bucket_name
location = var.region
}
resource "google_storage_bucket_object" "object" {
name = "test.js"
bucket = google_storage_bucket.bucket.name
source = "test.js"
}
My test.js is located in the same directory as where tf is located.
test.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
I see that the files have already been deployed correctly
And the error i am getting
I tried changing the url from
"https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
To
"https://storage.cloud.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
Try changing the shell = "node test.js" to shell = "node ./test.js"
Also i did take a look at GitHub Issue 4974 but is doesnt solve my problem. I did notice that when i try to terraform apply the error pretty much pop up quite fast so it seem that is stuck on a very first validation error.
Does the user that runs compute_engine.tf has "appengine.applications.create" and deploy permissions?
Also check if you set project and region in your google provider.
I'm trying to create a worker in an app created from create-react-app using react 16.8.6 and yarn 1.16.0. If I use
const backgroundWorker = new Worker('../assets/js/myWorker.js');
I get the console error: Uncaught SyntaxError: Unexpected token <
But I know that is the correct path. This works fine in Angular. Is there a good tutorial on how to create a worker in React?
The directory "assets" is the public directory for #angular/cli projects, not create-react-app projects. In create-react-app the equivalent of #angular/cli "assets" is "public" which is described in the create-react-app documentation under Using the Public Folder. Move your "js" directory and the "myWorker.js" file to the public directory and update the creation of the worker to point to that path instead:
const backgroundWorker = new Worker('/js/myWorker.js');
You can also use process.env.PUBLIC_URL instead:
const backgroundWorker = new Worker(`${process.env.PUBLIC_URL}/js/myWorker.js`);
Hopefully that helps!
Follow these steps in order to add your worker files to your create-react-app project.
1. Install these three packages:
$ yarn add worker-plugin --dev
$ yarn add comlink
$ yarn add react-app-rewired --dev
2. Override webpack config:
In your project's root directory create a config-overrides.js file with the following content:
const WorkerPlugin = require("worker-plugin");
module.exports = function override(config, env) {
//do stuff with the webpack config...
config.plugins = [new WorkerPlugin({ globalObject: "this"}), ...config.plugins]
return config;
}
3. Replace your npm scripts inside package.json by:
"start": "react-app-rewired start",
"build": "react-app-rewired build",
4. Create two files in order to test your configuration:
worker.js
import * as Comlink from "comlink";
class WorkerWorld {
sayHello() {
console.log("Hello! I am doing a heavy task.")
let numbers = Array(500000).fill(5).map(num => num * 5);
return numbers;
}
}
Comlink.expose(WorkerWorld)
use-worker.js
import * as Comlink from "comlink";
const initWorker = async () => {
const workerFile = new Worker("./worker", { name: "my-worker", type: "module" });
const WorkerClass = Comlink.wrap(workerFile)
const instance = await new WorkerClass();
const result = await instance.sayHello();
console.log("Result of my worker's computation: ", result);
}
initWorker()
5. See the output:
$ yarn start
So I have this Create react app (I don't really understand webpack), and I wanted to use EaselJS on this one, However the NPM counterpart of EselJS is their version 2 (BETA) and is quite unstable and undocumented - That's why I wanted to use the minified version.
I have a easeljs.min.js on my project but I don't know how to "import it".
doing `import './easeljs.min.js' seems to also generate a lot of linting issues and seems to nor work.
EDIT:
I tried using react-helmet and append it as a script tag, but it seems that react is doing something with the minified version and causes it to error. (unexpected token <)
So I was able to fix it:
I installed react-app-rewired created config-overrides.js and added this code:
module.exports = function override(config, env) {
if (!config.resolve || Object.keys(config.resolve).length === 0) {
config.resolve = {};
}
if (!config.module || Object.keys(config.module).length === 0) {
config.module = {};
}
if (!config.module.rules || config.module.rules.length === 0) {
config.module.rules = [];
}
const resolve = {
alias: {
createjs: "createjs/builds/1.0.0/createjs.js"
}
};
config.resolve = {
...config.resolve,
...resolve
};
config.module.rules.push({
test: /node_modules[/\\]createjs/,
loaders: ["imports-loader?this=>window", "exports-loader?window.createjs"]
});
return config;
};
It seems that it is an issue with createjs itself https://github.com/CreateJS/Combined/issues/12
I also ended up using this repo for createjs.
How can I deploy NodeJS app with local dependencies to GAE???
My app has local dependencies in package.json, so it failed.
Thanks!
No help came so I did it myself. Here's the solution for everyone has the same problem. Use gulp to copy local resources into current directory.
const gulp = require('gulp');
const merge = require('merge-stream');
const runSequence = require('run-sequence');
const del = require('del');
const fs = require('fs');
const resolve = require('path').resolve;
let getPackageGlobs = (dir) => {
let paths = [
dir + '/**',
'!' + dir + '/node_modules/**',
'!' + dir + '/npm-debug.log',
'!' + dir + '/build',
];
try {
let data = fs.readFileSync(dir + '/.npmignore', {
encoding: 'utf-8',
});
paths = paths.concat(data.split("\n")
.filter((e) => e.length > 0)
.map((e) => dir + '/' + e)
.filter(fs.existsSync)
.map((e) => fs.lstatSync(e).isDirectory() ? '!' + e + '/**' : '!' + e));
} catch (err) { }
return paths;
};
gulp.task('build.clean', () => {
return del(__dirname + '/build');
});
gulp.task('build.copy', () => {
return gulp.src(getPackageGlobs(__dirname))
.pipe(gulp.dest('build'));
});
gulp.task('build.normalize', () => {
let packageJson = require('./build/package.json');
let tasks = [];
for (let name in packageJson.dependencies) {
for (let s of ['../', '~/', './', '/']) {
if (packageJson.dependencies[name].startsWith(s)) {
tasks.push(gulp
.src(getPackageGlobs(resolve(packageJson.dependencies[name])))
.pipe(gulp.dest('./build/local_modules/' + name)));
packageJson.dependencies[name] = './local_modules' + '/' + name;
break;
}
}
}
return new Promise((resolve, reject) => {
fs.writeFile('./build/package.json',
JSON.stringify(packageJson), (err) => {
if (err) {
reject(err);
} else {
resolve(merge(tasks));
}
});
});
});
gulp.task('build', (done) => {
runSequence('build.clean',
'build.copy',
'build.normalize',
done);
});
And run with gulp build && gcloud app deploy build/app.yaml
Thanks to #Hung Hoang for the question and their answer. Their answer solved my issue as well. I was motivated to write a solution that achieves the same result (and a few improvements) without using Gulp.
The following code assumes that you have a local package located at ../local, and that the current working directory contains the Node.js application and the package.json to be deployed to App Engine.
The overall idea is to copy the contents of ../local to the Node.js app directory before deploying. This way, the local package code will be included as part of the code uploaded as part of the deploy, and the deploy will not result in an error. But, additionally, for this to work correctly the package.json dependency entry for the ../local package also needs to be updated.
There are three steps to the process (defined in Makefile format).
deploy: _predeploy _deploy _postdeploy
The pre-deploy step prepares files for deployment. See inline comments for details.
_predeploy:
# copy package to current directory
cp -r ../local tmp-local
# preserve original package.json,package-lock.json
cp package.json package.json.original
cp package-lock.json package-lock.json.original
# rewrite local dependency value in package.json (../local -> ./tmp-local)
sed -i '' 's/file:\.\.\/local/file:.\/tmp-local/g' package.json
# update package-lock.json corresondingly
npm i --package-lock-only
The deploy step does the actual deploy using the gcloud command.
_deploy:
gcloud app deploy
Finally the post-deploy step cleans up files created during the pre-deploy step, and restores the original state of package.json (such that ../local can be used as usual for local development).
_postdeploy:
# undo package.json,package-lock.json changes
mv package.json.original package.json
mv package-lock.json.original package-lock.json
# remove copied package
rm -rf tmp-local
To run, execute make deploy.