Is there any way to fail the yarn build step in case any environment variable is missing. In the bitbucket pipeline script the build process is executing even if no env variable is set under the repository variables.
Yes, this can be possible using an approach in the React app. In the root directory create a JS file named as validate-env.js and add the below content in it (I'm using only these env variables in my app - change them according to yours)
require('dotenv').config();
if (!process.env.REACT_APP_WEB_SOCKET_URL) {
throw 'REACT_APP_WEB_SOCKET_URL undefined';
} else if (!process.env.REACT_APP_API_URL_PROD) {
throw 'REACT_APP_API_URL_PROD undefined';
} else if (!process.env.REACT_APP_NODE_ENV) {
throw 'REACT_APP_NODE_ENV undefined';
} else if (!process.env.REACT_APP_CATE_APP) {
throw 'REACT_APP_CATERING_APP undefined';
} else if (!process.env.REACT_APP_FRESH_CHAT_TOKEN) {
throw 'REACT_APP_FRESH_CHAT_TOKEN undefined';
} else if (!process.env.REACT_APP_SENTRY_DSN_KEY) {
throw 'REACT_APP_SENTRY_DSN_KEY undefined';
} else {
console.log('required env set');
}
Make sure to install a dev dependency as yarn add dotenv -D
Now under the package.json file > script section add this line
"validate-env": "node ./validate-env",
and update the build script as (if you are using craco)
"build": "yarn validate-env && craco build",
So, whenever you will run yarn build. It will first check if all the env are present. IF anyone is missing it will fail the build process.
My Problem
I have a ReactJS website that parses a JSON file (stored in the src folder) to render content. I recently attempted to use a YAML file instead because of YAML's richer abilities (supporting Markdown, for example).
Because React must load and parse YAML asynchronously, this change complicated my codebase and degraded my app's performance (e.g., content flickers).
My Plan
Instead of rewriting my components and slowing down my app, I've written a script to convert my YAML file into a JSON file. This way, I can have the best of both worlds: the richer abilities of YAML and the simple implementation of JSON.
My Question
What's the best way to make React run this script when the app is built? My web host rebuilds my app every time I push a change, so hopefully this can be activated via package.json or similar.
My Solution
I solved the problem using js-yaml. I even found a way to make it work with Fast Refresh.
./src/[PATH]/yaml-convert.js:
const yaml = require('js-yaml');
const fs = require('fs');
const args = process.argv.slice(2);
switch (args[0]) {
case 'watch':
watch();
break;
default:
convert();
}
function watch() {
fs.watch('./src/[PATH]/myData.yaml', function (event, filename) {
require('child_process').fork('./src/[PATH]/yaml-convert.js');
});
}
function convert() {
try {
const json = yaml.load(fs.readFileSync('./src/[PATH]/myData.yaml', 'utf8'));
fs.writeFileSync('./src/[PATH]/myData.json', JSON.stringify(json));
} catch (e) {
console.log(e);
}
}
package.json:
(note the -- watch argument and the single & in the dev command)
...
"scripts": {
"start": "serve -s build",
"dev": "npm run yaml-convert -- watch & react-scripts start",
"build": "npm run yaml-convert && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"yaml-convert": "node ./src/[PATH]/yaml-convert.js"
}
...
And to keep git diff tidy...
.gitattributes:
/src/[PATH]/myData.json -diff
Try creating an empty object that will store the converted data from the YAML, and use an if statement to check if the former object length is >0 then render what you want from the data (and if not, render a placeholder)
I'm using webpack for a React project and would like to include the WebpackBundleAnalyzer, but only when explicitly specified in the npm script (e.g., npm run build --withReport true). By default, I don't want it to run.
My build script in package.json is straightforward:
"build": "webpack --mode production",
As are are the relevant snippets from my webpack.config.js:
...
const withReport = process.env.npm_config_withReport || 'false';
...
plugins: [
...
withReport ? new BundleAnalyzerPlugin() : '',
],
...
My thought is that withReport will be false unless I specify otherwise (e.g., npm run build --withReport true), thus the BundleAnalyzer will not execute if I leave that off (npm run build).
Instead, the analyzer executes even if I don't specify --withReport. What am I missing?
I fixed this by making a couple changes to my webpack.config.js.
First I changed the way I declare withReport. Then I changed the way I instantiate BundleAnalyzerPlugin, to instead use concat after the other plugins:
...
const withReport = process.env.npm_config_withReport ? true : false;
...
plugins: [
...
].concat(withReport ? [new BundleAnalyzerPlugin()] : []),
...
I created react project with : yarn create react-app. I'm using webpack 4.29.6, react 16.8.6.
I want to disable code splitting because I want just one 'main.js' file in build/static/js folder. (I already removed hash from their names.)
I tried:
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
and
splitChunks: {
chunks: 'all',
name: false,
cacheGroups: {
default:false
}
}
but these solutions give me these files:
build
/static
/js
-2.chunk.js
-2.chunk.js.map
-main.chunk.js
-main.chunk.js.map
-runtime~main.js
-runtime~main.js.map
I think runtime~main.js file and .map file are just okay, but I want the exact 'main.js' file without chunk, without 2.chunk.js. How can I disable default code splitting of webpack 4?
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
]
Try if this works. Install this manually LimitChunkCountPlugin
https://webpack.js.org/plugins/limit-chunk-count-plugin/
If you created your project with create-react-app and haven't yet ejected, it appears you have two options currently available:
Option 1 - Create a custom build script
First, install the package rewire as a dependency:
npm install rewire
Create a scripts folder, inside create a new file and give it a name e.g., build-non-split.js, then add:
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
let config = defaults.__get__('config');
config.optimization.splitChunks = {
cacheGroups: {
default: false,
},
};
config.optimization.runtimeChunk = false;
Modify package.json, inside "scripts" and replace build with:
"build": "node ./scripts/build-non-split.js",
Finally, run npm run build or yarn build
Option 2 - Install the package react-app-rewire-disable-chunks
Note: If you go with this option, don't forget to replace the build script with react-app-rewired. Like this:
"build": "react-app-rewired build",
Source: Disabling code splitting in CRA2 #5306
I'm currently using create-react-app to bootstrap one of my projects. Basically, I'm trying to set up paths in tsconfig.json by adding these to the default tsconfig.json generated by create-react-app:
"baseUrl": "./src",
"paths": {
"interfaces/*": [
"common/interfaces/*",
],
"components/*": [
"common/components/*",
],
},
However, every time I run yarn start which basically runs react-scripts start, it deletes my changes and generates the default configurations again.
How can I tell create-react-app to use my custom configs?
I was able to do this by using advice from this issue.
Put the configuration options react scripts likes to remove in a separate file (e.g. paths.json) and reference it from tsconfig.json via the extends directive.
paths.json:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"interfaces/*": [ "common/interfaces/*"],
"components/*": [ "common/components/*"],
}
}
}
tsconfig.json
{
"extends": "./paths.json"
...rest of tsconfig.json
}
Create React App does not currently support baseUrl. However there is a workaround...to setup baseUrl for both webpack and the IDE you have to do the following:
Create a .env file with the following code:
NODE_PATH=./
Create a tsconfig.paths.json file with the following code inside:
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"src/*": ["*"]
}
}
}
Add the following line to tsconfig.json
{
"extends": "./tsconfig.paths.json",
...
}
You can't and I am unsure when you will be able to. I have been trying to use baseUrl and paths so I can avoid relative imports but as you can see they are intentionally removing certain values. The "(yet)" is encouraging but (sigh) who knows when they will officially be supporting it. I recommend subscribing to this github issue to be alerted if/when this changes.
The following changes are being made to your tsconfig.json file:
- compilerOptions.baseUrl must not be set (absolute imports are not supported (yet))
- compilerOptions.paths must not be set (aliased imports are not supported)
If you are using react-scripts 4.0.0 like me then all you need to do is remove the line (around line 160 on my end):
paths: { value: undefined, reason: 'aliased imports are not supported' }
from the file node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
I was able to straight up add my baseUrl and paths config to my tsconfig.json file like so:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#domain/*": ["../src/domain/*"],
},
}
}
and finally compile and move on with my life.
Per usual, YMMV. Please test your stuff. This is obviously a hack but it worked for me so I'm posting here in case it helps someone.
Here's a patch if you feel like sharing with your team:
diff --git a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
index 00139ee..5ccf099 100644
--- a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
+++ b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
## -156,7 +156,8 ## function verifyTypeScriptSetup() {
: 'react',
reason: 'to support the new JSX transform in React 17',
},
- paths: { value: undefined, reason: 'aliased imports are not supported' },
+ // Removed this line so I can add paths to my tsconfig file
+ // paths: { value: undefined, reason: 'aliased imports are not supported' },
};
Edit
Per #Bartekus thoughtful suggestion in the comments thread I'm adding information on the package I use when I need to add (possibly) temporary changes like these to an npm package: patch-package
The package essentially provides a way to make changes to a package in a cleaner way. Especially when you consider collaboration it becomes very cumbersome to directly change an npm file and move on. The next time you update that package or even when you start developing in a new machine and run npm install your changes will be lost. Also, if you have teammates working on the same project they would never inherit the changes.
In essence you go through the following steps to patch a package:
# fix a bug in one of your dependencies
vim node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
# run patch-package to create a .patch file
npx patch-package react-scripts
# commit the patch file to share the fix with your team
git add patches/react-scripts+4.0.0.patch
git commit -m "Enable aliased imports in react-scripts"
Next time someone checks out the project and installs it, the patch will be applied automatically due to a post-install script you add during set up:
"scripts": {
+ "postinstall": "patch-package"
}
See up to date instructions in the package's documentation
I had a similar issue to this general problem (CRA overwrites "noEmit": false in my tsconfig.json of a React library I'm working on where I have two separate builds, one for local development, and another to build the production library with typings). Simple solution: use sed in a postbuild script in the package.json. For example: In-place edits with sed on OS X .
{
...
"scripts": {
...
"postbuild": "sed -i '' 's/{THING CRA IS REPLACING}/{WHAT YOU ACTUALLY WANT}/g' tsconfig.json # CRA is too opinionated on this one.",
...
}
...
}
This approach, however, is not cross-platform (unlike how rimraf is the cross-platform alternative to rm -rf).
For me, the problem was with VSCode using an older version of typescript (4.0.3), while the typescript version shipped with the project is (4.1.2).
The following did the trick for me:
Go to the command palette CTRL+Shift+P.
Choose "TypeScript: Select a TypeScript Version...".
Choose "Use workspace Version".
On Botpress (with react-scripts 4.0.3), we use a combination of 2 tricks to use paths without ejecting or patching the code. As Glenn and Microcipcip said, the first step is to extend the tsconfig.json file
tsconfig.path.json
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"~/*": ["src/*"],
"common/*": ["../bp/src/common/*"]
}
}
}
tsconfig.json
{
...
"extends": "./tsconfig.paths.json"
}
Then to make it work in the background, use the package react-app-rewired. It allows to make slight adjustments to the webpack configuration without actually ejecting CRA.
config-overrides.js
module.exports = {
webpack: (config, env) => {
config.resolve.alias['common'] = path.join(__dirname, '../bp/dist/common')
config.resolve.alias['~'] = path.join(__dirname, './src')
}
}
To see the full code, you can check the github repository https://github.com/botpress/botpress/tree/master/packages/ui-admin
For macOS this workaround should work.
package.json
"scripts": {
"start": "osascript -e 'tell app \"Terminal\" to do script \"cd $PATH_TO_REACT_APP && node ./setNoEmitFalse\"' && react-scripts start",
...
},
...
setNoEmitFalse.js
const fs = require('fs');
const { sleep } = require('sleep')
const path = './tsconfig.json'
const run = async () => {
sleep(2)
const tsconfig = fs.readFileSync(path, 'utf-8');
const fixed = tsconfig.replace('"noEmit": true', '"noEmit": false');
fs.writeFileSync(path, fixed)
}
run()
The execution of the javascript file in a separate terminal (osascript) provides the normal output for react-scripts in the original terminal.
Go to node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js and replace
const compilerOptions = {
...
};
by
const compilerOptions = { };