Core Tech

Core Tech

PMC's core tech consists of several plugins, design systems, and other features.

Scripts

The pmc-plugins repo contains a scripts directory that contains a centralized build script along with some configurations available to any plugin inside the pmc-plugins monorepo.

It is also recommended that an .npmrc and .nvmrc are added and/or the "engines" set in the package.json:

"engines": {
  "node": ">=16",
  "npm": ">=8"
},

Minimum Requirements

To enable this build process for a plugin there are a few dependencies required, at minimum. Install those with:

"devDependencies": {
  "@babel/core",
  "@babel/eslint-parser",
  "@babel/preset-env",
  "@babel/preset-react",
  "@penskemediacorp/stylelint-config",
  "@wordpress/babel-preset-default",
  "@wordpress/eslint-plugin",
  "@wordpress/jest-preset-default",
  "@wordpress/scripts",
  "babel-loader",
  "eslint",
  "eslint-plugin-jsdoc",
  "eslint-plugin-json-schema-validator",
  "eslint-plugin-jsonc",
  "eslint-plugin-react",
  "husky",
  "jest",
  "lint-staged",
  "prettier"
},
"dependencies": {
		"postcss",
		"postcss-scss",
}

Build Script

The build script scripts/build-package.js leverages the @wordpress/scripts (opens in a new tab) scripts, but provides a custom script middleware that allows us to target specific plugins with the script effectively centralizing our built process for all plugins in the pmc-plugins monorepo.

Usage

When adding script support for a plugin you can add the following scripts to your package.json which provides an excellent starting point compatible with WordPress, the PMC GitHub pipelines, and allows us to add assets for our scripts package as well as the plugin. For example we'd replace PLUGIN-FOLDER-SLUG for pmc-gutenberg in the context of that plugin:

"scripts": {
  "prod": "npm run build PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "start": "npm run start PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "format": "npm run format PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "format:style": "npm run format-style PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "test": "npm run assess PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "test:watch": "npm run assess-watch PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "test:update": "npm run assess-update PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "lint:js": "npm run lint PLUGIN-FOLDER-SLUG --prefix ../scripts/",
  "lint:style": "npm run lint-style PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "update": "npm run update PLUGIN-FOLDER-SLUG --prefix ../scripts",
  "postinstall": "npm ci --prefix ../scripts"
},

Effectively the format is npm run <type> <plugin-folder> --prefix ../scripts where the type is the build, start, assess (more about this below), lint, format, or update. Descriptions of how these function can be found in the core docs @wordpress/scripts (opens in a new tab) but the nuance and general descriptions are below.

Build

Bundles all .js, .jsx, .ts, or .tsx files for production. Will also build according to block.json files in the context of blocks. By default looks for entrypoints in the /src directory.

Start

This runs the dev server which watches files for changes and rebuilds, unminified. No hot module reloading is currently available.

Format

This command formats all .js, .jsx, .ts, or .tsx files. The subcommand format-style will format .scss files.

Assess

This command runs the jest test suite. With the PMC GitHub workflows test is run on all package.json scripts with a related diff. As a result, the command in our build is assess but correlates to the npm run test command referenced in the @wordpress/scripts (opens in a new tab) docs.

Subcommands assess-watch and assess-update can be run to watch tests for changes or update snapshot tests respectively.

Lint

This command lints all .js, .jsx, .ts, or .tsx files as well as .json, .jsonc, and .json5 files in the specified plugin. The subcommand lint-style will lint .scss files.

Update

This command will update the wordpress packages for the given plugin using the packages-update command provided by @wordpress/scripts (opens in a new tab).

Post Install

After the npm i or npm install command is run in the plugin, the post install command is run which does the same inside the pmc-plugins/scripts directory ensuring that all packages are available for the build process. This script is required both for local development but also for the pipeline to install dependencies appropriately.

Adding Custom Args

The build and start commands support custom args that @wordpress/scripts (opens in a new tab) supports. For example, adding the following build script would add an entry point src/index.js and output the file, after build, in the build directory. This can be helpful when building one-off files without needing to add a custom webpack

{
  		"build:custom": "npm run build PLUGIN-NAME src/index.js --output-path=build --prefix ../scripts"
}

NOTE: There is a gotcha with this approach that in order to correctly build all assets for blocks and custom entry points we need to add the custom script as a separate script rather than just running the custom script as build. Hypothetically adding the custom entry/output paths should build the custom AND the default, but in practice not all files are generated as expected. Our workaround is to disable the CleanWebpackPlugin.

ESLint

An .eslintrc config file lives in the scripts/config directory which can be used by any plugin by adding an .eslintrc file in the plugin and extending this config. For example:

{
	"extends": "../scripts/config/.eslintrc"
}

The eslint config extends the WordPress standard config but provides additional rules that places focus on documentation, prop type validations, and other validation-related configurations with little to no additional features related to code formatting.

Stylelint

Similarly there is a .stylelintrc.json config that lives in the scripts/config directory which can be extended for brands.

{
	"extends": "../scripts/config/.stylelintrc.json"
}

This extends the @penskemediacorp/stylelint-config package.

Babel Config

Similarly still, there is a babel.config.json config that lives in the scripts/config directory which can be extended for brands.

{
	"extends": "../scripts/config/babel.config.json"
}

Webpack Config

The webpack config available in the scripts/config directory extends the @wordpress/scripts package which provides a lot of flexibility out of the box for building, development mode, linting, formatting, and testing. That can be read about here (opens in a new tab).

The config uses the defaults that the wp-scripts package uses, but will look for a webpack.config.js file in the package define by the build scripts and merge that with the default script. This can be helpful for defining custom entry or output points or adding special plugin handling for a specific plugin. By default it will look for block.json or index.js files in the /src directory.

TODO Items

  • We should find a way to centralize the @wordpress/ dependencies so that we can ensure that all block features are on the same versions.
  • Automating the package.json through a custom script would be helpful for easily setting up new plugins.