Npm pre-scripts
Never Manually Setting IPs Again
Photo by Nathan Dumlao on Unsplash
I know, I know it sounds stupid, basic and simple but trust me it wasn't for me at the time.
At my workplace, we often deal with offline devices that connect to different networks. Each time they connect, they get a new IP address, which means updating the .env
file and rebuilding the app. It was a repetitive process that needed a better solution.
The basic workflow was:
- Get the new IP
- Update the
.env
file - Rebuild the app
- Fix any issues if something breaks
- Repeat for each device or network change
Even with Docker, managing dynamic IPs was still a hassle. Then I discovered something interesting about npm that I'd never thought about before - the "pre" scripts feature.
The npm Pre-Scripts Discovery
I never knew (or never thought about) how to update env files automatically when building or running a dev server. It turns out npm has this neat feature where any script prefixed with "pre" runs automatically before the main script. Here's how it works:
{
"scripts": {
"prestart": "node setup-env.js", // Runs automatically before "start"
"start": "react-scripts start",
"prebuild": "node setup-env.js", // Runs automatically before "build"
"build": "react-scripts build"
}
}
When you run npm start
:
- npm automatically looks for a script named "prestart"
- Runs that script first
- Then runs the actual "start" script
Same thing happens with npm run build
:
- npm looks for "prebuild"
- Executes that first
- Then runs the actual build
The Solution
Here's the complete setup. First, add this to your package.json
:
{
"scripts": {
"prestart": "node setup-env.js",
"prebuild": "node setup-env.js",
"start": "react-scripts start",
"build": "react-scripts build"
}
}
Then create a setup-env.js
:
const { networkInterfaces } = require('os');
const fs = require('fs');
function getLocalIP() {
const nets = networkInterfaces();
let localIP = '';
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
if (net.family === 'IPv4' && !net.internal) {
localIP = net.address;
return localIP;
}
}
}
return '127.0.0.1'; // Fallback to localhost
}
const envTemplate = `
REACT_APP_API_URL=http://${getLocalIP()}:3000
# Add other environment variables here
`;
fs.writeFileSync('.env', envTemplate.trim());
console.log(`Environment file updated with IP: ${getLocalIP()}`);
The script is straightforward:
networkInterfaces()
gets all your network interfaces- We filter for IPv4 and non-internal addresses
- The script updates your
.env
file with the correct IP - The pre-script feature runs this automatically before start/build
Now whenever you run npm start
or npm run build
, the script:
- Automatically detects your local IP
- Updates the
.env
file - Proceeds with the regular start/build process
This eliminates the need for manual IP updates and reduces the chance of errors from incorrect configurations. At my workplace, this solved our constant IP updating issues with offline devices. Even with Docker or other setups, dynamically creating the env with proper IPs became much simpler once I understood how npm pre-scripts worked. Even though there are loads of use-cases using pre-scripts like
- Run TypeScript type checks before build
- Clean build directories before new builds
- Format code before commits (Prettier)
But definitely it did solve one of my problem.
Never to late to know something.
Gracias.