Skip to content

Instantly share code, notes, and snippets.

@mgratch
Last active February 1, 2023 22:47
Show Gist options
  • Save mgratch/b3c91de9680e92d9b0dcc81aa7bc44ac to your computer and use it in GitHub Desktop.
Save mgratch/b3c91de9680e92d9b0dcc81aa7bc44ac to your computer and use it in GitHub Desktop.
Webpack setup at their project root that: Builds theme assets. Builds all blocks
{
"name": "client-plugins-and-theme",
"version": "1.0.0",
"description": "A Client Project with custom Plugins and theme.",
"main": "index.js",
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack --watch",
"eslint": "eslint \"src/**/*.{js,jsx}\" --quiet",
"eslint:fix": "eslint \"src/**/_.{js,jsx}\" --quiet --fix",
"format": "prettier --write \"src/**/*.{js,jsx,scss}\"",
"stylelint": "stylelint \"src/**/*.{css,scss}\"",
"stylelint:fix": "stylelint \"wp-content/themes/client-theme/src/**/*.{css,scss}\" --fix",
"wp-pot": "wp-pot --src '_.php' --dest-file 'languages/_s.pot' --domain '_s'"
},
"repository": {
"type": "git",
"url": "git+https://bitbucket.org/causelabs/artjewelryforum.org.git"
},
"keywords": [
"wordpress",
"webpack"
],
"author": "",
"license": "ISC",
"homepage": "https://marcgratch.com/",
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/eslint-parser": "^7.17.0",
"@babel/preset-env": "^7.18.0",
"@fancyapps/ui": "^4.0.31",
"@fullcalendar/core": "^6.0.2",
"@fullcalendar/daygrid": "^6.0.2",
"@fullcalendar/list": "^6.0.2",
"@fullcalendar/react": "^6.0.2",
"@fullcalendar/timegrid": "^6.0.2",
"@wordpress/prettier-config": "^2.5.0",
"@wordpress/scripts": "^23.1.0",
"@wordpress/stylelint-config": "^20.0.2",
"autoprefixer": "^10.4.7",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "^8.15.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"file-loader": "^6.2.0",
"img-loader": "^4.0.0",
"lodash.debounce": "^4.0.8",
"mini-css-extract-plugin": "^2.6.0",
"node-sass": "^7.0.1",
"postcss-combine-media-query": "^1.0.1",
"postcss-import": "^14.1.0",
"postcss-loader": "^7.0.0",
"precss": "^4.0.0",
"prettier": "^2.6.2",
"react-slick": "^0.29.0",
"sass-loader": "^13.0.0",
"style-loader": "^3.3.1",
"stylelint": "^14.8.2",
"stylelint-config-recommended-scss": "^6.0.0",
"stylelint-order": "^5.0.0",
"stylelint-scss": "^4.2.0",
"stylelint-webpack-plugin": "^3.2.0",
"svg-sprite-loader": "^6.0.11",
"svgo": "^2.8.0",
"svgo-loader": "^3.0.0",
"terser-webpack-plugin": "^5.3.1",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"wp-pot-cli": "^1.5.0"
},
"dependencies": {
"react-select": "^5.4.0"
}
}
const path = require('path'),
fs = require('fs'),
glob = require('glob'),
MiniCssExtractPlugin = require('mini-css-extract-plugin'),
TerserPlugin = require('terser-webpack-plugin'),
OptimizeCssAssetsPlugin = require('css-minimizer-webpack-plugin'),
StyleLintPlugin = require('stylelint-webpack-plugin'),
SpriteLoaderPlugin = require('svg-sprite-loader/plugin'),
wpScriptsConfig = require('@wordpress/scripts/config/webpack.config.js'),
copyWebpackPatterns = process.env.WP_COPY_PHP_FILES_TO_DIST
? '**/{block.json,*.php}'
: '**/block.json';
// Figure out which plugins can be compiled.
const pluginDirs = glob
.sync('wp-content/plugins/client-*/', { absolute: true })
.filter((dir) => fs.existsSync(path.join(dir, 'src/index.js')));
const pluginEntryPoints = pluginDirs.reduce((acc, dir) => {
const basename = path.basename(dir);
acc[basename] = [`./wp-content/plugins/${basename}/src/index.js`];
if (fs.existsSync(path.join(dir, 'src/frontend.js'))) {
acc[basename + '__frontend'] = [
`./wp-content/plugins/${basename}/src/frontend.js`,
];
}
return acc;
}, {});
// Override the default wordpress webpack config which expects to be run from
// within each plugin's directory.
wpScriptsConfig.name = 'plugins';
wpScriptsConfig.entry = pluginEntryPoints;
wpScriptsConfig.output = {
path: process.cwd(),
filename: (pathData) => {
const name = pathData.chunk.name;
const formattedName =
name.indexOf('__frontend') !== -1 ? 'frontend' : 'index';
const pluginDir = name.replace('__frontend', '');
return `wp-content/plugins/${pluginDir}/build/${formattedName}.js`;
},
};
wpScriptsConfig.optimization.splitChunks.cacheGroups.style.name = (
_,
chunks,
cacheGroupKey
) => {
const chunkName = chunks[0].name;
return `${chunkName}:style-index`;
};
// Alter default plugin config.
const plugins = [];
wpScriptsConfig.plugins.forEach((plugin) => {
switch (plugin.constructor.name) {
case 'CleanWebpackPlugin':
// Ignore clean up plugin for now.
// TODO: Tweak this plugin so it doesn't wipe the whole project after
// running :)
return;
case 'MiniCssExtractPlugin':
plugin.options.filename = function ({ chunk }) {
const segments = chunk.name.split(':');
const dir = segments[0];
const filename = segments[1] || 'index';
const formattedFilename =
dir.indexOf('__frontend') !== -1 ? 'frontend' : filename;
const formattedDir = dir.replace('__frontend', '');
return `wp-content/plugins/${formattedDir}/build/${formattedFilename}.css`;
};
break;
case 'CopyPlugin':
plugin.patterns = pluginDirs.map((dir) => ({
from: copyWebpackPatterns,
to: dir + '/build',
context: dir + '/src',
}));
break;
}
// Push new plugin config.
plugins.push(plugin);
});
wpScriptsConfig.plugins = plugins;
module.exports = [
wpScriptsConfig,
{
context: __dirname,
entry: glob
.sync('./wp-content/themes/client-theme/src{/,/js/}**.js')
.reduce(function (obj, el) {
obj[path.parse(el).name] = el;
return obj;
}, {}),
output: {
path: path.resolve(__dirname),
filename: 'wp-content/themes/client-theme/public/js/[name].min.js',
},
mode: 'development',
devtool: 'source-map',
module: {
rules: [
{
enforce: 'pre',
test: /\.jsx$/,
include: [
path.resolve(__dirname, 'wp-content/themes/client-theme'),
],
exclude: [
path.resolve(__dirname, 'node_modules'),
path.resolve(
__dirname,
'wp-content/themes/client-theme/public'
),
],
loader: 'eslint-loader',
},
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, 'wp-content/themes/client-theme'),
],
exclude: [
path.resolve(__dirname, 'node_modules'),
path.resolve(
__dirname,
'wp-content/themes/client-theme/public'
),
path.resolve(__dirname, 'wp-content/plugins'),
],
loader: 'babel-loader',
},
{
test: /\.s?css$/,
include: [
path.resolve(__dirname, 'wp-content/themes/client-theme'),
],
exclude: [
path.resolve(
__dirname,
'wp-content/themes/client-theme/public'
),
],
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.svg$/,
include: [
path.resolve(__dirname, 'wp-content/themes/client-theme'),
],
exclude: [
path.resolve(
__dirname,
'wp-content/themes/client-theme/public'
),
],
loader: 'svg-sprite-loader',
options: {
extract: true,
spriteFilename: 'svg-defs.svg',
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
publicPath:
'wp-content/themes/client-theme/assets/fonts/',
filename: '[name][ext]',
outputPath:
'wp-content/themes/client-theme/public/fonts/',
},
},
{
test: /\.(png|jpe?g|gif)$/,
generator: {
publicPath:
'wp-content/themes/client-theme/assets/images/',
filename: '[name][ext]',
outputPath:
'wp-content/themes/client-theme/public/images/',
},
use: [
{
loader: 'url-loader',
options: {},
},
],
},
],
},
plugins: [
new StyleLintPlugin({
files: ['wp-content/themes/client-theme'],
exclude: [
'wp-content/themes/client-theme/assets',
'wp-content/themes/client-theme/public',
],
}),
new MiniCssExtractPlugin({
filename: ({ chunk }) =>
`wp-content/themes/client-theme/public/css/${chunk.name}.css`,
}),
new SpriteLoaderPlugin(),
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin(), new OptimizeCssAssetsPlugin()],
splitChunks: {
cacheGroups: {
style: {
type: 'css/mini-extract',
test: /[\\/]style(\.module)?\.(sc|sa|c)ss$/,
chunks: 'all',
enforce: true,
name( _, chunks, cacheGroupKey ) {
const chunkName = chunks[ 0 ].name;
return `${ path.dirname(
chunkName
) }/${ cacheGroupKey }-${ path.basename( chunkName ) }`;
},
},
editor: {
type: 'css/mini-extract',
test: /[\\/]editor(\.module)?\.(sc|sa|c)ss$/,
chunks: 'all',
enforce: true,
name( _, chunks, cacheGroupKey ) {
const chunkName = chunks[ 0 ].name;
return `${ path.dirname(
chunkName
) }/${ cacheGroupKey }-${ path.basename( chunkName ) }`;
},
},
default: false,
},
},
},
},
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment