fix: automated tests

This commit is contained in:
Nathan Walker
2025-08-23 20:37:59 -07:00
parent ac7bcfbbf6
commit 9cce7578bd
5 changed files with 160 additions and 90 deletions

42
package-lock.json generated
View File

@@ -75,6 +75,7 @@
"postcss-loader": "^8.0.0", "postcss-loader": "^8.0.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"sass": "^1.72.0", "sass": "^1.72.0",
"sass-loader": "^16.0.0",
"shady-css-parser": "^0.1.0", "shady-css-parser": "^0.1.0",
"terser-webpack-plugin": "^5.0.0", "terser-webpack-plugin": "^5.0.0",
"tree-kill": "^1.2.2", "tree-kill": "^1.2.2",
@@ -24218,6 +24219,47 @@
"@parcel/watcher": "^2.4.1" "@parcel/watcher": "^2.4.1"
} }
}, },
"node_modules/sass-loader": {
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz",
"integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"neo-async": "^2.6.2"
},
"engines": {
"node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"@rspack/core": "0.x || 1.x",
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
"sass": "^1.3.0",
"sass-embedded": "*",
"webpack": "^5.0.0"
},
"peerDependenciesMeta": {
"@rspack/core": {
"optional": true
},
"node-sass": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"webpack": {
"optional": true
}
}
},
"node_modules/sass/node_modules/chokidar": { "node_modules/sass/node_modules/chokidar": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",

View File

@@ -82,6 +82,7 @@
"postcss-loader": "^8.0.0", "postcss-loader": "^8.0.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"sass": "^1.72.0", "sass": "^1.72.0",
"sass-loader": "^16.0.0",
"shady-css-parser": "^0.1.0", "shady-css-parser": "^0.1.0",
"terser-webpack-plugin": "^5.0.0", "terser-webpack-plugin": "^5.0.0",
"tree-kill": "^1.2.2", "tree-kill": "^1.2.2",

View File

@@ -1,10 +1,5 @@
import { extname, relative, resolve } from 'path'; import { extname, relative, resolve } from 'path';
import { import { ContextExclusionPlugin, HotModuleReplacementPlugin } from 'webpack';
ContextExclusionPlugin,
DefinePlugin,
HotModuleReplacementPlugin,
BannerPlugin,
} from 'webpack';
import Config from 'webpack-chain'; import Config from 'webpack-chain';
import { satisfies } from 'semver'; import { satisfies } from 'semver';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
@@ -23,6 +18,7 @@ import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin';
import { applyFileReplacements } from '../helpers/fileReplacements'; import { applyFileReplacements } from '../helpers/fileReplacements';
import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules';
import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin';
import { CompatDefinePlugin } from '../plugins/CompatDefinePlugin';
import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { applyDotEnvPlugin } from '../helpers/dotEnv';
import { env as _env, IWebpackEnv } from '../index'; import { env as _env, IWebpackEnv } from '../index';
import { getValue } from '../helpers/config'; import { getValue } from '../helpers/config';
@@ -545,7 +541,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
config config
.plugin('ContextExclusionPlugin|Other_Platforms') .plugin('ContextExclusionPlugin|Other_Platforms')
.use(ContextExclusionPlugin, [ .use(ContextExclusionPlugin, [
new RegExp(`\\.(${otherPlatformsRE})\\.(\\w+)$`), new RegExp(`\.(${otherPlatformsRE})\.(\w+)$`),
]); ]);
// Filter common undesirable warnings // Filter common undesirable warnings
@@ -565,31 +561,31 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
); );
// todo: refine defaults // todo: refine defaults
config.plugin('DefinePlugin').use(DefinePlugin, [ config.plugin('DefinePlugin').use(
{ CompatDefinePlugin as any,
__DEV__: mode === 'development', [
__NS_WEBPACK__: true, {
__NS_ENV_VERBOSE__: !!env.verbose, __DEV__: mode === 'development',
__NS_DEV_HOST_IPS__: __NS_WEBPACK__: true,
mode === 'development' ? JSON.stringify(getIPS()) : `[]`, __NS_ENV_VERBOSE__: !!env.verbose,
__CSS_PARSER__: JSON.stringify(getValue('cssParser', 'css-tree')), __NS_DEV_HOST_IPS__:
__UI_USE_XML_PARSER__: true, mode === 'development' ? JSON.stringify(getIPS()) : `[]`,
__UI_USE_EXTERNAL_RENDERER__: false, __CSS_PARSER__: JSON.stringify(getValue('cssParser', 'css-tree')),
__COMMONJS__: !!env.commonjs, __UI_USE_XML_PARSER__: true,
__ANDROID__: platform === 'android', __UI_USE_EXTERNAL_RENDERER__: false,
__IOS__: platform === 'ios', __COMMONJS__: !!env.commonjs,
__VISIONOS__: platform === 'visionos', __ANDROID__: platform === 'android',
__APPLE__: platform === 'ios' || platform === 'visionos', __IOS__: platform === 'ios',
/* for compat only */ 'global.isAndroid': platform === 'android', __VISIONOS__: platform === 'visionos',
/* for compat only */ 'global.isIOS': __APPLE__: platform === 'ios' || platform === 'visionos',
platform === 'ios' || platform === 'visionos', /* for compat only */ 'global.isAndroid': platform === 'android',
/* for compat only */ 'global.isVisionOS': platform === 'visionos', /* for compat only */ 'global.isIOS':
process: 'global.process', platform === 'ios' || platform === 'visionos',
/* for compat only */ 'global.isVisionOS': platform === 'visionos',
// todo: ?!?! process: 'global.process',
// profile: '() => {}', },
}, ] as any,
]); );
// enable DotEnv // enable DotEnv
applyDotEnvPlugin(config); applyDotEnvPlugin(config);

View File

@@ -0,0 +1,14 @@
export class CompatDefinePlugin {
private readonly definitions: Record<string, any>;
constructor(definitions: Record<string, any>) {
this.definitions = definitions || {};
}
apply(compiler: any) {
// Use the same webpack instance as the compiler to avoid version mismatches
const wp = compiler?.webpack || require('webpack');
const DefinePlugin = wp.DefinePlugin || require('webpack').DefinePlugin;
new DefinePlugin(this.definitions).apply(compiler);
}
}

View File

@@ -37,22 +37,28 @@ export class PlatformSuffixPlugin {
// require.context // require.context
compiler.hooks.contextModuleFactory.tap(id, (cmf) => { compiler.hooks.contextModuleFactory.tap(id, (cmf) => {
// @ts-ignore // @ts-ignore
cmf.hooks.alternativeRequests.tap(id, (modules, options) => { const altHook = (cmf as any).hooks?.alternativeRequests;
const additionalModules = []; if (altHook && typeof altHook.tap === 'function') {
// we are looking for modules that are platform specific (something.<platform>.ext) altHook.tap(id, (modules: any[], options: any) => {
// and we are duplicating them without the platform suffix const additionalModules = [];
// this allows using require.context with non-existent platformless filenames // we are looking for modules that are platform specific (something.<platform>.ext)
// but mapped to the platform specific variant (done in the resolver hook below) // and we are duplicating them without the platform suffix
for (const module of modules) { // this allows using require.context with non-existent platformless filenames
if (platformRE.test(module.request)) { // but mapped to the platform specific variant (done in the resolver hook below)
additionalModules.push({ for (const module of modules) {
...module, if (platformRE.test(module.request)) {
request: module.request.replace(platformRE, '.'), additionalModules.push({
}); ...module,
request: module.request.replace(platformRE, '.'),
});
}
} }
} modules.push(...additionalModules);
modules.push(...additionalModules); });
}); } else {
// Hook may be absent on some webpack versions; skip gracefully
// console.log(`[${id}] alternativeRequests hook not available; skipping.`)
}
}); });
compiler.resolverFactory.hooks.resolver compiler.resolverFactory.hooks.resolver
@@ -73,57 +79,68 @@ export class PlatformSuffixPlugin {
// }); // });
// }) // })
resolver.hooks.normalResolve.tapAsync( const normalResolveHook = (resolver as any).hooks?.normalResolve;
id, const ensureHook = (name: string) => {
(request_, resolveContext, callback) => { return typeof (resolver as any).ensureHook === 'function'
for (const platform of this.extensions) { ? (resolver as any).ensureHook(name)
const { path, request } = request_; : (resolver as any).hooks?.[name];
const ext = request && extname(request); };
const platformExt = ext ? `.${platform}${ext}` : '';
if (path && request && ext && !request.includes(platformExt)) { if (
const platformRequest = request.replace(ext, platformExt); !normalResolveHook ||
const extPath = resolve(path, platformRequest); typeof normalResolveHook.tapAsync !== 'function'
) {
// Missing or incompatible hook; skip to avoid crashes
return;
}
// console.log({ normalResolveHook.tapAsync(id, (request_, resolveContext, callback) => {
// path, for (const platform of this.extensions) {
// request, const { path, request } = request_;
// ext, const ext = request && extname(request);
// extPath const platformExt = ext ? `.${platform}${ext}` : '';
// })
// if a file with the same + a platform suffix exists if (path && request && ext && !request.includes(platformExt)) {
// we want to resolve that file instead const platformRequest = request.replace(ext, platformExt);
if (existsSync(extPath)) { const extPath = resolve(path, platformRequest);
const message = `resolving "${request}" to "${platformRequest}"`;
const hook = resolver.ensureHook('normalResolve');
console.log(message);
// here we are creating a new resolve object and replacing the path // console.log({
// with the .<platform>.<ext> suffix // path,
const obj = { // request,
...request_, // ext,
path: resolver.join(path, platformRequest), // extPath
relativePath: // })
request_.relativePath &&
resolver.join(request_.relativePath, platformRequest),
request: undefined,
};
// we call to the actual resolver to do the resolving of this new file // if a file with the same + a platform suffix exists
return resolver.doResolve( // we want to resolve that file instead
hook, if (existsSync(extPath)) {
obj, const message = `resolving "${request}" to "${platformRequest}"`;
message, const hook = ensureHook('normalResolve');
resolveContext,
callback // here we are creating a new resolve object and replacing the path
); // with the .<platform>.<ext> suffix
} const obj = {
...request_,
path: resolver.join(path, platformRequest),
relativePath:
request_.relativePath &&
resolver.join(request_.relativePath, platformRequest),
request: undefined,
};
// we call to the actual resolver to do the resolving of this new file
return (resolver as any).doResolve(
hook as any,
obj,
message,
resolveContext,
callback,
);
} }
} }
callback();
} }
); callback();
});
// resolver.hooks.rawFile.tap(id, (request, resolveContext, callback) => { // resolver.hooks.rawFile.tap(id, (request, resolveContext, callback) => {
// if(request.path && !/\.ios\..+$/.test(request.path)) { // if(request.path && !/\.ios\..+$/.test(request.path)) {
// const { ext } = parse(request.path) // const { ext } = parse(request.path)