@plaudit/webpack-extensions 3.17.0 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.19.0] - 2026-08-18
9
+ ### Added
10
+ - Automatic sync of WordPress's bundled packages list
11
+ - This comes from version `2.98.0`
12
+
13
+ ## [3.18.0] - 2026-08-18
14
+ ### Added
15
+ - David's improvements to build pipeline efficiency (Credit: David)
16
+ - This comes from version `2.97.0`
17
+ - Support for David's `@plaudit/dev-webpack-plugin` (Credit: David)
18
+ - This comes from version `2.97.0`
19
+
20
+ ### Changed
21
+ - To Webpack's standard plugin interface (`WebpackPluginInstance`)
22
+ - This comes from version `2.97.0`
23
+
24
+ ### Removed
25
+ - Browsersync and its tests (Credit: David)
26
+ - This comes from version `2.97.0`
27
+
8
28
  ## [3.17.0] - 2026-08-18
9
29
  ### Added
10
30
  - A port of WordPress's Dependency Extraction Webpack Plugin because they keep breaking it
@@ -260,6 +280,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
260
280
  - Legacy PostCSS features that have been integrated into modern CSS
261
281
  - `@extends` support
262
282
 
283
+ ## [2.98.0] - 2026-08-18
284
+ ### Added
285
+ - Automatic sync of WordPress's bundled packages list
286
+
287
+ ## [2.97.0] - 2026-08-18
288
+ ### Added
289
+ - David's improvements to build pipeline efficiency
290
+ - Support for David's `@plaudit/dev-webpack-plugin`
291
+
292
+ ### Changed
293
+ - To Webpack's standard plugin interface (`WebpackPluginInstance`)
294
+
295
+ ### Removed
296
+ - Browsersync tests
297
+
263
298
  ## [2.96.3] - 2026-08-11
264
299
  ### Added
265
300
  - A few more validation checks
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Plaudit Webpack Extensions
2
- A webpack configuration and plugin suite designed specifically for WordPress development workflows. This package extends `@wordpress/scripts` with custom webpack plugins, PostCSS configurations, and build optimizations tailored for Plaudit's WordPress projects. It includes specialized handling for Gutenberg blocks, asset management, internationalization (WPML), and development tooling like BrowserSync integration.
2
+ A webpack configuration and plugin suite designed specifically for WordPress development workflows. This package extends `@wordpress/scripts` with custom webpack plugins, PostCSS configurations, and build optimizations tailored for Plaudit's WordPress projects. It includes specialized handling for Gutenberg blocks, asset management, internationalization (WPML), and a same-origin CSS-inject / live-reload client for `wp-scripts start`.
3
3
 
4
4
  # Requirements
5
5
  - All block- and extension-related capabilities require that the `plaudit/plaudit-common` composer library be installed.
@@ -23,7 +23,27 @@ This suite generates loader code that uses the most efficient mechanisms availab
23
23
  The same file structure (both in the webpack.config.js file and the actual directory tree) can be used in plugins and themes.
24
24
 
25
25
  # Usage
26
- Check out the [User Guide](USER-GUIDE.md) file.
26
+ Config, entry types, and handles: [User Guide](USER-GUIDE.md).
27
+
28
+ ## `dist` vs `dist-dev`
29
+
30
+ With the unified loader (site `standard`), `outputDir` is `dist`. When `SERVER_MODE` is `development` (the default if unset on the host) and `omitDistDev` is off, webpack writes **`dist-dev`**. WordPress in development loads that folder via `dist/unified-loader.php` when `dist-dev/unified-loader.php` exists. Production WordPress always uses **`dist`**.
31
+
32
+ `SERVER_MODE` chooses the folder. The compiler (`mode`, minify, webpack cache) is always production for `dist`. For `dist-dev` it follows `NODE_ENV`: `wp-scripts start` is development (no minify, cache on); `wp-scripts build` is production (minify, cache off) still written to `dist-dev`.
33
+
34
+ `dev-reload.js` / overlay run only for `pnpm run dev` (`BROWSER_SYNC` + watch) and only under `dist-dev`. Pass `--no-dev-reload` after `--` (or `DEV_RELOAD=0`) to skip the overlay and live reload: `pnpm run dev -- --no-dev-reload`. Docker still starts and the browser still opens. The `--` is required so webpack-cli does not treat the flag as an unknown option.
35
+
36
+ | Command | Folder | Compiler | Overlay |
37
+ |-----------------------------------------|------------|------------------------------------------------------------------|---------|
38
+ | `pnpm run dev` | `dist-dev` | development (no minify, cache on) | yes |
39
+ | `pnpm run dev -- --no-dev-reload` | `dist-dev` | development (no minify, cache on) | no |
40
+ | `pnpm run watch` | `dist-dev` | development (no minify, cache on) | no |
41
+ | `pnpm run build` | `dist-dev` | production (minify, cache off) | no |
42
+ | `SERVER_MODE=production pnpm run build` | `dist` | same production compiler as `pnpm run build` (minify, cache off) | no |
43
+
44
+ The last row is the same compile as a local `build`; only the folder changes. That is what ships: `@plaudit/toolbox` (`toolbox init`) installs a **pre-commit** hook that runs `pnpm … build` with `SERVER_MODE=production` and stages `wp-content/**/dist/**`. A plain `pnpm run build` on your machine does **not** update `dist` unless you set `SERVER_MODE` yourself. `SKIP_BUILD=1` skips the hook build.
45
+
46
+ See [Plaudit - Dev Webpack Plugin](https://github.com/plaudit/dev-webpack-plugin#readme) for more details
27
47
 
28
48
  # Development
29
49
 
package/USER-GUIDE.md CHANGED
@@ -190,11 +190,13 @@ This file automatically:
190
190
  - Sets up blocks and extensions
191
191
 
192
192
  ### 4. Run Build Commands
193
- While you *can* manually run these commands, using `theapp pack dev/watch/build` is preferred
193
+ While you *can* manually run these commands, using `theapp pack dev/watch/build` is preferred.
194
+
195
+ Typical theme/plugin scripts are `watch`, `dev`, and `build`. Which folder they write (`dist` vs `dist-dev`) and whether the compiler minifies is in the package [README](README.md#dist-vs-dist-dev) — a local `pnpm run build` is a production compile into `dist-dev`, not into `dist`.
194
196
 
195
197
  ```bash
196
- pnpm run watch # Development mode (watches for changes)
197
- pnpm run build # Production build
198
+ pnpm run watch # Watch; writes dist-dev
199
+ pnpm run build # One-shot production compile into dist-dev
198
200
  ```
199
201
 
200
202
  ---
@@ -1,7 +1,7 @@
1
- import { Compilation, Compiler } from "webpack";
1
+ import { Compilation, Compiler, type WebpackPluginInstance } from "webpack";
2
2
  import { PseudoSemaphore } from "../utils/pseduo-semaphore";
3
3
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
4
- import { type ParsedAssetJsonProvider, WebpackPlugin } from "../shared";
4
+ import { type ParsedAssetJsonProvider } from "../shared";
5
5
  type TapWithAssetsJsonOptions = {
6
6
  name?: string;
7
7
  stage?: (typeof Compilation.PROCESS_ASSETS_STAGE_REPORT) | (typeof Compilation.PROCESS_ASSETS_STAGE_ANALYSE);
@@ -9,7 +9,7 @@ type TapWithAssetsJsonOptions = {
9
9
  };
10
10
  type TapWithAssetsJsonFn = Parameters<Compilation['hooks']['processAssets']['tapPromise']>[1];
11
11
  type TapWithParsedAssetsJsonFn = (parsedAssetJsonProvider: ParsedAssetJsonProvider, assets: Parameters<TapWithAssetsJsonFn>[0]) => Promise<void> | void;
12
- export declare abstract class AbstractBiPhasicGroupPlugin implements WebpackPlugin {
12
+ export declare abstract class AbstractBiPhasicGroupPlugin implements WebpackPluginInstance {
13
13
  protected readonly config: VerifiedPlauditWordpressWebpackConfig;
14
14
  readonly group: string;
15
15
  private readonly semaphores;
@@ -1,5 +1,4 @@
1
- import type { Compiler } from "webpack";
2
- import type { WebpackPlugin } from "../shared";
3
- export declare class MiniCSSExtractPluginErrorCleaner implements WebpackPlugin {
1
+ import type { Compiler, WebpackPluginInstance } from "webpack";
2
+ export declare class MiniCSSExtractPluginErrorCleaner implements WebpackPluginInstance {
4
3
  apply(compiler: Compiler): void;
5
4
  }
@@ -1,5 +1,4 @@
1
- import type { Compiler } from "webpack";
2
- import type { WebpackPlugin } from "../shared";
3
- export declare class PackageConfigSanityChecker implements WebpackPlugin {
1
+ import type { Compiler, WebpackPluginInstance } from "webpack";
2
+ export declare class PackageConfigSanityChecker implements WebpackPluginInstance {
4
3
  apply(compiler: Compiler): void;
5
4
  }
@@ -1,7 +1,6 @@
1
1
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
2
- import type { Compiler } from "webpack";
3
- import type { WebpackPlugin } from "../shared";
4
- export declare class VariablesJSMonitorPlugin implements WebpackPlugin {
2
+ import type { Compiler, WebpackPluginInstance } from "webpack";
3
+ export declare class VariablesJSMonitorPlugin implements WebpackPluginInstance {
5
4
  private readonly config;
6
5
  constructor(config: VerifiedPlauditWordpressWebpackConfig);
7
6
  apply(compiler: Compiler): void;
@@ -1,7 +1,6 @@
1
- import { type WebpackPlugin } from "../shared";
2
1
  import { AbstractBiPhasicGroupAndEntryPlugin } from "./AbstractBiPhasicGroupAndEntryPlugin";
3
- import { type Compiler } from "webpack";
4
- export declare class WPMLConfigBuilderPlugin implements WebpackPlugin {
2
+ import { type Compiler, type WebpackPluginInstance } from "webpack";
3
+ export declare class WPMLConfigBuilderPlugin implements WebpackPluginInstance {
5
4
  private readonly destDir;
6
5
  private readonly referencePlugin;
7
6
  private static jsdomInstance?;
package/dist/shared.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PHPFile, PHPWriter } from "@plaudit/php-writer";
2
2
  import { HereOrNowDoc } from "@plaudit/php-writer/expressions";
3
3
  import type { Options as PostcssFunctionsOptions } from "postcss-functions";
4
- import { type AssetInfo, type Compilation, type Configuration, type Entrypoint, WebpackError, type Compiler } from "webpack";
4
+ import { type AssetInfo, type Compilation, type Configuration, type Entrypoint, WebpackError } from "webpack";
5
5
  import { SourceType } from "./utils/entrypoint-resolution-logic";
6
6
  import type { NormalizedEnqueuingControlFlags } from "./utils/path-query-and-related-helpers";
7
7
  export * from "./utils/entrypoint-resolution-logic";
@@ -105,9 +105,6 @@ export declare function constantEntries<K extends string, V>(object: {
105
105
  [k in K]: V;
106
106
  }): [K, V][];
107
107
  export declare function determineCurrentSourceType(dest: string | AdvancedOutputConfig, srcIsDirectory: boolean): SourceType;
108
- export interface WebpackPlugin {
109
- apply(compiler: Compiler): void;
110
- }
111
108
  export type ObjectIndividualExternalDepConfig = {
112
109
  import?: string | [string, ...string[]];
113
110
  handle: string;
@@ -161,31 +158,38 @@ export type PlauditWordpressWebpackConfig = {
161
158
  targetNamespace?: string;
162
159
  useBlockSupportsAsThemeJsonDefaults?: boolean;
163
160
  };
161
+ /** Unified-loader watch output: `dist` → `dist-dev` when SERVER_MODE is development. */
162
+ export declare function shouldWriteDistDev(config: Pick<PlauditWordpressWebpackConfig, 'outputDir' | 'useUnifiedLoader' | 'omitDistDev'>): boolean;
163
+ /**
164
+ * This MUST be kept in sync with the copy in @plaudit/dev-webpack-plugin
165
+ * @returns true for `dist-dev` (or any `*-dev` output folder produced by {@link shouldWriteDistDev}).
166
+ */
167
+ export declare function isDistDevOutputPath(outputPath: string): boolean;
164
168
  export declare function applyStandards(config: PlauditWordpressWebpackConfig): {
165
- readonly standard?: "2026-03-13";
169
+ readonly standard?: '2026-03-13';
166
170
  readonly standaloneBlocks?: boolean;
167
171
  readonly variables?: Record<string, any>;
168
172
  readonly verbose?: boolean;
169
173
  readonly src?: string[] | SourcesObject;
170
- readonly stats?: Configuration["stats"];
174
+ readonly stats?: Configuration['stats'];
171
175
  readonly postcss?: {
172
- functions?: (variables: (name: string) => unknown) => PostcssFunctionsOptions["functions"];
176
+ functions?: (variables: (name: string) => unknown) => PostcssFunctionsOptions['functions'];
173
177
  };
174
178
  readonly externals?: Externals;
175
179
  readonly assumeGlobalizedPlauditLibraries?: boolean;
176
- useWebpackResourceFiltering?: boolean;
177
- outputDir?: string;
178
- extensionsVersion?: 1 | 2 | 3;
179
180
  readonly targetHandlePrefix?: string;
180
- plainEntrypointsVersion?: 1 | 2;
181
- srcDir?: string;
182
181
  readonly srcPrefixes?: string[];
183
- useUnifiedLoader?: boolean;
184
182
  readonly includePostInitFallback?: boolean;
185
183
  readonly omitDistDev?: boolean;
186
- onlyRunPostCSSOnPCSS?: boolean;
187
184
  readonly targetNamespace?: string;
188
185
  readonly useBlockSupportsAsThemeJsonDefaults?: boolean;
186
+ useWebpackResourceFiltering?: boolean | undefined;
187
+ extensionsVersion?: 1 | 2 | 3 | undefined;
188
+ plainEntrypointsVersion?: 1 | 2 | undefined;
189
+ srcDir?: string | undefined;
190
+ outputDir?: string | undefined;
191
+ useUnifiedLoader?: boolean | undefined;
192
+ onlyRunPostCSSOnPCSS?: boolean | undefined;
189
193
  };
190
194
  export declare function resolveStandard(standard: PlauditWordpressWebpackConfig['standard']): {
191
195
  readonly useWebpackResourceFiltering: true;
@@ -228,7 +232,7 @@ export declare const scriptExtension: RegExp;
228
232
  export declare const scriptWithoutModuleExtension: RegExp;
229
233
  export declare const scriptWithModuleExtension: RegExp;
230
234
  export declare const styleExtension: RegExp;
231
- export declare function scriptOrStyleTest(entryPath: string, scriptExtension: RegExp): "script" | "style" | "";
235
+ export declare function scriptOrStyleTest(entryPath: string, scriptExtension: RegExp): "" | "script" | "style";
232
236
  export declare function isStyleField(field: string): field is 'style' | 'viewStyle' | 'editorStyle';
233
237
  export declare function isScriptModuleField(field: string): field is 'viewScriptModule';
234
238
  export declare function mergeModuleDependencyArrays(a: WPModuleDependency[] | undefined, b: WPModuleDependency[] | undefined): WPModuleDependency[] | undefined;
@@ -240,8 +244,6 @@ type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N
240
244
  export declare function arrayIsLength<T, N extends number>(arr: T[] | null | undefined, length: N): arr is TupleOf<T, N>;
241
245
  export declare function kebabCase(value: string): string;
242
246
  export declare function camelCaseForPHPLabels(value: string): string;
243
- export declare function loadEnvFile(filePath: string): Promise<Record<string, string>>;
244
- export declare function parseEnvFile(contents: string): Record<string, string>;
245
247
  export declare function newCleanWebpackError(error: string | ConstructorParameters<typeof WebpackError>): WebpackError;
246
248
  export declare function newWebpackErrorForFile(error: string | ConstructorParameters<typeof WebpackError>, file: string): WebpackError;
247
249
  /**
package/dist/shared.js CHANGED
@@ -25,6 +25,8 @@ exports.isNormalizedUsageLocations = isNormalizedUsageLocations;
25
25
  exports.constantKeys = constantKeys;
26
26
  exports.constantEntries = constantEntries;
27
27
  exports.determineCurrentSourceType = determineCurrentSourceType;
28
+ exports.shouldWriteDistDev = shouldWriteDistDev;
29
+ exports.isDistDevOutputPath = isDistDevOutputPath;
28
30
  exports.applyStandards = applyStandards;
29
31
  exports.resolveStandard = resolveStandard;
30
32
  exports.convertUsageLocationsHandleToEmittableHandle = convertUsageLocationsHandleToEmittableHandle;
@@ -40,8 +42,6 @@ exports.hasAtLeastOneItem = hasAtLeastOneItem;
40
42
  exports.arrayIsLength = arrayIsLength;
41
43
  exports.kebabCase = kebabCase;
42
44
  exports.camelCaseForPHPLabels = camelCaseForPHPLabels;
43
- exports.loadEnvFile = loadEnvFile;
44
- exports.parseEnvFile = parseEnvFile;
45
45
  exports.newCleanWebpackError = newCleanWebpackError;
46
46
  exports.newWebpackErrorForFile = newWebpackErrorForFile;
47
47
  exports.emitResolveBaseUriFunction = emitResolveBaseUriFunction;
@@ -57,7 +57,6 @@ exports.instanceOfNodeError = instanceOfNodeError;
57
57
  exports.shouldBeSkipped = shouldBeSkipped;
58
58
  const node_crypto_1 = require("node:crypto");
59
59
  const node_fs_1 = require("node:fs");
60
- const promises_1 = require("node:fs/promises");
61
60
  const node_path_1 = __importDefault(require("node:path"));
62
61
  const php_writer_1 = require("@plaudit/php-writer");
63
62
  const expressions_1 = require("@plaudit/php-writer/expressions");
@@ -116,6 +115,17 @@ function determineCurrentSourceType(dest, srcIsDirectory) {
116
115
  return dest.directoryLayout;
117
116
  }
118
117
  }
118
+ /** Unified-loader watch output: `dist` → `dist-dev` when SERVER_MODE is development. */
119
+ function shouldWriteDistDev(config) {
120
+ return !!(config.outputDir && config.useUnifiedLoader && !config.omitDistDev && (process.env['SERVER_MODE'] ?? 'development') === 'development');
121
+ }
122
+ /**
123
+ * This MUST be kept in sync with the copy in @plaudit/dev-webpack-plugin
124
+ * @returns true for `dist-dev` (or any `*-dev` output folder produced by {@link shouldWriteDistDev}).
125
+ */
126
+ function isDistDevOutputPath(outputPath) {
127
+ return node_path_1.default.basename(outputPath.replace(/[/\\]+$/, '')).endsWith('-dev');
128
+ }
119
129
  function applyStandards(config) {
120
130
  switch (config.standard) {
121
131
  case '2026-03-13':
@@ -251,17 +261,6 @@ function camelCaseForPHPLabels(value) {
251
261
  })
252
262
  .join("\\");
253
263
  }
254
- async function loadEnvFile(filePath) {
255
- return (0, promises_1.readFile)(filePath, 'utf-8').then(parseEnvFile, () => ({}));
256
- }
257
- function parseEnvFile(contents) {
258
- return Object.fromEntries(contents.split(/(\r?\n)+/).map(line => line.trim())
259
- .filter(line => line.length > 0 && !line.startsWith("#") && !line.startsWith("//"))
260
- .map(line => {
261
- const equalsPos = line.indexOf('=');
262
- return equalsPos === -1 ? [line, ""] : [line.substring(0, equalsPos), line.substring(equalsPos + 1)];
263
- }));
264
- }
265
264
  function newCleanWebpackError(error) {
266
265
  const res = typeof error === 'string' ? new webpack_1.WebpackError(error) : new webpack_1.WebpackError(...error);
267
266
  res.hideStack = true;
@@ -1,6 +1,6 @@
1
1
  import type { AbstractBiPhasicGroupAndEntryPlugin, EntryProvider } from "../plugins/AbstractBiPhasicGroupAndEntryPlugin";
2
2
  import type { AdditionalDependencyInjectorPlugin } from "../plugins/AdditionalDependencyInjectorPlugin";
3
- import { EntrypointFields, PlauditWordpressWebpackConfig, BlockEntrypointInfo, VerifiedAdvancedOutputConfig, MinimumViableMetadata, WebpackPlugin } from "../shared";
3
+ import { EntrypointFields, PlauditWordpressWebpackConfig, BlockEntrypointInfo, VerifiedAdvancedOutputConfig, MinimumViableMetadata } from "../shared";
4
4
  import type { Compiler, Configuration, DynamicEntryPlugin, WebpackPluginInstance } from "webpack";
5
5
  import type WebpackRemoveEmptyScriptsPlugin from "webpack-remove-empty-scripts";
6
6
  export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals' | 'standard'>> & {
@@ -8,7 +8,7 @@ export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpre
8
8
  currentVariables: Record<string, any>;
9
9
  } & Pick<PlauditWordpressWebpackConfig, 'externals'>;
10
10
  export type CommonPluginConfig = {
11
- plugins: (WebpackPluginInstance | WebpackPlugin | ((this: Compiler, compiler: Compiler) => void))[];
11
+ plugins: (WebpackPluginInstance | ((this: Compiler, compiler: Compiler) => void))[];
12
12
  removeEmptyScriptsPlugin: WebpackRemoveEmptyScriptsPlugin;
13
13
  makeAdditionalDependencyInjectorPlugin(referencePlugin: AbstractBiPhasicGroupAndEntryPlugin<any>): AdditionalDependencyInjectorPlugin;
14
14
  };
@@ -417,10 +417,12 @@ function commonMakeWebpackConfig(config, commonConfig, webpackConfig, externaliz
417
417
  outputLibrary = webpackConfig.output?.library;
418
418
  }
419
419
  const extensions = processingModules ? ['.mjsx', '.mjs', '.mtsx', '.mts', '...'] : ['.jsx', '.tsx', '.ts', '...'];
420
+ // `dist` (SERVER_MODE=production, or omitDistDev) is always minified production. `dist-dev` follows NODE_ENV so `wp-scripts start` stays fast.
421
+ const isProductionBuild = !(0, shared_1.isDistDevOutputPath)(config.outputDir) || process.env['NODE_ENV'] === 'production';
420
422
  return {
421
423
  ...webpackConfig,
422
- devtool: 'source-map',
423
- mode: "production",
424
+ devtool: isProductionBuild ? 'source-map' : (webpackConfig.devtool ?? 'eval-cheap-module-source-map'),
425
+ mode: isProductionBuild ? 'production' : 'development',
424
426
  output: {
425
427
  ...webpackConfig.output,
426
428
  path: outPath,
@@ -431,6 +433,7 @@ function commonMakeWebpackConfig(config, commonConfig, webpackConfig, externaliz
431
433
  },
432
434
  optimization: {
433
435
  ...webpackConfig.optimization,
436
+ minimize: isProductionBuild,
434
437
  splitChunks: {
435
438
  ...(webpackConfig.optimization?.splitChunks || {}),
436
439
  cacheGroups: {
@@ -450,10 +453,12 @@ function commonMakeWebpackConfig(config, commonConfig, webpackConfig, externaliz
450
453
  default: false
451
454
  }
452
455
  },
453
- minimizer: [
454
- ...(webpackConfig.optimization?.minimizer || []),
455
- new css_minimizer_webpack_plugin_1.default()
456
- ]
456
+ minimizer: isProductionBuild
457
+ ? [
458
+ ...(webpackConfig.optimization?.minimizer || []),
459
+ new css_minimizer_webpack_plugin_1.default()
460
+ ]
461
+ : webpackConfig.optimization?.minimizer
457
462
  },
458
463
  module: {
459
464
  ...webpackConfig.module,
@@ -22,9 +22,9 @@ export declare function parseLocationEncodingFilenameForBlock(filename: string,
22
22
  * @param segment
23
23
  */
24
24
  export declare function extractLocationFromPropertyEncodingFilenameSegment(segment: string): {
25
- readonly locationName: "clientView" | "clientEditor" | "blockAssets" | "admin" | "login" | "customizer" | "analytics" | "register";
25
+ readonly locationName: "admin" | "analytics" | "blockAssets" | "clientEditor" | "clientView" | "customizer" | "login" | "register";
26
26
  readonly priority: number | true;
27
27
  } | {
28
- readonly locationName: false;
29
28
  readonly priority?: undefined;
29
+ readonly locationName: false;
30
30
  };
@@ -1,4 +1,4 @@
1
- import LegacyDependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
1
+ import type LegacyDependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
2
2
  import { Compilation, Compiler, Module, type TemplatePath } from "webpack";
3
3
  export interface EnhancedDependencyExtractionWebpackPluginOptions {
4
4
  injectPolyfill?: boolean;
@@ -1,10 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.EnhancedDependencyExtractionWebpackPlugin = void 0;
7
- const dependency_extraction_webpack_plugin_1 = __importDefault(require("@wordpress/dependency-extraction-webpack-plugin"));
8
4
  const webpack_1 = require("webpack");
9
5
  /**
10
6
  * Internal dependencies
@@ -34,7 +30,7 @@ class EnhancedDependencyExtractionWebpackPlugin {
34
30
  */
35
31
  useModules = false;
36
32
  constructor(options) {
37
- if (options instanceof dependency_extraction_webpack_plugin_1.default) {
33
+ if (typeof options === 'object' && options?.constructor?.name === 'DependencyExtractionWebpackPlugin') {
38
34
  options = options.options;
39
35
  }
40
36
  if (options instanceof EnhancedDependencyExtractionWebpackPlugin) {
@@ -15,6 +15,7 @@ const BUNDLED_PACKAGES = [
15
15
  '@wordpress/grid',
16
16
  '@wordpress/icons',
17
17
  '@wordpress/interface',
18
+ '@wordpress/kebab-case',
18
19
  '@wordpress/style-runtime',
19
20
  '@wordpress/ui',
20
21
  '@wordpress/undo-manager',
@@ -1,4 +1,4 @@
1
1
  import { PlauditWordpressWebpackConfig } from "./shared";
2
2
  import type { Configuration } from "webpack";
3
- declare const _default: (config: PlauditWordpressWebpackConfig, webpackConfig?: Configuration[] | Configuration) => Configuration[];
4
3
  export = _default;
4
+ declare function _default(config: PlauditWordpressWebpackConfig, webpackConfig?: Configuration[] | Configuration): Configuration[];
@@ -10,7 +10,6 @@ const entrypoint_resolution_logic_1 = require("./utils/entrypoint-resolution-log
10
10
  const common_config_helpers_1 = require("./utils/common-config-helpers");
11
11
  const path_query_and_related_helpers_1 = require("./utils/path-query-and-related-helpers");
12
12
  const AdditionalDependencyInjectorPlugin_1 = require("./plugins/AdditionalDependencyInjectorPlugin");
13
- const BrowserSyncPlugin_1 = require("./plugins/BrowserSyncPlugin");
14
13
  const dependency_extraction_webpack_plugin_config_builder_1 = require("./plugins/dependency-extraction-webpack-plugin-config-builder");
15
14
  const EnhancedDynamicEntryPlugin_1 = require("./plugins/EnhancedDynamicEntryPlugin");
16
15
  const ExtensionsConfigFileGeneratorPlugin_1 = require("./plugins/ExtensionsConfigFileGeneratorPlugin");
@@ -149,7 +148,7 @@ function buildVerifiedConfig(config) {
149
148
  config = (0, shared_1.applyStandards)(config);
150
149
  const { standaloneBlocks = false, stats = 'errors-warnings', variables: rawVariables, verbose = process.argv.includes('--verbose') || process.env['VERBOSE'] === 'true', postcss = {}, externals, assumeGlobalizedPlauditLibraries = true, useWebpackResourceFiltering = true, plainEntrypointsVersion = 1, srcDir = "", useUnifiedLoader = false, includePostInitFallback = false, omitDistDev = false, onlyRunPostCSSOnPCSS = false, useBlockSupportsAsThemeJsonDefaults = true, } = config;
151
150
  let outputDir = config.outputDir ?? "";
152
- if (outputDir && useUnifiedLoader && !omitDistDev && (process.env['SERVER_MODE'] ?? 'development') === 'development') {
151
+ if ((0, shared_1.shouldWriteDistDev)({ outputDir, useUnifiedLoader, omitDistDev })) {
153
152
  outputDir += "-dev";
154
153
  }
155
154
  let srcPrefixes;
@@ -348,34 +347,73 @@ function withDerivedOutputDir(cfg, sources) {
348
347
  })
349
348
  };
350
349
  }
350
+ let forkTsCheckerInstalled = false;
351
+ function isTypeScriptSourceFile(file) {
352
+ return /\.[cm]?tsx?$/i.test(file.split('?')[0] ?? '');
353
+ }
354
+ const prefixes = ['c', 'm', ''];
355
+ const suffixes = ['x', ''];
356
+ const tsExtensions = prefixes.map(prefix => prefix + "ts").flatMap(name => suffixes.map(suffix => name + suffix));
351
357
  function handleDisablingTSCheckerIfNecessary(srcRoot, scriptExtension, plugins) {
352
- if (process.env["NO_TS_CHECKER"] !== "true") {
353
- const include = (Array.isArray(srcRoot) ? srcRoot : [srcRoot])
354
- .filter(sr => (0, node_path_1.extname)(sr).length === 0 || (0, shared_1.scriptOrStyleTest)(sr, scriptExtension) === "script")
355
- .map(sr => (0, node_path_1.extname)(sr).length > 0 ? sr : (0, node_path_1.join)(sr, "**", "*"));
356
- if (include.length > 0) {
357
- plugins.push(new fork_ts_checker_webpack_plugin_1.default({
358
- async: true,
359
- typescript: {
360
- diagnosticOptions: {
361
- semantic: true,
362
- syntactic: true,
363
- },
364
- configOverwrite: {
365
- include,
366
- compilerOptions: {
367
- skipLibCheck: true
368
- }
369
- }
370
- },
371
- issue: {
372
- exclude(issue) {
373
- return issue.code === 'TS18003'; // This hides the "no TypeScript files found" error while still monitoring the directory
374
- }
375
- }
376
- }));
358
+ if (process.env["NO_TS_CHECKER"] === "true" || forkTsCheckerInstalled) {
359
+ return;
360
+ }
361
+ const include = [];
362
+ for (const sr of (Array.isArray(srcRoot) ? srcRoot : [srcRoot])) {
363
+ if ((0, node_path_1.extname)(sr).length === 0) {
364
+ include.push(...tsExtensions.map(tsExt => (0, node_path_1.join)(sr, "**", `*.${tsExt}`)));
365
+ }
366
+ else if ((0, shared_1.scriptOrStyleTest)(sr, scriptExtension) === "script") {
367
+ include.push(sr);
377
368
  }
378
369
  }
370
+ if (include.length === 0) {
371
+ return;
372
+ }
373
+ forkTsCheckerInstalled = true;
374
+ let logTsStatus = true;
375
+ plugins.push({
376
+ apply(compiler) {
377
+ compiler.hooks.watchRun.tap('PlauditForkTsCheckerCssQuiet', watchingCompiler => {
378
+ const changed = [
379
+ ...(watchingCompiler.modifiedFiles ?? []),
380
+ ...(watchingCompiler.removedFiles ?? [])
381
+ ];
382
+ logTsStatus = changed.length === 0 || changed.some(isTypeScriptSourceFile);
383
+ });
384
+ }
385
+ });
386
+ plugins.push(new fork_ts_checker_webpack_plugin_1.default({
387
+ async: true,
388
+ logger: {
389
+ log(message) {
390
+ if (!logTsStatus) {
391
+ return;
392
+ }
393
+ console.log(message);
394
+ },
395
+ error(message) {
396
+ console.error(message);
397
+ }
398
+ },
399
+ typescript: {
400
+ diagnosticOptions: {
401
+ semantic: true,
402
+ syntactic: true,
403
+ },
404
+ configOverwrite: {
405
+ include,
406
+ compilerOptions: {
407
+ skipLibCheck: true
408
+ }
409
+ }
410
+ },
411
+ issue: {
412
+ exclude(issue) {
413
+ return issue.code === 'TS18003';
414
+ }
415
+ }
416
+ }));
379
417
  }
380
418
  function buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize) {
381
419
  const plugins = webpackConfig.plugins?.filter(v => !!v)
@@ -420,7 +458,13 @@ function buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGl
420
458
  }
421
459
  const builtDependencyExtractionWebpackPlugin = (0, dependency_extraction_webpack_plugin_config_builder_1.makeDependencyExtractionPlugin)(config.externals, assumeGlobalizedPlauditLibraries, externalize);
422
460
  plugins[dependencyExtractionPluginIndex] = builtDependencyExtractionWebpackPlugin;
423
- plugins.push(new BrowserSyncPlugin_1.BrowserSyncPlugin());
461
+ if ((0, shared_1.isDistDevOutputPath)(config.outputDir)) {
462
+ try {
463
+ const { PlauditDevPlugin } = require("@plaudit/dev-webpack-plugin");
464
+ plugins.push(new PlauditDevPlugin());
465
+ }
466
+ catch { }
467
+ }
424
468
  return {
425
469
  plugins, removeEmptyScriptsPlugin,
426
470
  makeAdditionalDependencyInjectorPlugin(referencePlugin) {
@@ -467,7 +511,7 @@ function destToKey(dest) {
467
511
  : dest.externalize?.toString() ?? "undefined";
468
512
  return [dest.assumeGlobalizedPlauditLibraries, dest.bundleAnalyzer, externalize].join("~");
469
513
  }
470
- function processIndividualWebpackConfig(config, webpackConfig, sources, canClean) {
514
+ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean, preferNonModuleTsChecker) {
471
515
  if (webpackConfig.output?.module) {
472
516
  // This ensures that module files are emitted as module files
473
517
  webpackConfig = {
@@ -501,7 +545,9 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
501
545
  return batches.map(currentBatch => {
502
546
  const { bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize } = currentBatch[0].dest;
503
547
  const { plugins, removeEmptyScriptsPlugin, makeAdditionalDependencyInjectorPlugin } = buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize);
504
- handleDisablingTSCheckerIfNecessary(currentBatch.flatMap(a => a.srcRoots), scriptExtension, plugins);
548
+ if (!processingModules || !preferNonModuleTsChecker) {
549
+ handleDisablingTSCheckerIfNecessary(currentBatch.flatMap(a => a.srcRoots), scriptExtension, plugins);
550
+ }
505
551
  const applicableExtensionTest = (name) => {
506
552
  return commonConfig.scriptExtension.test(name) || (!processingModules && shared_1.styleExtension.test(name));
507
553
  };
@@ -642,12 +688,13 @@ module.exports = function (config, webpackConfig = require("@wordpress/scripts/c
642
688
  webpackConfig = webpackConfig[0];
643
689
  }
644
690
  if (Array.isArray(webpackConfig)) {
691
+ const hasNonModuleCompiler = webpackConfig.some(cfg => !cfg.output?.module);
645
692
  return webpackConfig.toSorted((a, b) => {
646
693
  if (a.output?.module) {
647
694
  return b.output?.module ? 0 : -1;
648
695
  }
649
696
  return b.output?.module ? 1 : 0;
650
- }).flatMap(wpCfg => processIndividualWebpackConfig(cfg, wpCfg, sources, false));
697
+ }).flatMap(wpCfg => processIndividualWebpackConfig(cfg, wpCfg, sources, false, hasNonModuleCompiler));
651
698
  }
652
- return processIndividualWebpackConfig(cfg, webpackConfig, sources, true);
699
+ return processIndividualWebpackConfig(cfg, webpackConfig, sources, true, false);
653
700
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "3.17.0",
3
+ "version": "3.19.0",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,14 +32,15 @@
32
32
  }
33
33
  },
34
34
  "devDependencies": {
35
+ "@plaudit/dev-webpack-plugin": "^1.0.1",
35
36
  "@plaudit/gutenberg-api-extensions": "^2.98.2",
36
- "@types/browser-sync-webpack-plugin": "^2.2.5",
37
- "@types/jsdom": "^28.0.3",
38
- "@types/node": "^25.9.5",
37
+ "@types/jsdom": "^30.0.0",
38
+ "@types/node": "^26.2.0",
39
39
  "@types/postcss-functions": "^4.0.4",
40
40
  "@types/postcss-import": "^14.0.3",
41
41
  "@types/tapable": "^2.3.0",
42
42
  "@types/webpack-sources": "^3.2.3",
43
+ "@wordpress/dependency-extraction-webpack-plugin": "^6.53.0",
43
44
  "atob": "^2.1.2",
44
45
  "css-loader": "^6.11.0",
45
46
  "glob": "^7.2.3",
@@ -50,7 +51,7 @@
50
51
  "react": "^18.3.1",
51
52
  "react-dom": "^18.3.1",
52
53
  "rimraf": "^5.0.10",
53
- "typescript": "^6.0.3",
54
+ "typescript": "^7.0.2",
54
55
  "webpack-bundle-analyzer": "^5.3.1"
55
56
  },
56
57
  "dependencies": {
@@ -58,16 +59,13 @@
58
59
  "@plaudit/postcss-color-function": "^5.1.0",
59
60
  "@plaudit/postcss-strip-units": "^3.0.0",
60
61
  "@plaudit/postcss-variables": "^2.0.1",
61
- "@wordpress/dependency-extraction-webpack-plugin": "^6.53.0",
62
62
  "@wordpress/scripts": "^32.6.0",
63
63
  "autoprefixer": "^10.5.4",
64
- "browser-sync": "^3.0.4",
65
64
  "copy-webpack-plugin": "10.2.4",
66
65
  "css-minimizer-webpack-plugin": "^8.0.0",
67
66
  "cssnano": "^7.1.9",
68
67
  "fork-ts-checker-webpack-plugin": "^9.1.0",
69
- "http-proxy-middleware": "^3.0.7",
70
- "jsdom": "^29.1.1",
68
+ "jsdom": "^30.0.1",
71
69
  "json2php": "0.0.12",
72
70
  "postcss": "^8.5.26",
73
71
  "postcss-calc": "^10.1.1",
@@ -83,6 +81,14 @@
83
81
  "webpack-remove-empty-scripts": "^1.1.1",
84
82
  "xml-formatter": "^3.7.0"
85
83
  },
84
+ "peerDependencies": {
85
+ "@plaudit/dev-webpack-plugin": "^1.0.0"
86
+ },
87
+ "peerDependenciesMeta": {
88
+ "@plaudit/dev-webpack-plugin": {
89
+ "optional": true
90
+ }
91
+ },
86
92
  "engines": {
87
93
  "node": ">=20"
88
94
  },
@@ -90,6 +96,7 @@
90
96
  "build": "tsc",
91
97
  "clean": "rm -rf dist",
92
98
  "build:clean": "pnpm run clean && pnpm run build",
99
+ "build:sync-wp-bundled-packages": "node tools/bundled-packages-sync.mts",
93
100
  "watch": "tsc -w",
94
101
  "test": "pnpm run build && pnpm run test:no-build",
95
102
  "test:no-build": "rm -rf tests/.tmp/coverage/jest && NODE_V8_COVERAGE=tests/.tmp/coverage/jest jest",
@@ -1,25 +0,0 @@
1
- import { type WebpackPlugin } from "../shared";
2
- import browserSync, { type BrowserSyncInstance } from "browser-sync";
3
- import type { Compiler } from "webpack";
4
- export type PluginOptions = {
5
- reload: boolean;
6
- name: string;
7
- callback?: (err: Error, bs: BrowserSyncInstance) => any;
8
- injectCss: boolean;
9
- middlewareBuilder?: (options: browserSync.Options) => browserSync.Options['middleware'];
10
- };
11
- export declare class BrowserSyncPlugin implements WebpackPlugin {
12
- private static isBrowserSyncRunning;
13
- private static browserSyncPluginOptions?;
14
- private readonly pluginOptions;
15
- private readonly browserSyncInstance;
16
- private isWebpackWatching;
17
- private mostRecentChunkHashes;
18
- private shouldNotify;
19
- constructor(pluginOptions?: Partial<PluginOptions>);
20
- private static getBrowserSyncPluginOptions;
21
- private static findEnvFile;
22
- apply(compiler: Compiler): void;
23
- private getCssOnlyEmittedAssetsNames;
24
- private static getSiteUrls;
25
- }
@@ -1,212 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.BrowserSyncPlugin = void 0;
7
- const node_child_process_1 = __importDefault(require("node:child_process"));
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const shared_1 = require("../shared");
11
- const browser_sync_1 = __importDefault(require("browser-sync"));
12
- const http_proxy_middleware_1 = require("http-proxy-middleware");
13
- class BrowserSyncPlugin {
14
- static isBrowserSyncRunning = false;
15
- static browserSyncPluginOptions;
16
- pluginOptions;
17
- browserSyncInstance;
18
- isWebpackWatching = false;
19
- mostRecentChunkHashes = {};
20
- shouldNotify = false;
21
- constructor(pluginOptions) {
22
- this.pluginOptions = { reload: true, name: "plaudit-bs-plugin", injectCss: true, ...pluginOptions };
23
- this.browserSyncInstance = browser_sync_1.default.has(this.pluginOptions.name) ? browser_sync_1.default.get(this.pluginOptions.name) : browser_sync_1.default.create(this.pluginOptions.name);
24
- }
25
- static getBrowserSyncPluginOptions() {
26
- return BrowserSyncPlugin.browserSyncPluginOptions ?? (BrowserSyncPlugin.browserSyncPluginOptions = new Promise(async (resolve) => {
27
- const envFilePath = BrowserSyncPlugin.findEnvFile();
28
- const envFile = envFilePath ? await (0, shared_1.loadEnvFile)(envFilePath) : {};
29
- const prefixes = BrowserSyncPlugin.getSiteUrls();
30
- const targetPort = envFile["WEB_PORT_SSL"]?.match(/^\d+$/) ? envFile["WEB_PORT_SSL"] : "8443";
31
- const targetHost = targetPort === "443" ? "localhost" : `localhost:${targetPort}`;
32
- if (prefixes.length === 0 || prefixes.every(prefix => prefix.startsWith("localhost"))) {
33
- resolve([{
34
- host: 'localhost',
35
- port: 3000,
36
- https: true,
37
- proxy: `https://${targetHost}`
38
- }, {}]);
39
- }
40
- else {
41
- resolve([{
42
- port: 3000,
43
- listen: "0.0.0.0",
44
- https: true,
45
- open: false,
46
- callbacks: {
47
- ready(err, bsi) {
48
- // This ensures that the opened URL is actually a valid one
49
- import("open").then(open => open.default(`https://${prefixes[0]?.replace(/:\d{2,4}/, "")}:${bsi.getOption("port") ?? 3000}`));
50
- }
51
- }
52
- }, {
53
- middlewareBuilder: (options) => {
54
- const proxyPort = options.port?.toString() ?? "3000";
55
- const router = prefixes.reduce((router, prefix) => {
56
- router[`${prefix}:${proxyPort}`] = {
57
- protocol: 'https:',
58
- slashes: true,
59
- auth: null,
60
- host: prefix,
61
- port: targetPort,
62
- hostname: targetHost,
63
- hash: null,
64
- search: null,
65
- query: null,
66
- pathname: '/',
67
- path: '/',
68
- href: `https://${targetHost}/`
69
- };
70
- return router;
71
- }, {});
72
- const portInjectionPattern = new RegExp(`(${prefixes.join('|')})(?!:3000)`, "gi");
73
- return (0, http_proxy_middleware_1.createProxyMiddleware)({
74
- changeOrigin: true, router, secure: false, xfwd: true, selfHandleResponse: true, target: `https://${targetHost}`,
75
- on: {
76
- proxyRes: (0, http_proxy_middleware_1.responseInterceptor)(async (responseBuffer, proxyRes) => {
77
- const contentType = proxyRes.headers["content-type"];
78
- if (contentType && (contentType.startsWith("text/") || contentType === "application/x-javascript")) {
79
- return responseBuffer.toString('utf-8').replaceAll(portInjectionPattern, "$1:3000");
80
- }
81
- return responseBuffer;
82
- })
83
- }
84
- });
85
- }
86
- }]);
87
- }
88
- }));
89
- }
90
- static findEnvFile() {
91
- for (let envFileHolderPath = process.cwd(); envFileHolderPath.length > 5; envFileHolderPath = node_path_1.default.dirname(envFileHolderPath)) {
92
- if (node_fs_1.default.existsSync(node_path_1.default.join(envFileHolderPath, ".env"))) {
93
- return node_path_1.default.join(envFileHolderPath, ".env");
94
- }
95
- }
96
- return undefined;
97
- }
98
- apply(compiler) {
99
- if (!process.argv.includes('--browser-sync') && process.env['BROWSER_SYNC'] !== 'true') {
100
- return;
101
- }
102
- let devTarget = process.env['DEV_TARGET'] ?? process.argv.find(a => a.startsWith("--dev-target="))?.substring(13);
103
- if (devTarget === undefined) {
104
- const flagIndex = process.argv.findIndex(a => a === "--dev-target");
105
- if (flagIndex > -1) {
106
- devTarget = process.argv[flagIndex + 1];
107
- }
108
- }
109
- if (devTarget !== undefined && devTarget !== node_path_1.default.basename(process.cwd()) && !(devTarget === "theme" && node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), "style.css")))) {
110
- return;
111
- }
112
- compiler.hooks.watchRun.tap(BrowserSyncPlugin.name, () => {
113
- this.isWebpackWatching = true;
114
- });
115
- compiler.hooks.compilation.tap(BrowserSyncPlugin.name, () => {
116
- if (BrowserSyncPlugin.isBrowserSyncRunning && this.shouldNotify) {
117
- this.browserSyncInstance.notify('Rebuilding...');
118
- }
119
- });
120
- compiler.hooks.done.tapPromise(BrowserSyncPlugin.name, async (stats) => {
121
- if (!this.isWebpackWatching) {
122
- return;
123
- }
124
- if (!BrowserSyncPlugin.isBrowserSyncRunning) {
125
- const [browserSyncOptions, pluginOptions] = await BrowserSyncPlugin.getBrowserSyncPluginOptions();
126
- const actualPluginOptions = { ...this.pluginOptions, ...pluginOptions };
127
- const middleware = actualPluginOptions.middlewareBuilder?.(browserSyncOptions);
128
- this.browserSyncInstance.init(middleware
129
- ? { ...browserSyncOptions, server: { middleware: Array.isArray(middleware) ? middleware : [middleware] } }
130
- : browserSyncOptions, this.pluginOptions.callback);
131
- if (browserSyncOptions.notify) {
132
- this.shouldNotify = true;
133
- }
134
- BrowserSyncPlugin.isBrowserSyncRunning = true;
135
- }
136
- if (this.pluginOptions.reload) {
137
- if (this.pluginOptions.injectCss) {
138
- const cssOnlyEmittedAssets = this.getCssOnlyEmittedAssetsNames(stats);
139
- if (cssOnlyEmittedAssets !== undefined) {
140
- this.browserSyncInstance.reload(cssOnlyEmittedAssets);
141
- return;
142
- }
143
- }
144
- this.browserSyncInstance.reload();
145
- }
146
- });
147
- }
148
- getCssOnlyEmittedAssetsNames(stats) {
149
- const compiledStats = stats.compilation.getStats().toJson({
150
- hash: true,
151
- publicPath: true,
152
- assets: true,
153
- chunks: true,
154
- modules: false,
155
- source: false,
156
- errorDetails: false,
157
- timings: false
158
- });
159
- const chunks = compiledStats.chunks
160
- ?.filter((chunk) => chunk.names !== undefined && chunk.files !== undefined);
161
- if (!chunks) {
162
- return undefined;
163
- }
164
- const mostRecentChunkHashes = this.mostRecentChunkHashes;
165
- this.mostRecentChunkHashes = Object.fromEntries(chunks.flatMap(chunk => chunk.names.map(cn => [cn, chunk.hash])));
166
- if (Object.keys(mostRecentChunkHashes).length !== chunks.length) {
167
- return undefined;
168
- }
169
- const changedFilenames = chunks
170
- .filter(chunk => chunk.names.some(name => mostRecentChunkHashes[name] !== chunk.hash))
171
- .flatMap(chunk => [...chunk.files, ...(chunk.auxiliaryFiles ?? [])])
172
- .filter(filename => !filename.endsWith(".asset.php"));
173
- if (changedFilenames.length === 0) {
174
- return undefined;
175
- }
176
- for (const filename of changedFilenames) {
177
- if (!filename.includes(".css")) {
178
- return undefined;
179
- }
180
- }
181
- return changedFilenames;
182
- }
183
- static getSiteUrls() {
184
- //docker container inspect "$(docker compose ps --format=json | jq '. | select(. | contains({"Service": "wordpress"})) | .ID' -r)" | jq '.[].Config.Env'
185
- const serviceId = node_child_process_1.default.spawnSync("docker", ["compose", "ps", "--format=json"], { encoding: "utf-8", stdio: ["ignore", "pipe", "inherit"] })
186
- .stdout.trim().split("\n").map(item => JSON.parse(item.trim())).find(item => item.Service === "wordpress")?.ID;
187
- if (serviceId === undefined) {
188
- return ["localhost"]; // This will only happen for Tomcat or misconfigured containers, both of which should use localhost
189
- }
190
- const inspectionResult = node_child_process_1.default.spawnSync("docker", ["container", "inspect", "--format=json", serviceId], { encoding: "utf-8", stdio: ["ignore", "pipe", "inherit"] })
191
- .stdout.trim();
192
- const containerEnv = Object.fromEntries(JSON.parse(inspectionResult)[0]?.Config.Env.map((envEntry) => {
193
- const equalSignIndex = envEntry.indexOf('=');
194
- return [envEntry.substring(0, equalSignIndex), envEntry.substring(equalSignIndex + 1)];
195
- }));
196
- if (containerEnv['WORDPRESS_MAPPED_DOMAINS'] !== '1') {
197
- return ["localhost:8443"]; //This will only happen for legacy WordPress sites
198
- }
199
- let siteUrls;
200
- const multisiteUrlsProcess = node_child_process_1.default.spawnSync("docker", ["compose", "exec", "--user=www-data", "wordpress", "wp", "site", "list", "--field=url", "--quiet"], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }); // We're forced to mute stderr here because it is otherwise almost guaranteed to print
201
- if (!multisiteUrlsProcess.error && !multisiteUrlsProcess.status && !multisiteUrlsProcess.signal) {
202
- siteUrls = multisiteUrlsProcess.stdout.split("\n").map(line => line.trim()).filter(line => line.length > 0);
203
- }
204
- else {
205
- siteUrls = [node_child_process_1.default.spawnSync("docker", ["compose", "exec", "--user=www-data", "wordpress", "wp", "option", "get", "siteurl"], { encoding: "utf-8", stdio: ["ignore", "pipe", "inherit"] }).stdout.trim()];
206
- }
207
- // Because mapped domain sites that are using my mapping scheme hyphenate instances of "www.", this is an effective test for whether it is in use.
208
- // If the URL still has the "www.", then it is using David's mapping scheme and should be accessed via localhost
209
- return siteUrls.map(siteUrl => siteUrl.includes("www.") ? "localhost" : siteUrl).map(siteUrl => siteUrl.replace(/^https?:\/\//i, ""));
210
- }
211
- }
212
- exports.BrowserSyncPlugin = BrowserSyncPlugin;