Build React app generate static files with chunk suffix - reactjs

I have create a react app using below command
npx create-react-app my-app
Now when I am building the app for production using below command
npm run build
It generate below files with suffix.
build\static\js\1.82dafdb5.chunk.js
build\static\js\runtime~main.229c360f.js
build\static\js\main.a27c0d6d.chunk.js
build\static\css\main.c2586263.chunk.css
I am looking how can i avoid random number and chunk suffix in file name. And is there any way to only have one js file so that instead of importing three js files I can have one js file to import.

You can create new webpack.config.js file at the root of your project and do something like this:
const path = require("path")
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
const glob = require("glob")
module.exports = {
entry: {
"bundle.js": glob.sync("build/static/?(js|css)/main.*.?(js|css)").map(f => path.resolve(__dirname, f)),
},
output: {
filename: "build/static/js/bundle.min.js",
},
module: {
rules: [{
test: /\.css$/,
use: ["style-loader", "css-loader"],
}, ],
},
plugins: [new UglifyJsPlugin()],
}
But you need to modify your package.json also accordingly:
...
"build": "npm run build:react && npm run build:bundle",
"build:react": "react-scripts build",
"build:bundle": "webpack --config webpack.config.js",
...

After digging around quite a bit, I found the Following solution which worked on Windows.
Install:
npm i --save-dev renamer replace-in-file
And replace package.json build with these
{
"build": "react-scripts build && npm run build-rename",
"build-rename": "npm run build-rename-js && npm run build-rename-css && npm run build-fix-references",
"build-rename-js": "renamer --find \"/main\\.[^\\.]+\\./i\" --replace \"main.\" build\\static\\js\\*",
"build-rename-css": "renamer --find \"/main\\.[^\\.]+\\./i\" --replace \"main.\" build\\static\\css\\*",
"build-fix-references": "npm run build-fix-sourcemap && npm run build-fix-index && npm run build-fix-serviceworker && npm run build-fix-assetmanifest",
"build-fix-sourcemap": "npm run build-fix-sourcemap-js && npm run build-fix-sourcemap-css",
"build-fix-sourcemap-js": "replace-in-file \"/sourceMappingURL=main\\.[^\\.]+\\.js\\.map/i\" \"sourceMappingURL=main.js.map\" build/static/js/main.js --isRegex",
"build-fix-sourcemap-css": "replace-in-file \"/sourceMappingURL=main\\.[^\\.]+\\.css\\.map/i\" \"sourceMappingURL=main.css.map\" build/static/css/main.css --isRegex",
"build-fix-index": "npm run build-fix-index-js && npm run build-fix-index-css",
"build-fix-index-js": "replace-in-file \"/main\\.[^\\.]+\\.js/i\" \"main.js?v=%npm_package_version%\" build/index.html --isRegex",
"build-fix-index-css": "replace-in-file \"/main\\.[^\\.]+\\.css/i\" \"main.css?v=%npm_package_version%\" build/index.html --isRegex",
"build-fix-serviceworker": "npm run build-fix-serviceworker-js && npm run build-fix-serviceworker-css",
"build-fix-serviceworker-js": "replace-in-file \"/main\\.[^\\.]+\\.js/i\" \"main.js\" build/service-worker.js --isRegex",
"build-fix-serviceworker-css": "replace-in-file \"/main\\.[^\\.]+\\.css/i\" \"main.css\" build/service-worker.js --isRegex",
"build-fix-assetmanifest": "npm run build-fix-assetmanifest-js && npm run build-fix-assetmanifest-css && npm run build-fix-assetmanifest-js-map && npm run build-fix-assetmanifest-css-map",
"build-fix-assetmanifest-js": "replace-in-file \"/main\\.[^\\.]+\\.js/i\" \"main.js\" build/asset-manifest.json --isRegex",
"build-fix-assetmanifest-css": "replace-in-file \"/main\\.[^\\.]+\\.css/i\" \"main.css\" build/asset-manifest.json --isRegex",
"build-fix-assetmanifest-js-map": "replace-in-file \"/main\\.[^\\.]+\\.js\\.map/i\" \"main.js.map\" build/asset-manifest.json --isRegex",
"build-fix-assetmanifest-css-map": "replace-in-file \"/main\\.[^\\.]+\\.css\\.map/i\" \"main.css.map\" build/asset-manifest.json --isRegex"
}
Reference: https://github.com/facebook/create-react-app/issues/821

Related

watch SASS/SCSS and nodemon together

I want to run Nodemon and node-sass watcher together.
I tried following script on the package.json file.
"build-css": "node-sass --include-path scss scss/main.scss public/css/main.css",
"watch-css": "nodemon -e scss -x \"npm run build-css & nodemon server.js\""
and devDependencies are:
"devDependencies": {
"node-sass": "^4.9.0",
"nodemon": "^1.17.5"
},
It does work, but my question is if I don't add & nodemon server.js in the watch-css script, it doesn't run the server and web app.
Is there any good solution for that?
Thanks.
Ok I got so much now I'll make it an answer instead, but I think the question is very open ended! I think you have to change things up depending on requirements anyway. Basically if it works then don't worry about it.
There are various solutions, like npm-run-all or concurrently but I think a third script like "run-both": "npm run build-css & npm run watch-css" is fine in most cases if you keep in mind the & is not cross-platform or even cross-shell (like windows cmd vs powershell). So I'd say if you work in a team it'll probably be easier to just add another dev-dependency.
But I'll toot a horn for pm2 which I think works great in both production and development. The ecosystem-files are particularly useful. I also think pm2 replaces nodemon completely. Not that nodemon is bad, but pm2 is great for multiple processes. Here are some of my npm scripts:
"winsrv": "pm2 flush & pm2 reload server/ecosystem-win.json & pm2 logs",
"winprod": "webpack --config ./webpack.config.js & npm run winsrv",
"windev": "set NODE_ENV=development webpack --config webpack.dev.config.js"
And as a last thing I'll add that the post/pre hooks in npm scripts are plenty useful. Run one command for three scripts:
"preprod": "./preprod.sh", // Makes backup of old files, changes symlink to the backup
"prod": "webpack --config ./webpack.config.js && pm2 flush && pm2 reload server/ecosystem-production.json",
"postprod": "./postprod.sh", // check files exist and relinks public to the new build
Sorry for the delay, I got distracted and hit some snags.
I decided to try node-sass programmatic api, I'm not sure how smart that was, but I learned a thing or two.
buildcss.js:
var sass = require("node-sass");
var fs = require("fs");
sass.render({file: "styles.scss"}, (err, results) => {
if (err) { console.log(err); }
fs.writeFile("styles.css", results.css, err => console.log);
console.log('scss -> css complete!');
});
Fake server.js
console.log("server.js...");
setInterval(function() {
console.log("interval that prevents our so called server from exiting" );
}, 1000 * 60 * 60);
ecosystem.json (restarts the scss-script on change. hmm...)
{
"apps": [
{
"name": "My Server",
"script": "server.js",
"watch" : ["server.js"]
},
{
"name": "SCSS to CSS",
"script": "buildcss.js",
"watch": ["styles.scss"],
"autorestart": false
}
]
}
And package.json
...
"scripts": {
"start": "pm2 logs && pm2 reload ecosystem.json && pm2 logs --out"
},
npm start
And I'd like to add that I usually handle my scss-compiling through webpack and can't really speak for the process used here (but it seems to work well enough!).
Thank you very much for your help. I followed your instruction. I got the concept from that and applied as follows that worked for me:
buildcss.js (at root):
const sass = require('node-sass');
const fs = require('fs');
const path = require('path');
var path_style = path.resolve(__dirname, "scss")
var path_dist = path.resolve(__dirname, "public")
sass.render({file: path.join(path_style, '/main.scss')}, function (err, results) {
if(err){
console.log(err);
}
fs.writeFile(path.join(path_dist, '/css/main.css'), results.css, function (err) {
console.log(err);
});
console.log('scss --> css completed.');
});
ecosystem.json(at root):
{
"apps" : [
{
"name": "My App",
"script": "app.js",
"watch": ["app.js"]
},
{
"name": "SCSS to CSS",
"script": "buildcss.js",
"watch": ["./scss/main.scss"]
}
]
}
And package.json:
"scripts": {
"start": "pm2 start ecosystem.json && pm2 logs --out"
},
According to your code on package.json, "start": "pm2 logs && pm2 reload ecosystem.json && pm2 logs --out", that did not work for me. I experienced the following error:
[TAILING] Tailing last 15 lines for [all] processes (change the value with --lines option)
[PM2][ERROR] No file to stream for app [all], exiting.npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! mysite#1.0.0 start: `pm2 logs && pm2 reload ecosystem.json && pm2 logs --out`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the mysite#1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
From log file:
12 info lifecycle mysite#1.0.0~start: Failed to exec start script

Determine npm or yarn script run from module

Lets say I have the following scripts in my package.json file:
{
"start": "node index.js",
"start-with-flag": "node index.js -f"
}
Insideindex.js I have a console.log(process.argv), and the scripts above output the following:
$ npm run start
[ '/usr/local/Cellar/node/8.4.0/bin/node',
'/Users/.../test_app/index.js' ]
$ npm run start-with-flag
[ '/usr/local/Cellar/node/8.4.0/bin/node',
'/Users/.../test_app/index.js',
'-f' ]
Is it possible to retrieve the value of the scripts which I ran (start or start-with-flag) inside of index.js?
You can access the script which is currently executed with the npm_lifecycle_event environment variable.
command
$ npm run start-with-flag
index.js
console.log(process.env.npm_lifecycle_event) // start-with-flag
package.json
{
"scripts": {
"start": "node index.js",
"start-with-flag": "node index.js -f"
}
}

Conditional postinstall in package.json depending on your OS?

Here in my package.json i'm running into this issue when going between my Linux machine and Windows machine:
"postinstall": "node.exe node_modules/bower/bin/bower install" (for Windows)
"postinstall": "./node_modules/bower/bin/bower install" (for Linux)
I have to keep swapping these lines depending on my environment - how can I do this cross-OS so it will work in both places?
I want to do something like:
"postinstall": isOSWindows ? "node.exe node_modules/bower/bin/bower install" : "./node_modules/bower/bin/bower install"
First thing is that I think you do not need switch OS to run bower from local dependencies.
After you install bower as devDepedency you can set for example script in package.json
"scripts":{
"postinstall": "bower install"
}
And then run npm install, should work.
This is possible because after installing bower as local dependency in node_modules folder an executable version of bower script is generated in .bin folder
Or if you want to switch between OS you can use this technique.
To not have to long script command I put this into external script and use process.platform, something like that script.js
const {exec} = require('child_process');
if (process.platform !== 'win32') {
// run scripts for Windows
return;
}
const commands = [
'set NODE_ENV=e2e_tests',
'npm run start-local-test-environment',
'grunt build',
'nightwatch ./test/e2e/tests --skipgroup common,helpers --env chrome'
];
const executedCommands = exec(commands.join('&&'), (error) => {
if (error) {
throw error;
}
});
and then in package.json script you can have:
"postinstall": "node ./scripts/script.js",

How to pass params from one npm script into another one

Is it possible to run npm script with params from another npm script?
For instance:
"scripts": {
"build": "node_modules/webpack/bin/webpack.js ", //should get params here
"build:dev": "npm run build --env.type=dev"
"build:prod": "npm run build --env.type=prod"
}
So, eventually params such as --env.type=dev should be passed to webpack.
P.S. I tried with $# but with no luck
How to do that?
https://nodejs.org/api/cli.html#cli_1
package.json
"scripts": {
"tt": "node ./t.js",
"tt:t": "npm run tt -- --env.type=prod"
}
t.js
'use strict';
console.log(process.argv);
Result
npm run tt
> node ./t.js
[ '/home/nazar/.nvm/versions/node/v6.6.0/bin/node',
'/home/nazar/Workspace/Source/t.js'
npm run tt:t
> npm run tt -- --env.type=prod
> node ./t.js "--env.type=prod"
[ '/home/nazar/.nvm/versions/node/v6.6.0/bin/node',
'/home/nazar/Workspace/Source/t.js',
'--env.type=prod' ]

Passing variables from NPM Scripts to Webpack

I have a production build with Webpack that uses node's process.env to set environment variables:
webpack.prod.babel.js:
const DefinePlugin = new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
API_URL: JSON.stringify('https://myprodurl.com'),
},
});
packge.json:
"scripts: {
"build:prod": "webpack"
}
It's working fine, but I need something different.
I need to set the production url as variable in the NPM Script.
So, instead of this:
npm run build:prod
I need this:
npm run build:prod --URL https://myprodurl.com
How about defining your environment variable in the command line, like:
URL=https://myprodurl.com npm run build:prod
I tested this with a simple script and was able to print out the URL.
"scripts": {
"test": "./myTest.js"
},
myTest.js:
#!/usr/local/bin/node
'use strict'
console.log(process.env.URL);
console.log('Done!');
then:
$ URL=https://whatever.com npm run test
> my-test#1.0.0 test /Test/my-test
> ./myTest.js
https://whatever.com
Done!
EDIT: As mentioned by #RyanZim, see the following for Windows: https://github.com/kentcdodds/cross-env
(disclaimer: I don't use Windows and have never tried this lib)

Resources