@wordpress/build 0.2.0 → 0.2.1-next.2f1c7c01b.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/.cache/tsconfig.tsbuildinfo +1 -1
- package/README.md +61 -0
- package/package.json +2 -2
- package/src/build.mjs +339 -107
- package/src/dependency-graph.mjs +110 -12
- package/src/package-utils.mjs +5 -0
- package/src/php-generator.mjs +101 -0
- package/src/route-utils.mjs +94 -0
- package/src/wordpress-externals-plugin.mjs +27 -10
- package/templates/index.php.template +6 -0
- package/templates/route-registry.php.template +11 -0
- package/templates/routes.php.template +66 -0
package/src/build.mjs
CHANGED
|
@@ -3,19 +3,15 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* External dependencies
|
|
5
5
|
*/
|
|
6
|
-
import { readFile, writeFile, copyFile, mkdir } from 'fs/promises';
|
|
7
|
-
import { readdirSync } from 'fs';
|
|
6
|
+
import { readFile, writeFile, copyFile, mkdir, unlink } from 'fs/promises';
|
|
8
7
|
import path from 'path';
|
|
9
8
|
import { parseArgs } from 'node:util';
|
|
10
9
|
import esbuild from 'esbuild';
|
|
11
10
|
import glob from 'fast-glob';
|
|
12
11
|
import chokidar from 'chokidar';
|
|
13
|
-
// See https://github.com/WordPress/gutenberg/issues/72136
|
|
14
|
-
// eslint-disable-next-line import/no-unresolved
|
|
15
12
|
import browserslistToEsbuild from 'browserslist-to-esbuild';
|
|
16
|
-
import { sassPlugin } from 'esbuild-sass-plugin';
|
|
13
|
+
import { sassPlugin, postcssModules } from 'esbuild-sass-plugin';
|
|
17
14
|
import postcss from 'postcss';
|
|
18
|
-
import postcssModulesPlugin from 'postcss-modules';
|
|
19
15
|
import autoprefixer from 'autoprefixer';
|
|
20
16
|
import rtlcss from 'rtlcss';
|
|
21
17
|
import cssnano from 'cssnano';
|
|
@@ -25,28 +21,43 @@ import { camelCase } from 'change-case';
|
|
|
25
21
|
/**
|
|
26
22
|
* Internal dependencies
|
|
27
23
|
*/
|
|
28
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
groupByDepth,
|
|
26
|
+
findScriptsToRebundle,
|
|
27
|
+
findRoutesToRebuild,
|
|
28
|
+
} from './dependency-graph.mjs';
|
|
29
29
|
import {
|
|
30
30
|
generatePhpFromTemplate,
|
|
31
31
|
getPhpReplacements,
|
|
32
|
+
generateRoutesPhp,
|
|
33
|
+
generateRoutesRegistry,
|
|
32
34
|
} from './php-generator.mjs';
|
|
33
35
|
import { getPackageInfo, getPackageInfoFromFile } from './package-utils.mjs';
|
|
34
36
|
import { createWordpressExternalsPlugin } from './wordpress-externals-plugin.mjs';
|
|
37
|
+
import {
|
|
38
|
+
getAllRoutes,
|
|
39
|
+
getRouteFiles,
|
|
40
|
+
generateContentEntryPoint,
|
|
41
|
+
} from './route-utils.mjs';
|
|
35
42
|
|
|
36
43
|
const ROOT_DIR = process.cwd();
|
|
37
44
|
const PACKAGES_DIR = path.join( ROOT_DIR, 'packages' );
|
|
38
45
|
const BUILD_DIR = path.join( ROOT_DIR, 'build' );
|
|
39
46
|
|
|
40
47
|
const SOURCE_EXTENSIONS = '{js,ts,tsx}';
|
|
48
|
+
const ASSET_EXTENSIONS = 'json';
|
|
41
49
|
const IGNORE_PATTERNS = [
|
|
42
50
|
'**/benchmark/**',
|
|
43
51
|
'**/{__mocks__,__tests__,test}/**',
|
|
44
52
|
'**/{storybook,stories}/**',
|
|
45
53
|
'**/*.native.*',
|
|
54
|
+
'**/*.ios.*',
|
|
55
|
+
'**/*.android.*',
|
|
46
56
|
];
|
|
47
57
|
const TEST_FILE_PATTERNS = [
|
|
48
58
|
/\/(benchmark|__mocks__|__tests__|test|storybook|stories)\/.+/,
|
|
49
59
|
/\.(spec|test)\.(js|ts|tsx)$/,
|
|
60
|
+
/\.(native|ios|android)\.(js|ts|tsx)$/,
|
|
50
61
|
];
|
|
51
62
|
|
|
52
63
|
/**
|
|
@@ -55,20 +66,23 @@ const TEST_FILE_PATTERNS = [
|
|
|
55
66
|
* @return {string[]} Array of package names.
|
|
56
67
|
*/
|
|
57
68
|
function getAllPackages() {
|
|
58
|
-
return
|
|
59
|
-
.
|
|
60
|
-
.map( (
|
|
69
|
+
return glob
|
|
70
|
+
.sync( normalizePath( path.join( PACKAGES_DIR, '*', 'package.json' ) ) )
|
|
71
|
+
.map( ( packageJsonPath ) =>
|
|
72
|
+
path.basename( path.dirname( packageJsonPath ) )
|
|
73
|
+
);
|
|
61
74
|
}
|
|
62
75
|
|
|
63
76
|
const PACKAGES = getAllPackages();
|
|
64
|
-
const ROOT_PACKAGE_JSON = getPackageInfoFromFile(
|
|
77
|
+
const ROOT_PACKAGE_JSON = getPackageInfoFromFile(
|
|
78
|
+
path.join( ROOT_DIR, 'package.json' )
|
|
79
|
+
);
|
|
65
80
|
const WP_PLUGIN_CONFIG = ROOT_PACKAGE_JSON.wpPlugin || {};
|
|
66
81
|
const SCRIPT_GLOBAL = WP_PLUGIN_CONFIG.scriptGlobal;
|
|
67
82
|
const PACKAGE_NAMESPACE = WP_PLUGIN_CONFIG.packageNamespace;
|
|
68
83
|
const HANDLE_PREFIX = WP_PLUGIN_CONFIG.handlePrefix || PACKAGE_NAMESPACE;
|
|
69
84
|
const EXTERNAL_NAMESPACES = WP_PLUGIN_CONFIG.externalNamespaces || {};
|
|
70
85
|
|
|
71
|
-
|
|
72
86
|
const baseDefine = {
|
|
73
87
|
'globalThis.IS_GUTENBERG_PLUGIN': JSON.stringify(
|
|
74
88
|
Boolean( process.env.npm_package_config_IS_GUTENBERG_PLUGIN )
|
|
@@ -92,20 +106,26 @@ const wordpressExternalsPlugin = createWordpressExternalsPlugin(
|
|
|
92
106
|
HANDLE_PREFIX
|
|
93
107
|
);
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
const styleBundlingPlugins = [
|
|
110
|
+
// Handle CSS modules (.module.css and .module.scss)
|
|
111
|
+
sassPlugin( {
|
|
112
|
+
embedded: true,
|
|
113
|
+
filter: /\.module\.(css|scss)$/,
|
|
114
|
+
transform: postcssModules( {
|
|
115
|
+
generateScopedName: '[name]__[local]__[hash:base64:5]',
|
|
116
|
+
} ),
|
|
117
|
+
type: 'style',
|
|
118
|
+
loadPaths: [ 'node_modules', path.join( PACKAGES_DIR, 'base-styles' ) ],
|
|
119
|
+
} ),
|
|
120
|
+
// Handle regular CSS/SCSS files
|
|
121
|
+
// Note: .module.css and .module.scss already handled by plugin above
|
|
122
|
+
sassPlugin( {
|
|
123
|
+
embedded: true,
|
|
124
|
+
filter: /\.(css|scss)$/,
|
|
125
|
+
type: 'style',
|
|
126
|
+
loadPaths: [ 'node_modules', path.join( PACKAGES_DIR, 'base-styles' ) ],
|
|
127
|
+
} ),
|
|
128
|
+
];
|
|
109
129
|
|
|
110
130
|
/**
|
|
111
131
|
* Normalize path separators for cross-platform compatibility.
|
|
@@ -278,7 +298,9 @@ async function bundlePackage( packageName ) {
|
|
|
278
298
|
|
|
279
299
|
// Check if package matches the namespace and should expose a global
|
|
280
300
|
const packageFullName = packageJson.name;
|
|
281
|
-
const matchesNamespace = packageFullName.startsWith(
|
|
301
|
+
const matchesNamespace = packageFullName.startsWith(
|
|
302
|
+
`@${ PACKAGE_NAMESPACE }/`
|
|
303
|
+
);
|
|
282
304
|
const shouldExposeGlobal = matchesNamespace && SCRIPT_GLOBAL !== false;
|
|
283
305
|
|
|
284
306
|
const globalName = shouldExposeGlobal
|
|
@@ -789,8 +811,10 @@ async function transpilePackage( packageName ) {
|
|
|
789
811
|
}
|
|
790
812
|
);
|
|
791
813
|
|
|
792
|
-
const
|
|
793
|
-
normalizePath(
|
|
814
|
+
const assetFiles = await glob(
|
|
815
|
+
normalizePath(
|
|
816
|
+
path.join( packageDir, `src/**/*.${ ASSET_EXTENSIONS }` )
|
|
817
|
+
),
|
|
794
818
|
{
|
|
795
819
|
ignore: IGNORE_PATTERNS,
|
|
796
820
|
}
|
|
@@ -806,7 +830,37 @@ async function transpilePackage( packageName ) {
|
|
|
806
830
|
// Check if this is the components package that needs emotion babel plugin.
|
|
807
831
|
// Ideally we should remove this exception and move away from emotion.
|
|
808
832
|
const needsEmotionPlugin = packageName === 'components';
|
|
809
|
-
const
|
|
833
|
+
const emotionPlugin = babel( {
|
|
834
|
+
filter: /\.[jt]sx?$/,
|
|
835
|
+
config: {
|
|
836
|
+
plugins: [ '@emotion/babel-plugin' ],
|
|
837
|
+
},
|
|
838
|
+
} );
|
|
839
|
+
const externalizeAllExceptCssPlugin = {
|
|
840
|
+
name: 'externalize-except-css',
|
|
841
|
+
setup( build ) {
|
|
842
|
+
// Externalize all non-CSS imports
|
|
843
|
+
build.onResolve( { filter: /.*/ }, ( args ) => {
|
|
844
|
+
// Skip entry points
|
|
845
|
+
if ( args.kind === 'entry-point' ) {
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Let CSS/SCSS files be processed by sassPlugin
|
|
850
|
+
if ( args.path.match( /\.(css|scss)$/ ) ) {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Externalize everything else (keep imports as-is)
|
|
855
|
+
return { path: args.path, external: true };
|
|
856
|
+
} );
|
|
857
|
+
},
|
|
858
|
+
};
|
|
859
|
+
const plugins = [
|
|
860
|
+
needsEmotionPlugin && emotionPlugin,
|
|
861
|
+
externalizeAllExceptCssPlugin,
|
|
862
|
+
...styleBundlingPlugins,
|
|
863
|
+
].filter( Boolean );
|
|
810
864
|
|
|
811
865
|
if ( packageJson.main ) {
|
|
812
866
|
builds.push(
|
|
@@ -814,7 +868,7 @@ async function transpilePackage( packageName ) {
|
|
|
814
868
|
entryPoints: srcFiles,
|
|
815
869
|
outdir: buildDir,
|
|
816
870
|
outbase: srcDir,
|
|
817
|
-
bundle:
|
|
871
|
+
bundle: true,
|
|
818
872
|
platform: 'node',
|
|
819
873
|
format: 'cjs',
|
|
820
874
|
sourcemap: true,
|
|
@@ -828,13 +882,13 @@ async function transpilePackage( packageName ) {
|
|
|
828
882
|
} )
|
|
829
883
|
);
|
|
830
884
|
|
|
831
|
-
for ( const
|
|
832
|
-
const relativePath = path.relative( srcDir,
|
|
885
|
+
for ( const assetFile of assetFiles ) {
|
|
886
|
+
const relativePath = path.relative( srcDir, assetFile );
|
|
833
887
|
const destPath = path.join( buildDir, relativePath );
|
|
834
888
|
const destDir = path.dirname( destPath );
|
|
835
889
|
builds.push(
|
|
836
890
|
mkdir( destDir, { recursive: true } ).then( () =>
|
|
837
|
-
copyFile(
|
|
891
|
+
copyFile( assetFile, destPath )
|
|
838
892
|
)
|
|
839
893
|
);
|
|
840
894
|
}
|
|
@@ -846,7 +900,7 @@ async function transpilePackage( packageName ) {
|
|
|
846
900
|
entryPoints: srcFiles,
|
|
847
901
|
outdir: buildModuleDir,
|
|
848
902
|
outbase: srcDir,
|
|
849
|
-
bundle:
|
|
903
|
+
bundle: true,
|
|
850
904
|
platform: 'neutral',
|
|
851
905
|
format: 'esm',
|
|
852
906
|
sourcemap: true,
|
|
@@ -860,7 +914,7 @@ async function transpilePackage( packageName ) {
|
|
|
860
914
|
} )
|
|
861
915
|
);
|
|
862
916
|
|
|
863
|
-
for ( const jsonFile of
|
|
917
|
+
for ( const jsonFile of assetFiles ) {
|
|
864
918
|
const relativePath = path.relative( srcDir, jsonFile );
|
|
865
919
|
const destPath = path.join( buildModuleDir, relativePath );
|
|
866
920
|
const destDir = path.dirname( destPath );
|
|
@@ -882,9 +936,9 @@ async function transpilePackage( packageName ) {
|
|
|
882
936
|
/**
|
|
883
937
|
* Compile styles for a single package.
|
|
884
938
|
*
|
|
885
|
-
* Discovers and compiles SCSS entry points based on package configuration
|
|
886
|
-
*
|
|
887
|
-
*
|
|
939
|
+
* Discovers and compiles SCSS entry points based on package configuration,
|
|
940
|
+
* supporting wpStyleEntryPoints in package.json for custom entry point
|
|
941
|
+
* patterns.
|
|
888
942
|
*
|
|
889
943
|
* @param {string} packageName Package name.
|
|
890
944
|
* @return {Promise<number|null>} Build time in milliseconds, or null if no styles.
|
|
@@ -907,13 +961,7 @@ async function compileStyles( packageName ) {
|
|
|
907
961
|
)
|
|
908
962
|
);
|
|
909
963
|
|
|
910
|
-
|
|
911
|
-
const cssModuleEntries = await glob(
|
|
912
|
-
normalizePath( path.join( packageDir, 'src/**/*.module.css' ) ),
|
|
913
|
-
{ ignore: IGNORE_PATTERNS }
|
|
914
|
-
);
|
|
915
|
-
|
|
916
|
-
if ( scssEntries.length === 0 && cssModuleEntries.length === 0 ) {
|
|
964
|
+
if ( scssEntries.length === 0 ) {
|
|
917
965
|
return null;
|
|
918
966
|
}
|
|
919
967
|
|
|
@@ -921,64 +969,6 @@ async function compileStyles( packageName ) {
|
|
|
921
969
|
const buildStyleDir = path.join( packageDir, 'build-style' );
|
|
922
970
|
const srcDir = path.join( packageDir, 'src' );
|
|
923
971
|
|
|
924
|
-
// Process .module.css files and generate JS modules
|
|
925
|
-
const cssResults = await Promise.all(
|
|
926
|
-
cssModuleEntries.map( async ( styleEntryPath ) => {
|
|
927
|
-
const buildDir = path.join( packageDir, 'build' );
|
|
928
|
-
const buildModuleDir = path.join( packageDir, 'build-module' );
|
|
929
|
-
|
|
930
|
-
const cssContent = await readFile( styleEntryPath, 'utf8' );
|
|
931
|
-
const relativePath = path.relative( srcDir, styleEntryPath );
|
|
932
|
-
|
|
933
|
-
let mappings = {};
|
|
934
|
-
const result = await postcss( [
|
|
935
|
-
postcssModulesPlugin( {
|
|
936
|
-
getJSON: ( _, json ) => ( mappings = json ),
|
|
937
|
-
} ),
|
|
938
|
-
] ).process( cssContent, { from: styleEntryPath } );
|
|
939
|
-
|
|
940
|
-
// Write processed CSS to build-style (preserving directory structure)
|
|
941
|
-
const cssOutPath = path.join(
|
|
942
|
-
buildStyleDir,
|
|
943
|
-
relativePath.replace( '.module.css', '.css' )
|
|
944
|
-
);
|
|
945
|
-
await mkdir( path.dirname( cssOutPath ), { recursive: true } );
|
|
946
|
-
await writeFile( cssOutPath, result.css );
|
|
947
|
-
|
|
948
|
-
// Generate JS modules with class name mappings (preserving directory structure)
|
|
949
|
-
const jsExport = JSON.stringify( mappings );
|
|
950
|
-
const jsPath = `${ relativePath }.js`;
|
|
951
|
-
await Promise.all( [
|
|
952
|
-
mkdir( path.dirname( path.join( buildDir, jsPath ) ), {
|
|
953
|
-
recursive: true,
|
|
954
|
-
} ),
|
|
955
|
-
mkdir( path.dirname( path.join( buildModuleDir, jsPath ) ), {
|
|
956
|
-
recursive: true,
|
|
957
|
-
} ),
|
|
958
|
-
] );
|
|
959
|
-
await Promise.all( [
|
|
960
|
-
writeFile(
|
|
961
|
-
path.join( buildDir, jsPath ),
|
|
962
|
-
`"use strict";\nmodule.exports = ${ jsExport };\n`
|
|
963
|
-
),
|
|
964
|
-
writeFile(
|
|
965
|
-
path.join( buildModuleDir, jsPath ),
|
|
966
|
-
`export default ${ jsExport };\n`
|
|
967
|
-
),
|
|
968
|
-
] );
|
|
969
|
-
|
|
970
|
-
// Return the processed CSS for combining
|
|
971
|
-
return result.css;
|
|
972
|
-
} )
|
|
973
|
-
);
|
|
974
|
-
|
|
975
|
-
// Generate combined stylesheet from all CSS modules
|
|
976
|
-
if ( cssResults.length > 0 ) {
|
|
977
|
-
const combinedCss = cssResults.join( '\n' );
|
|
978
|
-
await mkdir( buildStyleDir, { recursive: true } );
|
|
979
|
-
await writeFile( path.join( buildStyleDir, 'style.css' ), combinedCss );
|
|
980
|
-
}
|
|
981
|
-
|
|
982
972
|
// Process SCSS files
|
|
983
973
|
await Promise.all(
|
|
984
974
|
scssEntries.map( async ( styleEntryPath ) => {
|
|
@@ -1097,6 +1087,135 @@ function getPackageName( filename ) {
|
|
|
1097
1087
|
return null;
|
|
1098
1088
|
}
|
|
1099
1089
|
|
|
1090
|
+
/**
|
|
1091
|
+
* Build a single route's files.
|
|
1092
|
+
*
|
|
1093
|
+
* @param {string} routeName Route name.
|
|
1094
|
+
* @return {Promise<number>} Build time in milliseconds.
|
|
1095
|
+
*/
|
|
1096
|
+
async function buildRoute( routeName ) {
|
|
1097
|
+
const startTime = Date.now();
|
|
1098
|
+
const routeDir = path.join( ROOT_DIR, 'routes', routeName );
|
|
1099
|
+
const outputDir = path.join( BUILD_DIR, 'routes', routeName );
|
|
1100
|
+
|
|
1101
|
+
// Ensure output directory exists
|
|
1102
|
+
await mkdir( outputDir, { recursive: true } );
|
|
1103
|
+
|
|
1104
|
+
// Copy package.json
|
|
1105
|
+
await copyFile(
|
|
1106
|
+
path.join( routeDir, 'package.json' ),
|
|
1107
|
+
path.join( outputDir, 'package.json' )
|
|
1108
|
+
);
|
|
1109
|
+
|
|
1110
|
+
const files = getRouteFiles( routeDir );
|
|
1111
|
+
|
|
1112
|
+
// Build route.js if it exists
|
|
1113
|
+
if ( files.hasRoute ) {
|
|
1114
|
+
const routeEntryPoints = await glob( `route.${ SOURCE_EXTENSIONS }`, {
|
|
1115
|
+
cwd: routeDir,
|
|
1116
|
+
absolute: true,
|
|
1117
|
+
} );
|
|
1118
|
+
|
|
1119
|
+
if ( routeEntryPoints.length > 0 ) {
|
|
1120
|
+
const routePlugins = [
|
|
1121
|
+
wordpressExternalsPlugin( 'route.min', 'esm' ),
|
|
1122
|
+
];
|
|
1123
|
+
|
|
1124
|
+
// Build both minified and non-minified versions in parallel
|
|
1125
|
+
await Promise.all( [
|
|
1126
|
+
esbuild.build( {
|
|
1127
|
+
entryPoints: routeEntryPoints,
|
|
1128
|
+
outfile: path.join( outputDir, 'route.min.js' ),
|
|
1129
|
+
bundle: true,
|
|
1130
|
+
format: 'esm',
|
|
1131
|
+
target: browserslistToEsbuild(),
|
|
1132
|
+
minify: true,
|
|
1133
|
+
define: getDefine( false ),
|
|
1134
|
+
plugins: routePlugins,
|
|
1135
|
+
} ),
|
|
1136
|
+
esbuild.build( {
|
|
1137
|
+
entryPoints: routeEntryPoints,
|
|
1138
|
+
outfile: path.join( outputDir, 'route.js' ),
|
|
1139
|
+
bundle: true,
|
|
1140
|
+
format: 'esm',
|
|
1141
|
+
target: browserslistToEsbuild(),
|
|
1142
|
+
minify: false,
|
|
1143
|
+
define: getDefine( true ),
|
|
1144
|
+
plugins: routePlugins,
|
|
1145
|
+
} ),
|
|
1146
|
+
] );
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// Build content.js if stage or inspector exists
|
|
1151
|
+
if ( files.hasStage || files.hasInspector ) {
|
|
1152
|
+
// Create synthetic entry point
|
|
1153
|
+
const syntheticEntry = generateContentEntryPoint( files );
|
|
1154
|
+
const tempEntryPath = path.join( routeDir, '.content-entry.js' );
|
|
1155
|
+
|
|
1156
|
+
// Write temporary entry file
|
|
1157
|
+
await writeFile( tempEntryPath, syntheticEntry );
|
|
1158
|
+
|
|
1159
|
+
const contentPlugins = [
|
|
1160
|
+
wordpressExternalsPlugin( 'content.min', 'esm' ),
|
|
1161
|
+
...styleBundlingPlugins,
|
|
1162
|
+
];
|
|
1163
|
+
|
|
1164
|
+
// Build both minified and non-minified versions in parallel
|
|
1165
|
+
await Promise.all( [
|
|
1166
|
+
esbuild.build( {
|
|
1167
|
+
entryPoints: [ tempEntryPath ],
|
|
1168
|
+
outfile: path.join( outputDir, 'content.min.js' ),
|
|
1169
|
+
bundle: true,
|
|
1170
|
+
format: 'esm',
|
|
1171
|
+
target: browserslistToEsbuild(),
|
|
1172
|
+
minify: true,
|
|
1173
|
+
define: getDefine( false ),
|
|
1174
|
+
plugins: contentPlugins,
|
|
1175
|
+
} ),
|
|
1176
|
+
esbuild.build( {
|
|
1177
|
+
entryPoints: [ tempEntryPath ],
|
|
1178
|
+
outfile: path.join( outputDir, 'content.js' ),
|
|
1179
|
+
bundle: true,
|
|
1180
|
+
format: 'esm',
|
|
1181
|
+
target: browserslistToEsbuild(),
|
|
1182
|
+
minify: false,
|
|
1183
|
+
define: getDefine( true ),
|
|
1184
|
+
plugins: contentPlugins,
|
|
1185
|
+
} ),
|
|
1186
|
+
] );
|
|
1187
|
+
|
|
1188
|
+
await unlink( tempEntryPath );
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
return Date.now() - startTime;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Build all discovered routes.
|
|
1196
|
+
*
|
|
1197
|
+
* @return {Promise<void>}
|
|
1198
|
+
*/
|
|
1199
|
+
async function buildAllRoutes() {
|
|
1200
|
+
console.log( '\n🚦 Phase 3: Building routes...\n' );
|
|
1201
|
+
|
|
1202
|
+
const routes = getAllRoutes( ROOT_DIR );
|
|
1203
|
+
|
|
1204
|
+
if ( routes.length === 0 ) {
|
|
1205
|
+
console.log( ' No routes found, skipping.\n' );
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
await Promise.all(
|
|
1210
|
+
routes.map( async ( routeName ) => {
|
|
1211
|
+
const buildTime = await buildRoute( routeName );
|
|
1212
|
+
console.log(
|
|
1213
|
+
` ✔ Built route ${ routeName } (${ buildTime }ms)`
|
|
1214
|
+
);
|
|
1215
|
+
} )
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1100
1219
|
/**
|
|
1101
1220
|
* Main build function.
|
|
1102
1221
|
*/
|
|
@@ -1159,6 +1278,9 @@ async function buildAll() {
|
|
|
1159
1278
|
} )
|
|
1160
1279
|
);
|
|
1161
1280
|
|
|
1281
|
+
// Build routes
|
|
1282
|
+
await buildAllRoutes();
|
|
1283
|
+
|
|
1162
1284
|
console.log( '\n📄 Generating PHP registration files...\n' );
|
|
1163
1285
|
const phpReplacements = await getPhpReplacements( ROOT_DIR );
|
|
1164
1286
|
await Promise.all( [
|
|
@@ -1167,6 +1289,17 @@ async function buildAll() {
|
|
|
1167
1289
|
generateScriptRegistrationPhp( scripts, phpReplacements ),
|
|
1168
1290
|
generateStyleRegistrationPhp( styles, phpReplacements ),
|
|
1169
1291
|
generateVersionPhp( phpReplacements ),
|
|
1292
|
+
generateRoutesRegistry(
|
|
1293
|
+
ROOT_DIR,
|
|
1294
|
+
BUILD_DIR,
|
|
1295
|
+
phpReplacements[ '{{PREFIX}}' ]
|
|
1296
|
+
),
|
|
1297
|
+
generateRoutesPhp(
|
|
1298
|
+
ROOT_DIR,
|
|
1299
|
+
BUILD_DIR,
|
|
1300
|
+
HANDLE_PREFIX,
|
|
1301
|
+
phpReplacements[ '{{PREFIX}}' ]
|
|
1302
|
+
),
|
|
1170
1303
|
] );
|
|
1171
1304
|
console.log( ' ✔ Generated build/modules.php' );
|
|
1172
1305
|
console.log( ' ✔ Generated build/modules/index.php' );
|
|
@@ -1175,6 +1308,7 @@ async function buildAll() {
|
|
|
1175
1308
|
console.log( ' ✔ Generated build/styles.php' );
|
|
1176
1309
|
console.log( ' ✔ Generated build/styles/index.php' );
|
|
1177
1310
|
console.log( ' ✔ Generated build/version.php' );
|
|
1311
|
+
console.log( ' ✔ Generated build/routes.php' );
|
|
1178
1312
|
console.log( ' ✔ Generated build/index.php' );
|
|
1179
1313
|
|
|
1180
1314
|
const totalTime = Date.now() - startTime;
|
|
@@ -1202,6 +1336,9 @@ async function watchMode() {
|
|
|
1202
1336
|
}
|
|
1203
1337
|
const allFullNames = Array.from( shortToFull.values() );
|
|
1204
1338
|
|
|
1339
|
+
// Get all routes for dependency tracking
|
|
1340
|
+
const allRoutes = getAllRoutes( ROOT_DIR );
|
|
1341
|
+
|
|
1205
1342
|
/**
|
|
1206
1343
|
* Rebuild a package and any affected scripts/modules.
|
|
1207
1344
|
*
|
|
@@ -1238,22 +1375,69 @@ async function watchMode() {
|
|
|
1238
1375
|
);
|
|
1239
1376
|
}
|
|
1240
1377
|
}
|
|
1378
|
+
|
|
1379
|
+
// Find and rebuild affected routes
|
|
1380
|
+
const affectedRoutes = findRoutesToRebuild(
|
|
1381
|
+
fullName,
|
|
1382
|
+
allFullNames,
|
|
1383
|
+
ROOT_DIR,
|
|
1384
|
+
allRoutes
|
|
1385
|
+
);
|
|
1386
|
+
|
|
1387
|
+
for ( const route of affectedRoutes ) {
|
|
1388
|
+
try {
|
|
1389
|
+
const rebuildStartTime = Date.now();
|
|
1390
|
+
await buildRoute( route );
|
|
1391
|
+
const rebuildTime = Date.now() - rebuildStartTime;
|
|
1392
|
+
console.log(
|
|
1393
|
+
`✅ routes/${ route } (rebuilt) (${ rebuildTime }ms)`
|
|
1394
|
+
);
|
|
1395
|
+
} catch ( error ) {
|
|
1396
|
+
console.log(
|
|
1397
|
+
`❌ routes/${ route } - Rebuild error: ${ error.message }`
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1241
1401
|
} catch ( error ) {
|
|
1242
1402
|
console.log( `❌ ${ packageName } - Error: ${ error.message }` );
|
|
1243
1403
|
}
|
|
1244
1404
|
}
|
|
1245
1405
|
|
|
1406
|
+
/**
|
|
1407
|
+
* Rebuild a route.
|
|
1408
|
+
*
|
|
1409
|
+
* @param {string} routeName Route to rebuild.
|
|
1410
|
+
*/
|
|
1411
|
+
async function rebuildRoute( routeName ) {
|
|
1412
|
+
try {
|
|
1413
|
+
const startTime = Date.now();
|
|
1414
|
+
await buildRoute( routeName );
|
|
1415
|
+
const buildTime = Date.now() - startTime;
|
|
1416
|
+
console.log( `✅ routes/${ routeName } (${ buildTime }ms)` );
|
|
1417
|
+
} catch ( error ) {
|
|
1418
|
+
console.log(
|
|
1419
|
+
`❌ routes/${ routeName } - Error: ${ error.message }`
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1246
1424
|
async function processNextRebuild() {
|
|
1247
1425
|
if ( needsRebuild.size === 0 ) {
|
|
1248
1426
|
isRebuilding = false;
|
|
1249
1427
|
return;
|
|
1250
1428
|
}
|
|
1251
1429
|
|
|
1252
|
-
const
|
|
1430
|
+
const itemsToRebuild = Array.from( needsRebuild );
|
|
1253
1431
|
needsRebuild.clear();
|
|
1254
1432
|
|
|
1255
|
-
for ( const
|
|
1256
|
-
|
|
1433
|
+
for ( const item of itemsToRebuild ) {
|
|
1434
|
+
// Check if it's a route (prefixed with 'route:')
|
|
1435
|
+
if ( item.startsWith( 'route:' ) ) {
|
|
1436
|
+
const routeName = item.slice( 6 ); // Remove 'route:' prefix
|
|
1437
|
+
await rebuildRoute( routeName );
|
|
1438
|
+
} else {
|
|
1439
|
+
await rebuildPackage( item );
|
|
1440
|
+
}
|
|
1257
1441
|
}
|
|
1258
1442
|
|
|
1259
1443
|
await processNextRebuild();
|
|
@@ -1315,6 +1499,54 @@ async function watchMode() {
|
|
|
1315
1499
|
watcher.on( 'change', handleFileChange );
|
|
1316
1500
|
watcher.on( 'add', handleFileChange );
|
|
1317
1501
|
watcher.on( 'unlink', handleFileChange );
|
|
1502
|
+
|
|
1503
|
+
// Watch route files if routes exist
|
|
1504
|
+
if ( allRoutes.length > 0 ) {
|
|
1505
|
+
const routeWatchPaths = allRoutes.map( ( routeName ) =>
|
|
1506
|
+
path.join( ROOT_DIR, 'routes', routeName )
|
|
1507
|
+
);
|
|
1508
|
+
|
|
1509
|
+
const routeWatcher = chokidar.watch( routeWatchPaths, {
|
|
1510
|
+
persistent: true,
|
|
1511
|
+
ignoreInitial: true,
|
|
1512
|
+
useFsEvents: true,
|
|
1513
|
+
depth: 10,
|
|
1514
|
+
awaitWriteFinish: {
|
|
1515
|
+
stabilityThreshold: 100,
|
|
1516
|
+
pollInterval: 50,
|
|
1517
|
+
},
|
|
1518
|
+
} );
|
|
1519
|
+
|
|
1520
|
+
routeWatcher.on( 'error', ( error ) => {
|
|
1521
|
+
console.error( '❌ Route watcher error:', error );
|
|
1522
|
+
} );
|
|
1523
|
+
|
|
1524
|
+
const handleRouteFileChange = async ( filename ) => {
|
|
1525
|
+
// Extract route name from path: routes/{routeName}/...
|
|
1526
|
+
const routeMatch = filename.match( /routes[/\\]([^/\\]+)[/\\]/ );
|
|
1527
|
+
if ( ! routeMatch ) {
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
const routeName = routeMatch[ 1 ];
|
|
1532
|
+
if ( ! allRoutes.includes( routeName ) ) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
if ( isRebuilding ) {
|
|
1537
|
+
needsRebuild.add( `route:${ routeName }` );
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
isRebuilding = true;
|
|
1542
|
+
await rebuildRoute( routeName );
|
|
1543
|
+
await processNextRebuild();
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
routeWatcher.on( 'change', handleRouteFileChange );
|
|
1547
|
+
routeWatcher.on( 'add', handleRouteFileChange );
|
|
1548
|
+
routeWatcher.on( 'unlink', handleRouteFileChange );
|
|
1549
|
+
}
|
|
1318
1550
|
}
|
|
1319
1551
|
|
|
1320
1552
|
/**
|