diff --git a/packages/eslint-plugin/configs/recommended-with-formatting.js b/packages/eslint-plugin/configs/recommended-with-formatting.js index 3c7ce025ce8fe9..2499d8656d0c04 100644 --- a/packages/eslint-plugin/configs/recommended-with-formatting.js +++ b/packages/eslint-plugin/configs/recommended-with-formatting.js @@ -16,6 +16,7 @@ const config = { globals: { window: true, document: true, + SCRIPT_DEBUG: 'readonly', wp: 'readonly', }, settings: { diff --git a/packages/jest-preset-default/scripts/setup-globals.js b/packages/jest-preset-default/scripts/setup-globals.js index 105e0ab508ab37..abd99f620dc893 100644 --- a/packages/jest-preset-default/scripts/setup-globals.js +++ b/packages/jest-preset-default/scripts/setup-globals.js @@ -1,3 +1,6 @@ +// Run all tests with development tools enabled. +global.SCRIPT_DEBUG = true; + // These are necessary to load TinyMCE successfully. global.URL = window.URL; global.window.tinyMCEPreInit = { diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index c02fbfcbea2c96..29a25c9353ff3c 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -4,6 +4,7 @@ const { BundleAnalyzerPlugin } = require( 'webpack-bundle-analyzer' ); const { CleanWebpackPlugin } = require( 'clean-webpack-plugin' ); const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); +const { DefinePlugin } = require( 'webpack' ); const browserslist = require( 'browserslist' ); const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' ); const { basename, dirname, resolve } = require( 'path' ); @@ -243,6 +244,10 @@ const config = { ], }, plugins: [ + new DefinePlugin( { + // Inject the `SCRIPT_DEBUG` global, used for development features flagging. + SCRIPT_DEBUG: ! isProduction, + } ), // During rebuilds, all webpack assets that are not used anymore will be // removed automatically. There is an exception added in watch mode for // fonts and images. It is a known limitations: diff --git a/packages/warning/README.md b/packages/warning/README.md index 6adfe73b6d4594..67b471d154eccf 100644 --- a/packages/warning/README.md +++ b/packages/warning/README.md @@ -20,7 +20,7 @@ To prevent that, you should: 1. Put `@wordpress/warning/babel-plugin` into your [babel config](https://babeljs.io/docs/en/plugins#plugin-options) or use [`@wordpress/babel-preset-default`](https://www.npmjs.com/package/@wordpress/babel-preset-default), which already includes the babel plugin. - This will make sure your `warning` calls are wrapped within a condition that checks if `process.env.NODE_ENV !== 'production'`. + This will make sure your `warning` calls are wrapped within a condition that checks if `SCRIPT_DEBUG === true`. 2. Use [UglifyJS](https://github.com/mishoo/UglifyJS2), [Terser](https://github.com/terser/terser) or any other JavaScript parser that performs [dead code elimination](https://en.wikipedia.org/wiki/Dead_code_elimination). This is usually used in conjunction with JavaScript bundlers, such as [webpack](https://github.com/webpack/webpack). diff --git a/packages/warning/babel-plugin.js b/packages/warning/babel-plugin.js index f94de3a4f4ca28..02c466b5de24ec 100644 --- a/packages/warning/babel-plugin.js +++ b/packages/warning/babel-plugin.js @@ -5,7 +5,7 @@ const pkg = require( './package.json' ); /** * Babel plugin which transforms `warning` function calls to wrap within a - * condition that checks if `process.env.NODE_ENV !== 'production'`. + * condition that checks if `SCRIPT_DEBUG === true`. * * @param {import('@babel/core')} babel Current Babel object. * @@ -16,34 +16,20 @@ function babelPlugin( { types: t } ) { const typeofProcessExpression = t.binaryExpression( '!==', - t.unaryExpression( 'typeof', t.identifier( 'process' ), false ), + t.unaryExpression( 'typeof', t.identifier( 'SCRIPT_DEBUG' ), false ), t.stringLiteral( 'undefined' ) ); - const processEnvExpression = t.memberExpression( - t.identifier( 'process' ), - t.identifier( 'env' ), - false - ); - - const nodeEnvCheckExpression = t.binaryExpression( - '!==', - t.memberExpression( - processEnvExpression, - t.identifier( 'NODE_ENV' ), - false - ), - t.stringLiteral( 'production' ) + const scriptDebugCheckExpression = t.binaryExpression( + '===', + t.identifier( 'SCRIPT_DEBUG' ), + t.booleanLiteral( true ) ); const logicalExpression = t.logicalExpression( '&&', - t.logicalExpression( - '&&', - typeofProcessExpression, - processEnvExpression - ), - nodeEnvCheckExpression + typeofProcessExpression, + scriptDebugCheckExpression ); return { @@ -80,7 +66,7 @@ function babelPlugin( { types: t } ) { // Turns this code: // warning(argument); // into this: - // typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning(argument) : void 0; + // typeof SCRIPT_DEBUG !== 'undefined' && SCRIPT_DEBUG === true ? warning(argument) : void 0; node[ seen ] = true; path.replaceWith( t.ifStatement( diff --git a/packages/warning/src/index.js b/packages/warning/src/index.js index 38afc42caf0b0b..89ce71db112a21 100644 --- a/packages/warning/src/index.js +++ b/packages/warning/src/index.js @@ -4,11 +4,7 @@ import { logged } from './utils'; function isDev() { - return ( - typeof process !== 'undefined' && - process.env && - process.env.NODE_ENV !== 'production' - ); + return typeof SCRIPT_DEBUG !== 'undefined' && SCRIPT_DEBUG === true; } /** diff --git a/packages/warning/src/test/index.js b/packages/warning/src/test/index.js index a7ecbfb4a8ffec..a32e5f1e0fae4e 100644 --- a/packages/warning/src/test/index.js +++ b/packages/warning/src/test/index.js @@ -4,27 +4,28 @@ import warning from '..'; import { logged } from '../utils'; -const initialNodeEnv = process.env.NODE_ENV; - describe( 'warning', () => { + const initialScriptDebug = global.SCRIPT_DEBUG; + afterEach( () => { - process.env.NODE_ENV = initialNodeEnv; + global.SCRIPT_DEBUG = initialScriptDebug; logged.clear(); } ); - it( 'logs to console.warn when NODE_ENV is not "production"', () => { - process.env.NODE_ENV = 'development'; + it( 'logs to console.warn when SCRIPT_DEBUG is set to `true`', () => { + global.SCRIPT_DEBUG = true; warning( 'warning' ); expect( console ).toHaveWarnedWith( 'warning' ); } ); - it( 'does not log to console.warn if NODE_ENV is "production"', () => { - process.env.NODE_ENV = 'production'; + it( 'does not log to console.warn if SCRIPT_DEBUG not set to `true`', () => { + global.SCRIPT_DEBUG = false; warning( 'warning' ); expect( console ).not.toHaveWarned(); } ); it( 'should show a message once', () => { + global.SCRIPT_DEBUG = true; warning( 'warning' ); warning( 'warning' ); diff --git a/packages/warning/test/babel-plugin.js b/packages/warning/test/babel-plugin.js index a98d270a9845bc..a3c4bd55745efd 100644 --- a/packages/warning/test/babel-plugin.js +++ b/packages/warning/test/babel-plugin.js @@ -28,7 +28,7 @@ describe( 'babel-plugin', () => { ); const expected = join( 'import warning from "@wordpress/warning";', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning("a") : void 0;' + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warning("a") : void 0;' ); expect( transformCode( input ) ).toEqual( expected ); @@ -45,7 +45,7 @@ describe( 'babel-plugin', () => { const input = 'warning("a");'; const options = { callee: 'warning' }; const expected = - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning("a") : void 0;'; + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warning("a") : void 0;'; expect( transformCode( input, options ) ).toEqual( expected ); } ); @@ -59,9 +59,9 @@ describe( 'babel-plugin', () => { ); const expected = join( 'import warning from "@wordpress/warning";', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning("a") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning("b") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning("c") : void 0;' + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warning("a") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warning("b") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warning("c") : void 0;' ); expect( transformCode( input ) ).toEqual( expected ); @@ -76,9 +76,9 @@ describe( 'babel-plugin', () => { ); const expected = join( 'import warn from "@wordpress/warning";', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("a") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("b") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("c") : void 0;' + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("a") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("b") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("c") : void 0;' ); expect( transformCode( input ) ).toEqual( expected ); @@ -93,9 +93,9 @@ describe( 'babel-plugin', () => { ); const expected = join( 'import warn from "@wordpress/warning";', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("a") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("b") : void 0;', - 'typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warn("c") : void 0;' + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("a") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("b") : void 0;', + 'typeof SCRIPT_DEBUG !== "undefined" && SCRIPT_DEBUG === true ? warn("c") : void 0;' ); expect( transformCode( input ) ).toEqual( expected ); diff --git a/tools/webpack/shared.js b/tools/webpack/shared.js index 9aaa35737400c9..debd3fc93f6f6d 100644 --- a/tools/webpack/shared.js +++ b/tools/webpack/shared.js @@ -69,6 +69,8 @@ const plugins = [ // Inject the `IS_WORDPRESS_CORE` global, used for feature flagging. 'process.env.IS_WORDPRESS_CORE': process.env.npm_package_config_IS_WORDPRESS_CORE, + // Inject the `SCRIPT_DEBUG` global, used for dev versions of JavaScript. + SCRIPT_DEBUG: mode === 'development', } ), mode === 'production' && new ReadableJsAssetsWebpackPlugin(), ]; diff --git a/typings/gutenberg-env/index.d.ts b/typings/gutenberg-env/index.d.ts index e2876716bd8b7f..ecf60a7ca094f9 100644 --- a/typings/gutenberg-env/index.d.ts +++ b/typings/gutenberg-env/index.d.ts @@ -7,3 +7,5 @@ interface Process { env: Environment; } declare var process: Process; + +declare var SCRIPT_DEBUG: boolean;