Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Expand Feature flags #2591

Merged
merged 17 commits into from
Jun 5, 2020
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
rules: {
'@wordpress/dependency-group': 'off',
'woocommerce/dependency-group': 'error',
'woocommerce/feature-flag': 'error',
'woocommerce/feature-flag': 'off',
'valid-jsdoc': 'off',
radix: 'error',
yoda: [ 'error', 'never' ],
Expand Down
14 changes: 7 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,35 @@ jobs:
php: 7.1
env:
- WP_VERSION=latest
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
script:
- phpunit
- name: PHP 5.6/unit-tests/Latest WP
php: 5.6
env:
- WP_VERSION=latest
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
script:
- phpunit
- name: PHP Linting Check
php: 7.3
env:
- WP_TRAVISCI=phpcs
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
script:
- npm run lint:php
- name: Javascript Tests
script:
- npm install
- npm run test
env:
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
- name: Javascript/CSS Lint check
script:
- npm install
- npm run lint:ci
env:
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
- name: E2E Tests
script:
- npm ci
Expand All @@ -84,12 +84,12 @@ jobs:
- npm run build:e2e-test
- npm run test:e2e
env:
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
- stage: deploy
if: (NOT type IN (pull_request)) AND (branch = master)
name: Deploy Storybook
env:
- WOOCOMMERCE_BLOCKS_PHASE=experimental
- WOOCOMMERCE_BLOCKS_PHASE=3
install:
- npm ci
script:
Expand Down
5 changes: 2 additions & 3 deletions assets/js/blocks/cart-checkout/cart/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
*/
import { __ } from '@wordpress/i18n';
import { InnerBlocks } from '@wordpress/block-editor';
import { registerBlockType } from '@wordpress/blocks';
import { Icon, cart } from '@woocommerce/icons';
import classnames from 'classnames';

import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
Expand Down Expand Up @@ -51,4 +50,4 @@ const settings = {
},
};

registerBlockType( 'woocommerce/cart', settings );
registerFeaturePluginBlockType( 'woocommerce/cart', settings );
4 changes: 2 additions & 2 deletions assets/js/blocks/cart-checkout/checkout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import { Icon, card } from '@woocommerce/icons';
import classnames from 'classnames';
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';

/**
* Internal dependencies
Expand Down Expand Up @@ -49,4 +49,4 @@ const settings = {
},
};

registerBlockType( 'woocommerce/checkout', settings );
registerFeaturePluginBlockType( 'woocommerce/checkout', settings );
4 changes: 2 additions & 2 deletions assets/js/blocks/single-product/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import { registerExperimentalBlockType } from '@woocommerce/block-settings';

/**
* Internal dependencies
Expand Down Expand Up @@ -40,4 +40,4 @@ const settings = {
save,
};

registerBlockType( BLOCK_NAME, settings );
registerExperimentalBlockType( BLOCK_NAME, settings );
4 changes: 4 additions & 0 deletions assets/js/settings/blocks/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const IS_SHIPPING_COST_HIDDEN = getSetting(
'isShippingCostHidden',
false
);
export const WOOCOMMERCE_BLOCKS_PHASE = getSetting(
'woocommerceBlocksPhase',
1
);
export const WC_BLOCKS_ASSET_URL = getSetting( 'wcBlocksAssetUrl', '' );
export const SHIPPING_COUNTRIES = getSetting( 'shippingCountries', {} );
export const ALLOWED_COUNTRIES = getSetting( 'allowedCountries', {} );
Expand Down
57 changes: 57 additions & 0 deletions assets/js/settings/blocks/feature-flags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 on putting these in their own file (and the name is great)!

* External dependencies
*/
import { registerBlockType } from '@wordpress/blocks';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern I have here is that we are now loading this api on the frontend for anything using block-settings right? is that problematic? I think I might have been the one who suggested putting this api in block-settings so that could be my fault here.

It doesn't look like it's affected build sizes significantly, so maybe this would be okay (since @woocommerce/block-settings is essentially just an alias for the path and thus it should be tree-shakeable).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had similar conerns, but I'm assuming this is tree shakeable, bundle bot didn’t report any extra weight so It’s safe.


/**
* Internal dependencies
*/
import { WOOCOMMERCE_BLOCKS_PHASE } from './constants';

/**
* Registers a new experimental block provided a unique name and an object defining its
* behavior. Once registered, the block is made available as an option to any
* editor interface where blocks are implemented.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
*
* @return {?Object} The block, if it has been successfully registered;
* otherwise `undefined`.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for being so thorough with the comment blocks here 👏 !

export const registerExperimentalBlockType = ( name, settings ) => {
if ( WOOCOMMERCE_BLOCKS_PHASE > 2 ) {
return registerBlockType( name, settings );
}
};

/**
* Registers a new feature plugin block provided a unique name and an object
* defining its behavior. Once registered, the block is made available as an
* option to any editor interface where blocks are implemented.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
*
* @return {?Object} The block, if it has been successfully registered;
* otherwise `undefined`.
*/
export const registerFeaturePluginBlockType = ( name, settings ) => {
if ( WOOCOMMERCE_BLOCKS_PHASE > 1 ) {
return registerBlockType( name, settings );
}
};

/**
* Checks if we're executing the code in an experimental build mode.
*
* @return {boolean} True if this is an experimental build, false otherwise.
*/
export const isExperimentalBuild = () => WOOCOMMERCE_BLOCKS_PHASE > 2;

/**
* Checks if we're executing the code in an feature plugin or experimental build mode.
*
* @return {boolean} True if this is an experimental or feature plugin build, false otherwise.
*/
export const isFeaturePluginBuild = () => WOOCOMMERCE_BLOCKS_PHASE > 1;
1 change: 1 addition & 0 deletions assets/js/settings/blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
* Internal dependencies
*/
export * from './constants';
export * from './feature-flags';
5 changes: 3 additions & 2 deletions bin/eslint-plugin-woocommerce/rules/feature-flag.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ function findParent( sourceNode, predicate ) {
* @example
* ```js
* // good
* if ( process.env.WOOCOMMERCE_BLOCKS_PHASE === 'experimental' ) {
* if ( process.env.WOOCOMMERCE_BLOCKS_PHASE > 1 ) {
*
* // bad
* if ( WOOCOMMERCE_BLOCKS_PHASE === 'experimental' ) {
* if ( WOOCOMMERCE_BLOCKS_PHASE > 1 ) {
* ```
*
* @param {Object} node The WOOCOMMERCE_BLOCKS_PHASE identifier node.
* @param {Object} context The eslint context object.
* @todo: update this rule to match the new flags.
*/
function testIsAccessedViaProcessEnv( node, context ) {
let parent = node.parent;
Expand Down
40 changes: 10 additions & 30 deletions bin/webpack-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extrac
const WebpackRTLPlugin = require( 'webpack-rtl-plugin' );
const chalk = require( 'chalk' );
const { omit } = require( 'lodash' );
const { DefinePlugin } = require( 'webpack' );
const NODE_ENV = process.env.NODE_ENV || 'development';

function findModuleMatch( module, match ) {
Expand Down Expand Up @@ -149,16 +148,17 @@ const stableMainEntry = {
'active-filters': './assets/js/blocks/active-filters/index.js',
'block-error-boundary':
'./assets/js/base/components/block-error-boundary/style.scss',
'single-product': './assets/js/blocks/single-product/index.js',
cart: './assets/js/blocks/cart-checkout/cart/index.js',
checkout: './assets/js/blocks/cart-checkout/checkout/index.js',
};

const experimentalMainEntry = {
cart: './assets/js/blocks/cart-checkout/cart/index.js',
checkout: './assets/js/blocks/cart-checkout/checkout/index.js',
'single-product': './assets/js/blocks/single-product/index.js',
};

const mainEntry =
process.env.WOOCOMMERCE_BLOCKS_PHASE === 'stable'
// env variables are strings, so we compare against a string, so we need to parse it.
parseInt( process.env.WOOCOMMERCE_BLOCKS_PHASE, 10 ) < 3
? stableMainEntry
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means that we still have dead code removal on releases for anything marked experimental right? Might be a good idea to also check that process.env.WOOCOMMERCE_BLOCKS_PHASE is defined before using here? If it's undefined won't this cause a ReferenceError (especially since it looks like we no longer define a default for process.env.WOOCOMMERCE_BLOCKS_PHASE)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn’t cause a Reference Error because process.env is always defined, WOOCOMMERCE_BLOCKS_PHASE not being defined will result in experimental files being generated which is safer than them not being generated right?

Copy link
Contributor

@nerrad nerrad Jun 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay with experimental files being built if WOOCOMMERCE_BLOCKS_PHASE is not defined, that's not what I'm calling out here. I thought we might have an issue if parseInt returned NaN but it looks like we won't:

Image 2020-06-02 at 3 32 39 PM

So all is okay here (assuming node behaves the same).

: { ...stableMainEntry, ...experimentalMainEntry };

Expand All @@ -168,16 +168,17 @@ const stableFrontEndEntry = {
'price-filter': './assets/js/blocks/price-filter/frontend.js',
'attribute-filter': './assets/js/blocks/attribute-filter/frontend.js',
'active-filters': './assets/js/blocks/active-filters/frontend.js',
'single-product': './assets/js/blocks/single-product/frontend.js',
cart: './assets/js/blocks/cart-checkout/cart/frontend.js',
checkout: './assets/js/blocks/cart-checkout/checkout/frontend.js',
};

const experimentalFrontEndEntry = {
cart: './assets/js/blocks/cart-checkout/cart/frontend.js',
checkout: './assets/js/blocks/cart-checkout/checkout/frontend.js',
'single-product': './assets/js/blocks/single-product/frontend.js',
};

const frontEndEntry =
process.env.WOOCOMMERCE_BLOCKS_PHASE === 'stable'
// env variables are strings, so we compare against a string, so we need to parse it.
parseInt( process.env.WOOCOMMERCE_BLOCKS_PHASE, 10 ) < 3
? stableFrontEndEntry
: { ...stableFrontEndEntry, ...experimentalFrontEndEntry };

Expand Down Expand Up @@ -358,13 +359,6 @@ const getMainConfig = ( options = {} ) => {
requestToExternal,
requestToHandle,
} ),
new DefinePlugin( {
// Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging.
'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify(
// eslint-disable-next-line woocommerce/feature-flag
process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental'
),
} ),
],
resolve,
};
Expand Down Expand Up @@ -460,13 +454,6 @@ const getFrontConfig = ( options = {} ) => {
requestToExternal,
requestToHandle,
} ),
new DefinePlugin( {
// Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging.
'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify(
// eslint-disable-next-line woocommerce/feature-flag
process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental'
),
} ),
],
resolve,
};
Expand Down Expand Up @@ -599,13 +586,6 @@ const getPaymentMethodsExtensionConfig = ( options = {} ) => {
requestToExternal,
requestToHandle,
} ),
new DefinePlugin( {
// Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging.
'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify(
// eslint-disable-next-line woocommerce/feature-flag
process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental'
),
} ),
],
resolve,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to get someone else to review webpack who knows more :)

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"build:map": "cross-env BABEL_ENV=default NODE_ENV=production FORCE_MAP=true webpack",
"changelog": "node ./bin/changelog",
"changelog:zenhub": "node ./bin/changelog --changelogSrcType='ZENHUB_RELEASE'",
"deploy": "cross-env WOOCOMMERCE_BLOCKS_PHASE=stable composer install --no-dev && npm run build --loglevel error && sh ./bin/github-deploy.sh",
"deploy": "cross-env WOOCOMMERCE_BLOCKS_PHASE=2 composer install --no-dev && npm run build --loglevel error && sh ./bin/github-deploy.sh",
"dev": "cross-env BABEL_ENV=default webpack",
"explore": "source-map-explorer",
"lint": "npm run lint:php && npm run lint:css && npm run lint:js",
Expand Down Expand Up @@ -208,4 +208,4 @@
"license.txt",
"woocommerce-gutenberg-products-block.php"
]
}
}
10 changes: 7 additions & 3 deletions src/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,15 @@ public static function register_assets() {
self::register_script( 'wc-price-filter', plugins_url( self::get_block_asset_build_path( 'price-filter' ), __DIR__ ), $block_dependencies );
self::register_script( 'wc-attribute-filter', plugins_url( self::get_block_asset_build_path( 'attribute-filter' ), __DIR__ ), $block_dependencies );
self::register_script( 'wc-active-filters', plugins_url( self::get_block_asset_build_path( 'active-filters' ), __DIR__ ), $block_dependencies );
self::register_script( 'wc-checkout-block', plugins_url( self::get_block_asset_build_path( 'checkout' ), __DIR__ ), $block_dependencies );
self::register_script( 'wc-cart-block', plugins_url( self::get_block_asset_build_path( 'cart' ), __DIR__ ), $block_dependencies );

if ( 'experimental' === WOOCOMMERCE_BLOCKS_PHASE ) {
if ( Package::is_experimental_build() ) {
self::register_script( 'wc-single-product-block', plugins_url( self::get_block_asset_build_path( 'single-product' ), __DIR__ ), $block_dependencies );
}

if ( Package::is_feature_plugin_build() ) {
self::register_script( 'wc-checkout-block', plugins_url( self::get_block_asset_build_path( 'checkout' ), __DIR__ ), $block_dependencies );
self::register_script( 'wc-cart-block', plugins_url( self::get_block_asset_build_path( 'cart' ), __DIR__ ), $block_dependencies );
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we should move script registration to the block classes - I always forget to add them here :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, there's a bunch of things I'd like to do around that eventually (including incorporating using block.json files which can contain all the things around the blocks and thus make the initialization code more dynamic).

}

/**
Expand Down Expand Up @@ -178,6 +181,7 @@ public static function get_wc_block_data( $settings ) {
'checkoutAllowsGuest' => 'yes' === get_option( 'woocommerce_enable_guest_checkout' ),
'checkoutAllowsSignup' => 'yes' === get_option( 'woocommerce_enable_signup_and_login_from_checkout' ),
'baseLocation' => wc_get_base_location(),
'woocommerceBlocksPhase' => WOOCOMMERCE_BLOCKS_PHASE,

/*
* translators: If your word count is based on single characters (e.g. East Asian characters),
Expand Down
22 changes: 11 additions & 11 deletions src/Domain/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ protected function init() {
if ( ! $this->has_core_dependencies() ) {
return;
}
$this->define_feature_flag();
$this->register_dependencies();
$this->register_payment_methods();

Expand All @@ -72,7 +73,6 @@ protected function init() {
// Load assets in admin and on the frontend.
if ( ! $is_rest ) {
$this->add_build_notice();
$this->define_feature_flag();
$this->container->get( AssetDataRegistry::class );
$this->container->get( Installer::class );
BlockAssets::init();
Expand Down Expand Up @@ -130,17 +130,17 @@ function() {
* Define the global feature flag.
*/
protected function define_feature_flag() {
$allowed_flags = [ 'experimental', 'stable' ];
$flag = getenv( 'WOOCOMMERCE_BLOCKS_PHASE' );
if ( ! in_array( $flag, $allowed_flags, true ) ) {
if ( file_exists( __DIR__ . '/../../blocks.ini' ) ) {
$woo_options = parse_ini_file( __DIR__ . '/../../blocks.ini' );
$flag = is_array( $woo_options ) && 'experimental' === $woo_options['woocommerce_blocks_phase'] ? 'experimental' : 'stable';
} else {
$flag = 'stable';
}
$default_flag = defined( 'WC_BLOCKS_IS_FEATURE_PLUGIN' ) ? '2' : '1';
$allowed_flags = [ '1', '2', '3' ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we use strings here instead of numbers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment variables and ini values are treated as strings, to avoid casting and recasting things all over the place, I assume everything is a string and when I define the flag I turn it to an int.


if ( file_exists( __DIR__ . '/../../blocks.ini' ) ) {
$woo_options = parse_ini_file( __DIR__ . '/../../blocks.ini' );
$flag = is_array( $woo_options ) && in_array( $woo_options['woocommerce_blocks_phase'], $allowed_flags, true ) ? $woo_options['woocommerce_blocks_phase'] : $default_flag;
} else {
$flag = $default_flag;
}
define( 'WOOCOMMERCE_BLOCKS_PHASE', $flag );

define( 'WOOCOMMERCE_BLOCKS_PHASE', intval( $flag ) );
}

/**
Expand Down
Loading