How to connect to a sqlite db from a React app? - reactjs

I'm trying to build a page using Create React App, plus the sqlite3 module. In their default configurations, the two things don't seem to be compatible out of the box. I'm new to React and JS in general, so I'm hoping there's something obvious I'm missing here.
Using npx v6.9.0 and Node v12.4.0, I can reproduce this by typing npx create-react-app test, cd test, npm start.
So far so good. I type: npm install sqlite3, and receive an npm warning that I should install typescript. OK, I type npm install typescript. All good. I start up the app, and it compiles so far. Great!
I open up App.js, and per sqlite3's readme doc, under the import lines, I type var sqlite3 = require('sqlite3').verbose();
This is probably where I'm doing something wrong. My app now fails to compile, telling me:
./node_modules/sqlite3/node_modules/node-pre-gyp/lib/info.js
Module not found: Can't resolve 'aws-sdk' in '/Users/brendanlandis/Desktop/test/node_modules/sqlite3/node_modules/node-pre-gyp/lib'
I try npm install aws-sdk, which gets me a little farther. My app still won't compile, but now the error is:
TypeError: stream is undefined
./node_modules/set-blocking/index.js/</module.exports/<
node_modules/set-blocking/index.js:3
1 | module.exports = function (blocking) {
2 | [process.stdout, process.stderr].forEach(function (stream) {
> 3 | if (stream._handle && stream.isTTY && typeof stream._handle.setBlocking === 'function') {
4 | stream._handle.setBlocking(blocking);
5 | }
6 | });
In googling around, I haven't yet figured out what I'm doing wrong. Any help would be appreciated. Thanks!

As the other answer mentioned, this is probably not recommended. You should really stick your database on the backend somewhere.
However it is possible to do this using sql.js. I had no luck with the sqlite3 module.
Here is the example I used: https://github.com/sql-js/react-sqljs-demo
Start by installing Craco. This is needed for bundling the wasm file.
npm install #craco/craco --save
replace your react scripts with Craco scripts in package.json:
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
Make a craco.config.js file in the root of your project and place this code inside:
module.exports = {
webpack: {
configure:{
// See https://github.com/webpack/webpack/issues/6725
module:{
rules: [{
test: /\.wasm$/,
type: 'javascript/auto',
}]
}
}
}
};
Then install sql.js
npm install sql.js --save
You probably need to do some more backend setup after this, but for now import the package:
import initSqlJs from 'sql.js';
// Required to let webpack 4 know it needs to copy the wasm file to our assets
import sqlWasm from "!!file-loader?name=sql-wasm-[contenthash].wasm!sql.js/dist/sql-wasm.wasm";
I had to disable eslint to get the second import to work. Really not ideal, but eslint throws errors if you try using file-loader. These are the lines to remove in package.json:
"eslintConfig": {
"extends": "react-app"
},
Now call the library!
const response = fetch("example.com/sqlitedatabase");
const buf = await response.arrayBuffer();
const SQL = await initSqlJs({ locateFile: () => sqlWasm });
const db = new SQL.Database(new Uint8Array(buf));
You can then query the database; The following code runs a query and then puts it into a more useable form than the default response.
const query = db.exec(`
SELECT
*
FROM
table;
`);
const columns = query[0].columns;
const values = query[0].values;
let rows = [];
values.forEach(element => {
let row = {};
for (let i = 0; i < columns.length; i++) {
row[columns[i]] = element[i];
}
rows.push(row);
});
That should work, but as I mentioned above, you might need to mess with the backend a little. Often times single page applications have trouble with CORS when dealing with bundled files. To fix this on AWS Amplify, I added the following code in a file called customHttp.yml to the root of my project:
customHeaders:
- pattern: '**/*'
headers:
- key: Access-Control-Allow-Origin
value: '*'
- pattern: '*.wasm'
headers:
- key: Access-Control-Allow-Origin
value: '*'
(Edit: Added a more generic pattern to the file, didn't work without it.)
Note that it may take some time for the custom headers to update, even though it looks like they update immediately.
Also related to single page applications, wasm files need to be added to the list of files exempted from redirects:
Source address: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|json|map|wasm)$).)*$/>
Target address: /index.html
Type: 200 (Rewrite)

ReactJS is mostly a front end framework, you should create a backend server.
Some NPM packages are not compatible with front-end JS application.
Your react application will call the server and the server manipulate the DB transactions. You can for example use express js. Useful docs below :
ExpressJS - SQLite doc
API Request from react app

Related

Nextjs app won't export due to Image Optimization [duplicate]

This question already has answers here:
Error: Image Optimization using Next.js default loader is not compatible with `next export`
(5 answers)
Closed 5 months ago.
I see this question but the most upvoted answer was to use some Akamai-based config and I am not hosting this with Akamai.
I have a React/Nextjs with a package.json whose scripts look like:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"export": "next export"
},
When I run:
npm run export
I get:
> myapp-website#0.1.0 export
> next export
info - using build directory: /Users/myuser/workspace/myappsite/myapp-website/.next
info - Copying "static build" directory
info - No "exportPathMap" found in "/Users/myuser/workspace/myappsite/myapp-website/next.config.js". Generating map from "./pages"
Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
Possible solutions:
- Use `next start` to run a server, which includes the Image Optimization API.
- Configure `images.unoptimized = true` in `next.config.js` to disable the Image Optimization API.
Read more: https://nextjs.org/docs/messages/export-image-api
at /Users/myuser/workspace/myappsite/myapp-website/node_modules/next/dist/export/index.js:149:23
at async Span.traceAsyncFn (/Users/myuser/workspace/myappsite/myapp-website/node_modules/next/dist/trace/trace.js:79:20)
When I check my next.config.js file I see:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
module.exports = nextConfig
What do I need to do so that npm run export runs successfully? And what's happening here?
I also don't understand why Nextjs wouldn't just work as-is, out of the starting gate.
What we have to keep in mind is how Next.js optimization works under the hood. The images are not optimized during build, they are optimized on-demand. Naturally, for that a server needs to be running.
It is mentioned in the docs:
Images can not be optimized at build time using next export, only on-demand. To use next/image with next export, you will need to use a different loader than the default. Read more in the discussion.
Running next export does not run a server. Instead you are trying to export a static HTML out of your next.js project (for example, to run on github pages etc.)
next export allows you to export your Next.js application to static HTML, which can be run standalone without the need of a Node.js server.
There will be unsupported features, and image optimization is one example.
You can change configuration by adding the below to next.config.js:
module.exports = {
images: {
unoptimized: true,
},
}
or
module.exports = {
images: {
loader: 'imgix',
path: 'https://example.com/myaccount/',
},
}
By using the imgix loader, you are offloading that task to imgix
servers, and they will serve you the image. By using unoptimized : true in config, you are disabling image optimization. This way you do not need a server.
In the next.config.js, turn off the image optimization feature, and then run npm build and npm export. Export doesn't support image optimization because there won't be any nextjs server to optimize image. After export you can use third party libraries to optimize your images or load your images from websites which optimizes your images.
Add this is config file -
images: {
unoptimized: true
}

Environment variables in manifest.json - Chrome Extension

Is it possible to set environment variables in the manifest.json file of a Chrome Extension?
Like wOxxOm said, I used webpack to proccess manifest.json.
In my case, I needed to set version automatically on manifest file.
I added to webpack script:
plugins: [
new CopyWebpackPlugin([
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modify(content)
}
}
]),
]
And the modify function replaces version on file for the parameter:
function modify(buffer) {
var manifest = JSON.parse(buffer.toString());
let argv = process.argv[2];
if (argv) manifest.version = argv.split("=")[1];
let manifest_JSON = JSON.stringify(manifest, null, 2);
return manifest_JSON;
}
So, I build like "yarn build --version=x.x" and webpack do what I need.
PS: if you're going to use this, remember to change:
the manifest.json directory, if necessary;
the value in the modify function, in my case it was version
As the OP has mentioned in her answer, using the copy-webpack-plugin in the webpack.config.js file is the way to go if you're building your Chrome Extension with React. However, if your React app is based on create-react-app, directly editing the webpack.config.js file (which is located in node_modules/react-scripts/config) is not recommended.
In such a case, use craco, which is an npm package that can be used to customize an app based on create-react-app. Here's how you do it:
Install craco into your project using npm i #craco/craco.
Install copy-webpack-plugin as a dev-dependency in your project using npm i --save-dev copy-webpack-plugin.
Let's suppose we're creating a development and a production build of our Chrome Extension. Let's also suppose we've already assigned "version": "0.1.0" in our Chrome Extension's manifest.json. Depending on the build type, we'd like to assign accordingly the version_name field in our Chrome Extension's manifest.json, e.g., "version_name": "0.1.0 dev" for development and "version_name": "0.1.0" for production. In your React app's package.json, introduce two fields (the script names can be whatever you wish) as follows:
"scripts": {
...
"build-dev": "CRX_ENV=dev craco build", // or "set CRX_ENV=dev&& craco build" in the case of Windows
"build-prod": "CRX_ENV=prod craco build", // or "set CRX_ENV=prod&& craco build" in the case of Windows
...
}
Create a new file called craco.config.js in the root of your project. As per your need, do something similar to the following in the craco.config.js file:
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
webpack: {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modifyManifest(content)
},
},
],
}),
],
},
}
function modifyManifest(buffer) {
const manifest = JSON.parse(buffer.toString())
if (process.env.CRX_ENV === "dev") {
manifest.version_name = `${manifest.version} dev`
} else if (process.env.CRX_ENV === "prod") {
manifest.version_name = `${manifest.version}`
}
const manifestJson = JSON.stringify(manifest, null, 2)
return manifestJson
}
Run npm run build-dev. It will create a folder called build in your project root. This build folder is your unpacked Chrome Extension, which you can load into Chrome using the "Load unpacked" button on the chrome://extensions page. Once loaded, you should be able to see 0.1.0 dev as the version name of your Chrome Extension.
Delete the build folder created from the previous step and run npm run build-prod, and repeat the same steps. You should be able to see 0.1.0 as the version name of your Chrome Extension on the chrome://extensions page.

React analyze bundle size

I have a question - how to analyze bundle size?
I want to get informations how bundle files change in case i will push the commit in gitlab.
I was looking for something like danger.js but it probably doesn't support gitlab.
You can use this script to analyze, without ejecting create-react-app
Put analyze.js in root of your project ( where the package.json is located )
npm install progress-bar-webpack-plugin
npm install webpack-bundle-analyzer
analyze.js
process.env.NODE_ENV = 'production';
const webpack = require('webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpackConfigProd = require('react-scripts/config/webpack.config')('production');
// this one is optional, just for better feedback on build
const chalk = require('chalk');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const green = text => {
return chalk.green.bold(text);
};
// pushing BundleAnalyzerPlugin to plugins array
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
// optional - pushing progress-bar plugin for better feedback;
// it can and will work without progress-bar,
// but during build time you will not see any messages for 10-60 seconds (depends on the size of the project)
// and decide that compilation is kind of hang up on you; progress bar shows nice progression of webpack compilation
webpackConfigProd.plugins.push(
new ProgressBarPlugin({
format: `${green('analyzing...')} ${green('[:bar]')}${green('[:percent]')}${green('[:elapsed seconds]')} - :msg`,
}),
);
// actually running compilation and waiting for plugin to start explorer
webpack(webpackConfigProd, (err, stats) => {
if (err || stats.hasErrors()) {
console.error(err);
}
});
Now simply put node ./analyze.js in the package.json scripts
"scripts": {
.....
"analyze": "node ./analyze.js"
},
after that run npm run analyze
You can also accomplish this using webpack stats json file, supported by create-react-app and webpack-bundle-analyzer.
When running your build with create-react-app, add the --stats flag:
yarn build --stats
This will create a build/bundle-stats.json file, with webpack stats, allowing you to use the webpack-bundle-analyzer CLI to analyze this stats.
yarn run webpack-bundle-analyzer build/bundle-stats.json
reference:
https://www.npmjs.com/package/webpack-bundle-analyzer#user-content-usage-as-a-cli-utility
tested with CRA latest version at the time: v4
You can use and configure webpack-bundle-analyzer library and use it in your React App WITHOUT EJECTING
Add some dependencies by executing npm install --save-dev progress-bar-webpack-plugin webpack-bundle-analyzer
Create a new folder named scripts at the root of your React App.
Create a new file analyze_build_bundle.js in the scripts folder and add the below code in that file
// script to enable webpack-bundle-analyzer
process.env.NODE_ENV = 'production';
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const webpackConfigProd = require('react-scripts/config/webpack.config')(
'production'
);
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
webpackConfigProd.plugins.push(
new ProgressBarPlugin({
format: `analyzing... [:bar] [:percent] [:elapsed seconds] - :msg`,
})
);
// actually running compilation and waiting for plugin to start explorer
webpack(webpackConfigProd, (err, stats) => {
if (err || stats.hasErrors()) {
console.error(err);
}
});
Add the analyze-build-bundle command in your package.json file to run the webpack-bundle-analyzer as below:
"scripts": {
"analyze-build-bundle": "node scripts/analyze_build_bundle.js",
"start": "react-scripts start",
.....
...
}
Now execute command npm run analyze-build-bundle. This will build your app and then start the analyzer local server and you should be able to see the screen as shown in below image

Custom Proxy in Create React App using Typescript

I need to proxy requests from a Create React App to a separate API server, and set that server dynamically or with environment variables. I followed configuring proxy manually, however I am using TypeScript. react-scripts-ts does not seem to load src/setupProxy.js even after updating to latest version (v3.1.0). I got it working with vanilla javascript, but am unable to get it to work with TypeScript. Has anyone gotten setupProxy to work with React TypeScript?
After code diving, it appears the typescript create-react-app has not yet incorporated custom proxy functionality. I had to update two files:
https://github.com/samuelstevens9/create-react-app/blob/next/packages/react-scripts/config/paths.js
Added proxySetup: resolveApp('src/setupProxy.js'), to each module.exports, the last (3rd) being proxySetup: resolveOwn('template/src/setupProxy.js'),
https://github.com/samuelstevens9/create-react-app/blob/next/packages/react-scripts/config/webpackDevServer.config.js
Added const fs = require('fs'); below line 15 const paths = require('./paths'); and added
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(app);
}
inside the before(app) { ... } function towards the end of the file.
I am working on creating a pull request to the main repo, but it looks like the v3.1.0 files are different from the most up to date ones on the next branch. For now I use a patch script I made since we are using a lerna monorepo that updates all necessary packages:
#!/bin/bash
CONFIG_PATHS_URL="https://raw.githubusercontent.com/samuelstevens9/create-react-app/next/packages/react-scripts/config/paths.js"
CONFIG_WEBPACKDEVSERVER_URL="https://raw.githubusercontent.com/samuelstevens9/create-react-app/next/packages/react-scripts/config/webpackDevServer.config.js"
SETUPPROXY_URL="https://gist.githubusercontent.com/samuelstevens9/5872e72ac915dfc1a8ae2fdcef323899/raw/7f2c76d42bc0915026379dfc7884cb1bd97f56bb/setupProxy.js"
for f in packages/*; do
if [ -d ${f} ]; then
echo $f
# Will not run if no directories are available
NODE_MODULES_CONFIG_DIR=$f/node_modules/react-scripts-ts/config
if [ -d "$NODE_MODULES_CONFIG_DIR" ]; then
# Control will enter here if $DIRECTORY exists.
echo $NODE_MODULES_CONFIG_DIR
curl -o $NODE_MODULES_CONFIG_DIR/paths.js $CONFIG_PATHS_URL
curl -o $NODE_MODULES_CONFIG_DIR/webpackDevServer.config.js $CONFIG_WEBPACKDEVSERVER_URL
curl -o $f/src/setupProxy.js $SETUPPROXY_URL
fi
fi
done
And updates the setupProxy.js file in each package as well. Hope this helps.
Now CRA supports Typescript but I couldn't make setupProxy.js to work.
My mistake was super dumb. setupProxy was outside src/ folder.
So, make sure that you create setupProxy inside the folder src
src/setupProxy.js
My code looks like this:
module.exports = function (app) {
app.use(
'/api',
createProxyMiddleware({
target: process.env.REACT_APP_API_URI,
changeOrigin: true,
})
)
}
Also, make sure that your env configuration is working.
You need to install the package env-cmd and replace
"start": "react-scripts start",
for
"start": "env-cmd -f .env.development.local react-scripts start",

Push notification in Create-react-app (Web)

In my React App, I want to implement push notification.
What I've done so far.
In the service worker registration step, I added some codes to initialize push manager that handles user subscription, now my app will prompt user to subscribe to push notification.
After subscription, from what I read, the final step is to register event listeners that catches pushes and listen to push notification click. Something like : self.addEventListener('push', function() { // Some codes here })
Now, where should I put the listener codes ? As CRA auto-generated the service-worker for production build
This doco suggests adding it after fetch in the registerServiceWorker.js.
The following solution works only CRA 1.x.x!
As I understood CRA doesn't support extending its service-worker.js from the box.
I've found the following workaround.
1) Install the cra-append-sw
npm install cra-append-sw --save
2) Add an extension file custom-sw.js to the root directory
self.addEventListener("push", event => {
const data = event.data.json()
const { title } = data
const body = {
body: data.body,
icon: data.icon
}
event.waitUntil(self.registration.showNotification(title, body))
})
3) Patch the package.json to run the cra-append-sw during debugging and building
"scripts": {
...
"start": "npm-run-all -p watch-css start-js && cra-append-sw --mode dev ./custom-sw.js",
...
"build": "npm-run-all build-css build-js && cra-append-sw ./custom-sw.js",
}
For anyone looking for this, here is a good guide on how to achieve push notifications in React.
Guide: Integrating Push Notifications in your Node/React Web App

Resources