Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: Pulling JavaScript to the frontend from a Core Block. #29537

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions packages/block-library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,63 @@ npm install @wordpress/block-library --save

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Building JavaScript for the browser

If a `frontend.js` file is present in the block's directory, this file will be built along other assets, making it available to load it from the browser.

This enables us to, for instance, load this file when the block is present on the page in several ways:

1. Using the block's `render_callback`:

```php

function render_my_block() {
$script_path = __DIR__ . '/block-name/frontend.js';

if ( file_exists( $script_path ) ) {
wp_enqueue_script(
'my_block_frontend_script',
plugins_url( 'frontend.js', $script_path ),
array(),
false,
true
);
}
}

function register_block_my_block() {
register_block_type_from_metadata(
__DIR__ . '/block-name',
array(
'render_callback' => 'render_my_block',
)
);
}


add_action( 'init', 'register_block_my_block' );
```

2. Using the `render_block` filter:

```php
function render_my_block() {
$script_path = __DIR__ . '/block-name/frontend.js';

if ( file_exists( $script_path ) ) {
wp_enqueue_script(
'my_block_frontend_script',
plugins_url( 'frontend.js', $script_path ),
array(),
false,
true
);
}
}

apply_filter( 'render_block', 'render_my_block' );
```

## API

<!-- START TOKEN(Autogenerated API docs) -->
Expand Down
96 changes: 56 additions & 40 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ const { DefinePlugin } = require( 'webpack' );
const CopyWebpackPlugin = require( 'copy-webpack-plugin' );
const TerserPlugin = require( 'terser-webpack-plugin' );
const postcss = require( 'postcss' );
const { get, escapeRegExp, compact } = require( 'lodash' );
const { basename, sep } = require( 'path' );
const { escapeRegExp, compact } = require( 'lodash' );
const { sep } = require( 'path' );
const fastGlob = require( 'fast-glob' );

/**
* WordPress dependencies
Expand Down Expand Up @@ -64,6 +65,34 @@ const stylesTransform = ( content ) => {
return content;
};

const blockNameRegex = new RegExp( /(?<=src\/).*(?=(\/frontend))/g );

const createEntrypoints = () => {
const scriptPaths = fastGlob.sync(
'./packages/block-library/src/**/frontend.js',
{
ignore: [ '**/build*/**' ],
}
);

const scriptEntries = scriptPaths.reduce( ( entries, scriptPath ) => {
const [ blockName ] = scriptPath.match( blockNameRegex ) || [];

return {
...entries,
[ blockName ]: scriptPath,
};
}, {} );

const packageEntries = gutenbergPackages.reduce( ( memo, packageName ) => {
memo[ packageName ] = `./packages/${ packageName }`;

return memo;
}, {} );

return { ...packageEntries, ...scriptEntries };
};

module.exports = {
optimization: {
// Only concatenate modules in production, when not analyzing bundles.
Expand All @@ -90,16 +119,22 @@ module.exports = {
],
},
mode,
entry: gutenbergPackages.reduce( ( memo, packageName ) => {
const name = camelCaseDash( packageName );
memo[ name ] = `./packages/${ packageName }`;
return memo;
}, {} ),
entry: createEntrypoints(),
output: {
devtoolNamespace: 'wp',
filename: './build/[basename]/index.js',
filename: ( data ) => {
const { chunk } = data;
const { entryModule } = chunk;
const { rawRequest } = entryModule;

if ( rawRequest && rawRequest.includes( '/frontend.js' ) ) {
return `./build/block-library/blocks/[name]/frontend.js`;
}

return './build/[name]/index.js';
},
path: __dirname,
library: [ 'wp', '[name]' ],
library: [ 'wp', '[camelName]' ],
libraryTarget: 'window',
},
module: {
Expand Down Expand Up @@ -135,39 +170,20 @@ module.exports = {
),
} ),
new CustomTemplatedPathPlugin( {
basename( path, data ) {
let rawRequest;

const entryModule = get( data, [ 'chunk', 'entryModule' ], {} );
switch ( entryModule.type ) {
case 'javascript/auto':
rawRequest = entryModule.rawRequest;
break;

case 'javascript/esm':
rawRequest = entryModule.rootModule.rawRequest;
break;
}

if ( rawRequest ) {
return basename( rawRequest );
}

return path;
vcanales marked this conversation as resolved.
Show resolved Hide resolved
camelName( path, data ) {
return camelCaseDash( data.chunk.name );
},
} ),
new LibraryExportDefaultPlugin(
[
'api-fetch',
'deprecated',
'dom-ready',
'redux-routine',
'token-list',
'server-side-render',
'shortcode',
'warning',
].map( camelCaseDash )
),
new LibraryExportDefaultPlugin( [
'api-fetch',
'deprecated',
'dom-ready',
'redux-routine',
'token-list',
'server-side-render',
'shortcode',
'warning',
] ),
new CopyWebpackPlugin(
gutenbergPackages.map( ( packageName ) => ( {
from: `./packages/${ packageName }/build-style/*.css`,
Expand Down