Thursday, August 29, 2019

sh: react-scripts: command not found

sh: react-scripts: command not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn




It could be that you are running a script from Visual Studio Code's NPM-Scripts sidebar. To fix that, add the following configuration in settings.json file under .vscode directory. If .vscode directory nor settings.json is not existing, just create those two.


{
    "npm.packageManager": "yarn"
}

Restart VS Code, then click the start script from NPM Scripts sidebar.

If you don't want to create .vscode directory and settings.json file, there's a global settings where npm.packageManager setting could be applied. This can be set by going to the menu under File > Preferences > Settings. (Code > Preferences > Settings on macOS). On User tab, type package manager. Change the Npm: Package Manager to yarn.



Restart VS Code.

Alternatively, it can be set directly on global settings.json file by opening the Command Palette. Command Palette can be accessed in the menu under View > Command Palette (keyboard shortcut: Control+Shift+P on Windows, Command+Shift+P on Mac). Then type settings



Choose Preferences: Open Settings (JSON).

Then add "npm.packageManager", then choose "yarn":



Restart VS Code

Thursday, August 15, 2019

Error: Invariant failed: You should not use Link outside a Router

As of the time of this writing, the latest version for connected-react-router is 6.5.2, and the latest version for react-router and react-router-dom is 5.0.1. However, I got the errors that says Link should not be used outside a Router when using those versions.



Cause of the error: https://github.com/ReactTraining/react-router/issues/6634#issuecomment-500084539


The example of connected-react-router (even if the latest version is 6.5.2) uses connected-react-router 6.0.0 though: https://github.com/supasate/connected-react-router/blob/d822fb9afd12e9d32e8353a04c1c6b4b5ba95f72/examples/basic/package.json#L26

That example uses react-router and react-router-dom 4.3.1.


To fix the error, just use the same version from the example. Pin the version of connected-react-router to 6.0.0, and both react-router, react-router-dom to ^4.3.1.

"dependencies": {
    "connected-react-router": "6.0.0",
    "history": "^4.9.0",
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-redux": "^7.1.0",
    "react-router": "^4.3.1",
    "react-router-dom": "^4.3.1",
    "react-scripts": "3.1.1",
    "redux": "^4.0.4"
},


Then delete yarn.lock and node_modules:
$ rm yarn.lock
$ rm -rf node_modules

Then reinstall:
$ yarn

Then add prop-types:
$ yarn add prop-types


As of the time of this writing, I got ^15.7.2 for prop-types.


That's all.




Wednesday, August 14, 2019

npm install -g without sudo

On my machine, ~/.npmrc file is not existing. So I created one, and then add the following:


prefix=~/.npm


And in ~/.bash_profile (which is also not existing on my machine, so I created one), I added this line:

export PATH="$HOME/.npm/bin:$PATH"


Restarted terminal, npm install -g now works even without the sudo


Followed these steps:

https://medium.com/@ExplosionPills/dont-use-sudo-with-npm-still-66e609f5f92

https://www.reddit.com/r/applehelp/comments/9tf7hx/bashrc_on_mojave/



Thursday, August 8, 2019

All things being equal, they are not equal

I put all my shared files on external drive with exFAT file system. Found out later that the default cluster size (128 KB) that macOS allocates for exFAT drives is atrociously wasteful for npm-based projects. The external drive is permanently plugged to the back of iMac's Thunderbolt 3 port.

Image

For 128KB cluster size partition, a 3.5GB npm-based project consumes 81GB of space, yes that's 81GB not 8.1GB. For 4K cluster size partition, a 3.5GB npm-based project consumes 5.44GB only.

I resized the exFAT drive's cluster size to 4 KB, there is a problem when the computer boots though. The exFAT drive affects the boot speed of the computer. Do note that the computer is booting from internal drive (APFS), not from external exFAT drive.

From cold boot to Apple logo, the exFAT drive affects the boot speed of the computer to almost ten minutes.

Here are the other boot speed from various exFAT cluster sizes:

8 KB = 2 minutes 50 seconds
16 KB = 50 seconds
32 KB = 16 seconds
64 KB = 8 seconds
128 KB = 7 seconds


For other file systems cluster sizes:

4 KB APFS = 5 seconds
4 KB NTFS = 5 seconds

For both file systems, they don't affect the boot speed of the computer even if they are permanently plugged to Thunderbolt port.

Ultimately I decided to use NTFS and used third-party software on macOS that can read and write to NTFS drive.


Further space saved by deleting node_modules from npm-based projects by using Yarn Plug'n'Play:




Saturday, August 3, 2019

Could not read from remote repository

Got this error when pushing code to GitHub:

Developers-iMac:experiment-react-route-based-lazy-load dev$ git push -u origin master
Warning: Permanently added the RSA host key for IP address '13.250.177.223' to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.


One solution that works:

Developers-iMac:experiment-react-route-based-lazy-load dev$ git remote set-url origin https://github.com/ienablemuch/experiment-react-route-based-lazy-load
Developers-iMac:experiment-react-route-based-lazy-load dev$ git push -u origin masterEnumerating objects: 28, done.
Counting objects: 100% (28/28), done.
Delta compression using up to 8 threads
Compressing objects: 100% (28/28), done.
Writing objects: 100% (28/28), 302.35 KiB | 12.09 MiB/s, done.
Total 28 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/ienablemuch/experiment-react-route-based-lazy-load
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

Got the solution from: https://stackoverflow.com/questions/21255438/permission-denied-publickey-fatal-could-not-read-from-remote-repository-whil/55239661#55239661

Wednesday, July 24, 2019

Simple docker-compose example

Create a barebone Node.js app by following this: https://nodejs.org/en/docs/guides/nodejs-docker-webapp/


Then update this section of code:

// App
const app = express();
app.get('/', (req, res) => {
  const message = `Hello world: ${process.env.GREETING_MESSAGE}`;
  res.send(message);
});


Create docker-compose.yml:

version: '3'
services:
  spiderman: 
    build: .
    ports:
        - "80:8080"
    environment:
        GREETING_MESSAGE: 你好世界


To test:
$ docker-compose up -d

Output:
Developers-iMac:experiment-nodejs-docker-compose dev$ docker-compose up -d
Creating network "experiment-nodejs-docker-compose_default" with the default driver
Building spiderman
Step 1/7 : FROM node:10
 ---> e05cbde47b8f
Step 2/7 : WORKDIR /usr/src/app
 ---> Running in 95c12e65805a
Removing intermediate container 95c12e65805a
 ---> be613c39b5ab
Step 3/7 : COPY package*.json ./
 ---> 619110050a58
Step 4/7 : RUN npm install
 ---> Running in e32232fc4928
npm WARN docker_web_app@1.0.0 No repository field.
npm WARN docker_web_app@1.0.0 No license field.

added 50 packages from 37 contributors and audited 126 packages in 1.148s
found 0 vulnerabilities

Removing intermediate container e32232fc4928
 ---> 92b713b4c799
Step 5/7 : COPY . .
 ---> ee82daff1c05
Step 6/7 : EXPOSE 8080
 ---> Running in a797e79b2f85
Removing intermediate container a797e79b2f85
 ---> 838f931be1ea
Step 7/7 : CMD [ "node", "server.js" ]
 ---> Running in c3b932bb7e0c
Removing intermediate container c3b932bb7e0c
 ---> 5a0d42751576
Successfully built 5a0d42751576
Successfully tagged experiment-nodejs-docker-compose_spiderman:latest
WARNING: Image for service spiderman was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating experiment-nodejs-docker-compose_spiderman_1 ... done


List the created docker image (think OOP's class):
Developers-iMac:experiment-nodejs-docker-compose dev$ docker images
REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE
experiment-nodejs-docker-compose_spiderman   latest              5a0d42751576        3 minutes ago       906MB
node                                         10                  e05cbde47b8f        6 weeks ago         904MB



List the docker image's instance (think class' instance):
Developers-iMac:experiment-nodejs-docker-compose dev$ docker ps
CONTAINER ID        IMAGE                                        COMMAND                  CREATED             STATUS              PORTS                  NAMES
35c7818a4704        experiment-nodejs-docker-compose_spiderman   "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        0.0.0.0:80->8080/tcp   experiment-nodejs-docker-compose_spiderman_1


Visiting 0.0.0.0 (a.k.a. 127.0.0.1, a.k.a. localhost) on browser:



Saturday, July 6, 2019

https with node.js local environment

Do it step-by-step:
https://www.freecodecamp.org/news/how-to-get-https-working-on-your-local-development-environment-in-5-minutes-7af615770eec/

Or just use someone else's scripts (made by same author above (Daksh Shah)):
https://github.com/dakshshah96/local-cert-generator

There's a caveat by the author that his steps should not be used for production (I've yet to know why):

"In an Express app written in Node.js, here’s how you would do it. Make sure you do this only for your local environment. Do not use this in production."


The following steps are basically a copy of the Daksh's steps for creating SSL certificate. Just making sure in any case that those links become unavailable, I will still be able to generate SSL certificate for my local environment.


Let's follow and see what happens on each step.


This generates rootCA.key file:
Developers-iMac:experiment-nodejs-https dev$ openssl genrsa -des3 -out rootCA.key 2048
Generating RSA private key, 2048 bit long modulus
............................................................................................................+++
...................................+++
e is 65537 (0x10001)
Enter pass phrase for rootCA.key:
Verifying - Enter pass phrase for rootCA.key:
Developers-iMac:experiment-nodejs-https dev$ ls -la
total 768
drwxrwxrwx  1 dev  staff  131072 Jul  6 18:25 .
drwxrwxrwx  1 dev  staff  131072 May 30 08:47 ..
-rwxrwxrwx  1 dev  staff    1751 Jul  6 18:30 rootCA.key


This generates rootCA.pem file:
Developers-iMac:experiment-nodejs-https dev$ openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem
Enter pass phrase for rootCA.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:PH
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:
Email Address []:
Developers-iMac:experiment-nodejs-https dev$ ls -la
total 1024
drwxrwxrwx  1 dev  staff  131072 Jul  6 18:25 .
drwxrwxrwx  1 dev  staff  131072 May 30 08:47 ..
-rwxrwxrwx  1 dev  staff    1751 Jul  6 18:30 rootCA.key
-rwxrwxrwx  1 dev  staff     956 Jul  6 18:31 rootCA.pem

Create server.csr.cnf file with this content:
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=PH
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost


Create v3.ext file with this content:
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost


Files:
Developers-iMac:experiment-nodejs-https dev$ ls -la
total 1536
drwxrwxrwx  1 dev  staff  131072 Jul  6 18:25 .
drwxrwxrwx  1 dev  staff  131072 May 30 08:47 ..
-rwxrwxrwx  1 dev  staff    1751 Jul  6 18:30 rootCA.key
-rwxrwxrwx  1 dev  staff     956 Jul  6 18:31 rootCA.pem
-rwxrwxrwx  1 dev  staff     214 Jul  6 18:33 server.csr.cnf
-rwxrwxrwx  1 dev  staff     200 Jul  6 18:34 v3.ext

This generates server.csr and server.key files:
Developers-iMac:experiment-nodejs-https dev$ openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config server.csr.cnf
Generating a 2048 bit RSA private key
.........................................+++
...............+++
writing new private key to 'server.key'
-----
Developers-iMac:experiment-nodejs-https dev$ ls -la
total 2048
drwxrwxrwx  1 dev  staff  131072 Jul  6 18:25 .
drwxrwxrwx  1 dev  staff  131072 May 30 08:47 ..
-rwxrwxrwx  1 dev  staff    1751 Jul  6 18:30 rootCA.key
-rwxrwxrwx  1 dev  staff     956 Jul  6 18:31 rootCA.pem
-rwxrwxrwx  1 dev  staff    1098 Jul  6 18:35 server.csr
-rwxrwxrwx  1 dev  staff     214 Jul  6 18:33 server.csr.cnf
-rwxrwxrwx  1 dev  staff    1704 Jul  6 18:35 server.key
-rwxrwxrwx  1 dev  staff     200 Jul  6 18:34 v3.ext

This generates rootCA.srl and server.crt files:
Developers-iMac:experiment-nodejs-https dev$ openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext
Signature ok
subject=/C=PH/ST=RandomState/L=RandomCity/O=RandomOrganization/OU=RandomOrganizationUnit/emailAddress=hello@example.com/CN=localhost
Getting CA Private Key
Enter pass phrase for rootCA.key:
Developers-iMac:experiment-nodejs-https dev$ ls -la
total 2560
drwxrwxrwx  1 dev  staff  131072 Jul  6 18:25 .
drwxrwxrwx  1 dev  staff  131072 May 30 08:47 ..
-rwxrwxrwx  1 dev  staff    1751 Jul  6 18:30 rootCA.key
-rwxrwxrwx  1 dev  staff     956 Jul  6 18:31 rootCA.pem
-rwxrwxrwx  1 dev  staff      17 Jul  6 18:36 rootCA.srl
-rwxrwxrwx  1 dev  staff    1306 Jul  6 18:36 server.crt
-rwxrwxrwx  1 dev  staff    1098 Jul  6 18:35 server.csr
-rwxrwxrwx  1 dev  staff     214 Jul  6 18:33 server.csr.cnf
-rwxrwxrwx  1 dev  staff    1704 Jul  6 18:35 server.key
-rwxrwxrwx  1 dev  staff     200 Jul  6 18:34 v3.ext


Open Keychain Access:


Then import rootCA.pem file using File > Import Items, the certificate will be added to Keychain Access:



Create app.js:
var fs = require('fs');
var express = require('express');
var https = require('https');

var certOptions = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
};

var app = express();

app.get('/message', (req, res) => {
    res.json({message: 'Great'});
})

var server = https.createServer(certOptions, app).listen(443);


Run app.js:
Developers-iMac:experiment-nodejs-https dev$ nodemon app.js
[nodemon] 1.19.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node app.js`

Open https://localhost/message on your browser:



Safari:



To prevent that error from happening, double-click the certificate, then change the Trust settings to Always Trust:



Exit Keychain Access dialog, it will then prompt you with your super user password:




Reload the page:


Safari:



For some reasons, Firefox is uncooperative :)