Removing console.log in production React JS with WebPack / Babel - reactjs

I would like to keep console.log in developer builds, but in production builds I want them removed.
babel-plugin-transform-remove-console
I cannot remember if I installed it as --save or --save-dev (and not quite sure the difference). I also do not know how to check how it was installed, but it is in my node_modules directory as babel-plugin-transform-remove-console.
Whether I use npm run dev or npm run build to build my project I still see the console.log statements. I would have expected the npm run build command to remove the console.log files.
My .babelrc file looks like this:
{
"presets" : ["env", "stage-0", "react"],
"env" : {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
The pertinent parts of my package.json look like this:
"scripts": {
"dev": "webpack -d --watch",
"build": "webpack -p"
},
...
"dependencies": {
...
"babel-plugin-transform-remove-console": "^6.9.2",
...
}
Why is the npm run build not removing console.log statements for me?

-p is a flag for Webpack itself. Babel doesn't know anything about it. If you want your Webpack config to toggle behavior based on it, you'd need to do that yourself.
// webpack.config.js
module.exports = function(env) {
return {
// ...
module: {
rules: [{
loader: "babel-loader",
options: {
forceEnv: env.production ? "production" : "development"
}
}],
},
},
};

I cannot remember if I installed it as --save or --save-dev (and not quite sure the difference).
Just look at your package.json file.
-- save will make your package appear in dependencies (this is the default behaviour if no option was provided)
-- save-dev will make your package appear in devDependencies
https://docs.npmjs.com/cli/install

When you use run webpack -p, webpack sets process.env.NODE_ENV = "production", but Babel expects process.env.BABEL_ENV = "production".

Related

Webpack Error when trying to run reactJS app (w. typescript)

I'm trying to get webpack to work in my ReactJS & typescript app but I'm getting this error, and I can't figure out what I am missing. I've got a webpack.config.js file, shown further down and I have tsconfig.json and my scripts from package.json, seen further down:
Error Message
C:\Users\perni\Projects\typescript_project\react-crud>yarn start
yarn run v1.19.1
$ webpack-dev-server --mode development --open --hot
(node:15192) Warning: require() of ES modules is not supported.
require() of C:\Users\perni\Projects\typescript_project\react-crud\webpack.config.js from C:\Users\perni\Projects\typescript_project\react-crud\node_modules\webpack-cli\bin\utils\convert-argv.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename webpack.config.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\Users\perni\Projects\typescript_project_inspired\react-crud\package.json.
internal/modules/cjs/loader.js:1156
throw new ERR_REQUIRE_ESM(filename);
^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\perni\Projects\typescript_project_inspired\react-crud\webpack.config.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1156:13)
at Module.load (internal/modules/cjs/loader.js:976:32)
at Function.Module._load (internal/modules/cjs/loader.js:884:14)
at Module.require (internal/modules/cjs/loader.js:1016:19)
at require (internal/modules/cjs/helpers.js:69:18)
at WEBPACK_OPTIONS (C:\Users\perni\Projects\typescript_project_inspired\react-crud\node_modules\webpack-cli\bin\utils\convert-argv.js:114:13)
at requireConfig (C:\Users\perni\Projects\typescript_project_inspired\react-crud\node_modules\webpack-cli\bin\utils\convert-argv.js:116:6)
at C:\Users\perni\Projects\typescript_project_inspired\react-crud\node_modules\webpack-cli\bin\utils\convert-argv.js:123:17
at Array.forEach (<anonymous>)
at module.exports (C:\Users\perni\Projects\typescript_project_inspired\react-crud\node_modules\webpack-cli\bin\utils\convert-argv.js:121:15) {
code: 'ERR_REQUIRE_ESM'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
This is how my webpack config file looks, can provide more code if needed.
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// webpack will take the files from ./src/index
entry: './src/index',
// and output it into /dist as bundle.js
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/'
},
// adding .ts and .tsx to resolve.extensions will help babel look for .ts and .tsx files to transpile
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
module: {
rules: [
// we use babel-loader to load our jsx and tsx files
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
},
},
// css-loader to bundle all the css files into one file and style-loader to add all the styles inside the style tag of the document
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif|ico)$/,
exclude: /node_modules/,
use: ['file-loader?name=[name].[ext]'] // ?name=[name].[ext] is only necessary to preserve the original file name
}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.ico'
})
]
};
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --mode development --open --hot",
"build": "webpack --mode production",
"eject": "react-scripts eject",
"start:build": "tsc -w",
"start:run": "nodemon src/index.js",
"dev": "concurrently npm:start:*",
"bundle": "webpack"
},
What Node version you are using? I resolved the same error by changing node version to 12.10.0
depending upon your OS install NVM and then
nvm install 12.10.0
nvm use 12.10.0
then restart your terminal.
TL;DR: Remove the "type": "module" from the package.json file. That should solve the problem.
If type field is set to module then, it expects every .js file in your directory to be of ESModule type instead of CommonJS. It also means webpack.config.js and other webpack helper files like loaders which are loaded dynamically by Webpack using CommonJS/Node.js require() must be of ESModule as well.
Removing this field from the package.json should not impact as long as you are building for an application.
Authoring for libraries
If you are building/authorizing a library for NPM distribution, then it is a different story. If you intend to publish entire library as set of ESModules, then removal is not an option for you.
To solve library issue, you can use alternative approach of renaming Webpack config file to webpack.config.cjs. The .cjs extension tells Node that it is a CommonJS module even if package.json has "type": "module set.

Disable ESLint that create-react-app provides

create-react-app v3.0.0 is out. It supports TypeScript linting internally. (That's nice!) I think I understand the situation where TSLint is on, and am planning to replace it with ESLint, but it is not right now.
How to disable that linting step in react-scripts start?
/* eslint-disable */ and others are not the ones I'm looking for.
As of react-scripts v4.0.2, you can now opt out of ESLint with an environment variable. You can do this by adding it to your .env file, or by prefixing your scripts in your package.json file.
For example in .env:
DISABLE_ESLINT_PLUGIN=true
Or in your package.json:
{
"scripts": {
"start": "DISABLE_ESLINT_PLUGIN=true react-scripts start",
"build": "DISABLE_ESLINT_PLUGIN=true react-scripts build",
"test": "DISABLE_ESLINT_PLUGIN=true react-scripts test"
}
}
https://github.com/facebook/create-react-app/pull/10170
You could set EXTEND_ESLINT environment variable to true, for example in .env file:
EXTEND_ESLINT=true
Now you can extend eslint configuration in your package.json file:
...
"eslintConfig": {
"extends": "react-app",
"rules": {
"jsx-a11y/anchor-is-valid": "off"
}
},
...
To disable eslint you could add a file .eslintignore with the content:
*
See documentation for details: https://create-react-app.dev/docs/setting-up-your-editor/#experimental-extending-the-eslint-config
You can disable eslint (and override other configurations) using Craco.
It takes 4 changes:
npm install #craco/craco --save
create craco.config.js (in the same folder as is package.json)
populate craco.config.js with:
module.exports = {
eslint: {
enable: false,
},
};
Finally, replace react-script with craco in your package.json scripts, i.e.
"scripts": {
"build": "craco build",
"start": "craco start",
}
This will disable ESLint. Refer to Craco documentation for examples how to extend ESLint configuration.
step 1
create .env file in your project root if its not there and add this line to it
EXTEND_ESLINT=true
Step 2
add .eslintrc.js to your project root with following content
module.exports = {
"extends": ["react-app"],
"rules": {
},
"overrides": [
{
"files": ["**/*.js?(x)"],
"rules": {
// ******** add ignore rules here *********
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"react/prop-types": "off",
}
}
]
}
note that override > rules section: add rules with "off" flag to disable them.
My workaround without ejecting:
Use an environment variable in .eslintrc.js like this:
module.exports = {
"extends": process.env.REACT_APP_DEV_DISABLE_ESLINT ? [] : [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:json/recommended",
"plugin:#typescript-eslint/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react/recommended",
],
"rules": process.env.REACT_APP_DEV_DISABLE_ESLINT ? {} : {
// ...rules for production CI
}
}
Set the variable in start script in package.json:
{
"scripts": {
"eslint:disable": "REACT_APP_DEV_DISABLE_ESLINT=true",
"start": "npm run eslint:disable react-scripts start"
}
}
First ensure EXTEND_ESLINT environment variable is set to true. It can be set in .env file.
For Typescript, further rules should be added in overrides array, as example below:
{
"eslintConfig": {
"extends": ["react-app"],
"overrides": [
{
"files": ["**/*.ts?(x)"],
"rules": {
"eqeqeq": "warn"
}
}
]
}
}
My workaround:
Add a .eslintignore file:
*
and run eslint with --no-ignore. So you are able to setup your own eslint. If you need a ignore file you can define it with --ignore-path instead of using the --no-ignore option.
One way is to eject react-scripts - by running yarn eject / npm run eject - and turn off eslint in webpack config file manually.
Beware though that ejecting should not be done lightly and other options should be considered before ejecting. Please read Don’t eject your Create React App to gain some understanding of what it means and perhaps some reason's why you shouldn't
Please take a look at this fork: create-react-app closer look, especially at eject-tic_tac_toe directory, where you have scripts/start.js - the script where the magic happens after yarn start / npm start - and config/webpack.config.dev.js - where you have webpack's config, used in start.js. This is the part you can be interested in to edit:
// …
module.exports = {
// …
module: {
preLoaders: [
{
test: /\.(js|jsx)$/,
loader: 'eslint',
include: paths.appSrc,
}
]
}
// …
};

create-react-app jest encountered unexpected token {

I'm developing a React app with a QR-scanner in it with create-react-app.
I've added the module react-qr-reader which in turn uses the modules webrtc-adapter.
It all works great, until I run yarn test. Then it shows me this error:
I've already ejected the project so I can use transformIgnorePatterns and added node_modules/webrtc-adapter to the array, but that still results in the same error.
Can anyone help me with this?
If you don't want to eject from Create-React-App you can use the CLI in your package.json to override 'transformIgnorePatterns'.
Reference - https://github.com/facebook/create-react-app/issues/2537#issuecomment-390341713
"scripts": {
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!your-module-name)/\"",
},
It's because of de ES6 syntax in a package into node_modules, you need to config the "transformIgnorePatterns" to transform this package.
The issue on Jest: https://github.com/facebook/jest/issues/2081
How to configure: http://facebook.github.io/jest/docs/tutorial-react-native.html#transformignorepatterns-customization
"transformIgnorePatterns": [
"node_modules/(?!(react-qr-reader)/)"
]
if this doesn't work, use the babel.config.js with this configuration (is important the file ".js", this configuration don't work in ".babelrc" file):
module.exports = {
presets: [
[
"#babel/preset-env",
{
"modules": "commonjs",
"debug": false
}
],
/// your presets
],
plugins: [
//... your plugins
]
};

React Storybook Fails on Demo

I'm attempting to use React Storybook in a project that already has an extensive Webpack 2 config. I started the Storybook following the basic steps:
npm i -g #storybook/cli
getstorybook
When I run yarn storybook, it breaks on the JSX of the demo component:
ERROR in ./stories/index.jsx
Module parse failed: /Users/alexanderhadik/project/web/node_modules/#storybook/react/node_modules/babel-loader/lib/index.js??ref--0!/Users/alexanderhadik/project/web/stories/index.jsx Unexpected token (9:55)
You may need an appropriate loader to handle this file type.
| import { Button, Welcome } from '#storybook/react/demo';
|
| storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);
|
| storiesOf('Button', module)
# ./.storybook/config.js 4:2-23
# multi ./node_modules/#storybook/react/dist/server/config/polyfills.js ./node_modules/#storybook/react/dist/server/config/globals.js ./node_modules/webpack-hot-middleware/client.js?reload=true ./.storybook/config.js
Since I didn't start this project originally using create-react-app - do I need to modify the Storybook webpack config to enable JSX?
This might to be a problem with Storybook not replicating webpack babelrc behaviour exactly.
In my case, I had an empty (just {}) .babelrc file with all the important react/jsx plugins defined in webpack.config.js. Storybook read the .babelrc instead of using the babel settings in webpack.config.js.
Deleting the .babelrc solved that issue.
in my case, i didnt have a .babelrc at all -- i used the entry "babel" in the package.json. when running the storybook in this project, the babel entry wasnt there. i added it and things magically started working.
{
"name": "root",
"private": true,
"devDependencies": {
"#storybook/addon-actions": "^4.1.11",
"#storybook/addon-links": "^4.1.11",
"#storybook/addons": "^4.1.11",
"#storybook/react": "^4.1.11",
...
},
"dependencies": {},
"scripts": {
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"babel": {
"presets": [
"#babel/preset-env",
"#babel/preset-react"
]
}
}
i hope this helps someone.

How do I change `src` folder to something else in create-react-app

I'd like to know if it's possible using react-script to rename src to something else like app folder
You can use react-app-rewired to override react paths configuration.
In my case, I can change the paths in config-overrides.js file
const path = require('path');
module.exports = {
paths: function (paths, env) {
paths.appIndexJs = path.resolve(__dirname, 'mysrc/client.js');
paths.appSrc = path.resolve(__dirname, 'mysrc');
return paths;
},
}
Not sure if this answers your question but I'll give it a shot. My directory structure looks like this:
/root
--/app
----/build
----/public
------index.html
----/src
------index.js
app.js
package.js
My /root/package.json has this in it:
"scripts": {
"build": "cd app && npm run build",
"start": "node app.js",
"serve": "cd app && npm run start"
},
"dependencies": {
"express": "^4.8.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-scripts": "^1.0.17"
},
and my /root/app/package.json looks like this:
"scripts": {
"build": "react-scripts build",
"start": "set PORT=3000 && react-scripts start"
},
"dependencies": {
"react-scripts": "^1.0.17"
}
To run the development version of Reactjs, in the /root I can just npm run serve to serve up the dev version.
I am using node and express, so to run the production version of Reactjs,
in the /root I can just npm run build to create the /root/app/build directory. I have a router that looks like this:
var options = {root : config.siteRoot + '/app/build'};
mainRte.all('/', function(req, res) {
console.log('In mainRte.all Root');
res.sendFile('index.html', options);
});
so when I run /root/app.js in node and surf to "/" it opens up /root/app/public/index.html and then /root/app/index.js.
Hopefully that helps.
react-app-rewired allows for this exact customization.
1
Install react-app-rewired as a dev dependency:
npm install --save-dev react-app-rewired
2
In package.json, change these lines
"scripts": {
"react-start": "react-scripts start",
"react-build": "react-scripts build",
"react-test": "react-scripts test",
...
}
to
"scripts": {
"react-start": "react-app-rewired start",
"react-build": "react-app-rewired build",
"react-test": "react-app-rewired test",
...
}
3
Create a config-overrides.json file in your project directory root with the following contents:
const paths = require('react-scripts/config/paths')
const path = require('path')
// Make the "app" folder be treated as the "src" folder
paths.appSrc = path.resolve(__dirname, 'app')
// Tell the app that "src/index.js" has moved to "app/index.js"
paths.appIndexJs = path.resolve(__dirname, 'app/index.js')
Now your app folder is the new src!
You can also customize many other things, such as the name of the "public" folder:
paths.appPublic = path.resolve(__dirname, 'subfolder/public')
paths.appHtml = path.resolve(__dirname, 'subfolder/public/index.html')
And you can also change the location of package.json and node_modules. See here for the full list.
I know this is an old question but I'm still gonna post my solution since it might help someone.
I got it working by doing the following:
Run npm run eject. This exposes some internal configuration stuff from create-react-app
Open your package.json and edit the respective regexes under jest.collectCoverageFrom and jest.testMatch to match your test path
Alter the paths for appSrc, appIndexJs and testsSetup in the config/paths.js file
T0astBread's answer is nearly perfect, but there's an additional reference to "src" that he missed inside modules.js.
Specifically:
return {
src: paths.appSrc,
};
needs to be changed to
return {
newSrcName: paths.appSrc,
};
This is a great question and a valid scenario for changing this folder name is when migrating old react projects to CRA.
Here's another approach I found that breaks less things:
Create a symlink with:
ls -s ./app src
Then add this in config-overrides.js, to allow webpack to process the symlink:
module.exports = (config, ...rest) => {
return { ...config, resolve: { ...config.resolve, symlinks: false } };
};
Then install react-app-rewired and add this to your package.json:
"start": "react-app-rewired start",
While Cong Dan Luong's answer is correct as far as renaming the folder goes, it will break testing with jest. You need to expand the config-overrides.js module.exports part with the following:
module.exports = {
jest: function(config) {
config.collectCoverageFrom = ['client/**/*.{js,jsx,ts,tsx}', '!client/**/*.d.ts'];
config.testMatch = [
'<rootDir>/client/**/__tests__/**/*.{js,jsx,ts,tsx}',
'<rootDir>/client/**/*.{spec,test}.{js,jsx,ts,tsx}',
];
config.roots = ['<rootDir>/client'];
return config;
},
// The paths config
paths: function(paths, env) {
paths.appIndexJs = path.resolve(__dirname, 'client/index.js');
paths.appSrc = path.resolve(__dirname, 'client');
return paths;
},
};
In my above example I am using 'client' instead of 'src'. npm test now works.
Perhaps a symbolic link might address your reasons for wanting to do this:
ln -s ./src/ ./app
The src folder will remain but you can work with it as if it was the app folder.
If, like me you're using vscode you can also do:
Cmd-shift-p search workspace settings, and add the following:
{
"files.exclude": {
"src/": true
}
}
You could do similarly with other editors
Create file in root of your project, insert this code and run.
const fs = require('fs');
const path = './node_modules/react-scripts/config/paths.js';
const folder = 'app';
fs.readFile(path, 'utf8', (err, data) => {
if (err) throw err;
data = data.replace(/src/g, folder);
fs.writeFile(path, data, 'utf8');
});

Resources