Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
14b524b
[POC] Add Rspack config as a drop-in alternative to Webpack for web b…
roryabraham Jul 4, 2026
20fecb3
[POC] Migrate Storybook to Rsbuild and fully remove Webpack
roryabraham Jul 5, 2026
101a651
Remove webpack-era dev-server auto-restart crash recovery
roryabraham Jul 5, 2026
716ac26
Fix CI after merging main: Rspack warnings, spellcheck, gh-actions bu…
roryabraham Jul 6, 2026
12f7176
Rebuild isDeployChecklistLocked from a clean npm ci install
roryabraham Jul 6, 2026
aeadff3
Restore webpack override to neutralize react-web-config's legacy tran…
roryabraham Jul 6, 2026
69e809c
Polish Rspack/Rsbuild migration: DRY configs, drop html-webpack-plugin
roryabraham Jul 6, 2026
0146850
Fix knip and spellcheck failures
roryabraham Jul 6, 2026
cb9a1ca
Migrate web/Storybook builds from Rspack to Rsbuild
roryabraham Jul 7, 2026
1513562
Remove ForceGarbageCollectionPlugin - not needed under Rsbuild
roryabraham Jul 7, 2026
8f90005
Remove unused import/extensions eslint-disable in ModuleInitTimingPlugin
roryabraham Jul 7, 2026
305a2be
Replace webpack-bundle-analyzer with Rsdoctor
roryabraham Jul 7, 2026
a00f942
Restore dev PORT define for fallback ports
roryabraham Jul 8, 2026
a97eaad
perf(webpack): add Fullstory + OXC React Compiler webpack loaders
roryabraham Jun 18, 2026
4cb583f
fix(ci): fix ESLint, Prettier, spellcheck, knip, and Storybook failures
roryabraham Jun 18, 2026
c1aaf3d
chore: bump babel-plugin-react-compiler to 20260507 experimental
roryabraham Jul 5, 2026
8e2888d
fix(ci): pin babel-plugin-react-compiler to fix npm ci override conflict
roryabraham Jul 5, 2026
bfb0112
Fix CI: Storybook webpack, knip lockfile, spellcheck
roryabraham Jul 5, 2026
49bfeaa
Address knip/dependency fallout from combined OXC + Rsbuild migration
roryabraham Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title: React Compiler compliance

### Reasoning

React Compiler is enabled in this codebase (`babel-plugin-react-compiler` runs first in both webpack and metro configs). It automatically memoizes components and hooks at the AST level — analyzing data flow, tracking dependencies, and inserting fine-grained caching that is more precise than any hand-written `useMemo`, `useCallback`, or `React.memo`.
React Compiler is enabled in this codebase (`babel-plugin-react-compiler` runs first in both Rspack and metro configs). It automatically memoizes components and hooks at the AST level — analyzing data flow, tracking dependencies, and inserting fine-grained caching that is more precise than any hand-written `useMemo`, `useCallback`, or `React.memo`.

Manual memoization is therefore:

Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/playwright-app-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Use Playwright testing when:

Before using Playwright tools, verify the dev server is running:
```bash
ps aux | grep "webpack" | grep -v grep
ps aux | grep "rspack" | grep -v grep
```

**If server not running**: Inform user to start with `cd App && npm run web`
Expand All @@ -29,7 +29,7 @@ ps aux | grep "webpack" | grep -v grep

## Playwright Testing Workflow

1. **Verify server**: Check webpack process is running
1. **Verify server**: Check Rspack process is running
2. **Navigate**: Open `https://dev.new.expensify.com:8082/` in the browser
3. **Interact**: Use Playwright MCP tools to inspect, click, type, and navigate

Expand Down
73 changes: 48 additions & 25 deletions .github/actions/javascript/authorChecklist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3232,7 +3232,7 @@ exports.checkBypass = checkBypass;

/***/ }),

/***/ 5573:
/***/ 4244:
/***/ (function(module, __unused_webpack_exports, __nccwpck_require__) {

/* module decorator */ module = __nccwpck_require__.nmd(module);
Expand Down Expand Up @@ -16564,9 +16564,9 @@ class Buffer {
};
return result;
}
append(str, maybeNewline) {
append(str, maybeNewline, ignoreMapping = false) {
this._flush();
this._append(str, maybeNewline);
this._append(str, maybeNewline, ignoreMapping);
}
appendChar(char) {
this._flush();
Expand Down Expand Up @@ -16612,7 +16612,7 @@ class Buffer {
position.column = 0;
}
}
_append(str, maybeNewline) {
_append(str, maybeNewline, ignoreMapping) {
const len = str.length;
const position = this._position;
const sourcePos = this._sourcePosition;
Expand All @@ -16625,7 +16625,7 @@ class Buffer {
} else {
this._str += str;
}
const hasMap = this._map !== null;
const hasMap = !ignoreMapping && this._map !== null;
if (!maybeNewline && !hasMap) {
position.column += len;
return;
Expand Down Expand Up @@ -16709,13 +16709,16 @@ class Buffer {
_normalizePosition(prop, loc, columnOffset) {
this._flush();
const pos = loc[prop];
const target = this._sourcePosition;
if (pos) {
target.line = pos.line;
target.column = Math.max(pos.column + columnOffset, 0);
target.filename = loc.filename;
this.setSourcePosition(pos.line, Math.max(pos.column + columnOffset, 0));
this._sourcePosition.filename = loc.filename;
}
}
setSourcePosition(line, column) {
const target = this._sourcePosition;
target.line = line;
target.column = column;
}
getCurrentColumn() {
return this._position.column + (this._queuedChar ? 1 : 0);
}
Expand Down Expand Up @@ -21049,7 +21052,8 @@ class Printer {
const spacesCount = count > 0 ? column : column - this._buf.getCurrentColumn();
if (spacesCount > 0) {
const spaces = this._originalCode ? this._originalCode.slice(index - spacesCount, index).replace(/[^\t\x0B\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]/gu, " ") : " ".repeat(spacesCount);
this._append(spaces, false);
this._buf.append(spaces, false, true);
this._buf.setSourcePosition(line, column);
this.setLastChar(32);
}
}
Expand Down Expand Up @@ -21506,7 +21510,7 @@ Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
var _genMapping = __nccwpck_require__(5573);
var _genMapping = __nccwpck_require__(4244);
var _traceMapping = __nccwpck_require__(4817);
class SourceMap {
constructor(opts, code) {
Expand Down Expand Up @@ -21560,7 +21564,9 @@ class SourceMap {
line,
column: column
});
if (!originalMapping.name && identifierNamePos) {
if (originalMapping.name && (identifierNamePos || identifierName != null && originalMapping.column === column)) {
identifierName = originalMapping.name;
} else if (identifierNamePos) {
const originalIdentifierMapping = (0, _traceMapping.originalPositionFor)(this._inputMap, identifierNamePos);
if (originalIdentifierMapping.name) {
identifierName = originalIdentifierMapping.name;
Expand Down Expand Up @@ -24234,7 +24240,7 @@ var flow = superClass => class FlowParserMixin extends superClass {
}
flowParseDeclareVariable(node) {
this.next();
node.id = this.flowParseTypeAnnotatableIdentifier(true);
node.id = this.flowParseTypeAnnotatableIdentifier();
this.scope.declareName(node.id.name, 5, node.id.loc.start);
this.semicolon();
return this.finishNode(node, "DeclareVariable");
Expand Down Expand Up @@ -24408,9 +24414,14 @@ var flow = superClass => class FlowParserMixin extends superClass {
reservedType: word
});
}
flowParseRestrictedIdentifier(liberal, declaration) {
flowParseRestrictedIdentifierName(liberal, declaration) {
this.checkReservedType(this.state.value, this.state.startLoc, declaration);
return this.parseIdentifier(liberal);
return this.parseIdentifierName(liberal);
}
flowParseRestrictedIdentifier(liberal, declaration) {
const node = this.startNode();
const name = this.flowParseRestrictedIdentifierName(liberal, declaration);
return this.createIdentifier(node, name);
}
flowParseTypeAlias(node) {
node.id = this.flowParseRestrictedIdentifier(false, true);
Expand Down Expand Up @@ -24444,14 +24455,21 @@ var flow = superClass => class FlowParserMixin extends superClass {
this.semicolon();
return this.finishNode(node, "OpaqueType");
}
flowParseTypeParameterBound() {
if (this.match(14) || this.isContextual(81)) {
const node = this.startNode();
this.next();
node.typeAnnotation = this.flowParseType();
return this.finishNode(node, "TypeAnnotation");
}
}
flowParseTypeParameter(requireDefault = false) {
const nodeStartLoc = this.state.startLoc;
const node = this.startNode();
const variance = this.flowParseVariance();
const ident = this.flowParseTypeAnnotatableIdentifier();
node.name = ident.name;
node.name = this.flowParseRestrictedIdentifierName();
node.variance = variance;
node.bound = ident.typeAnnotation;
node.bound = this.flowParseTypeParameterBound();
if (this.match(29)) {
this.eat(29);
node.default = this.flowParseType();
Expand Down Expand Up @@ -25148,13 +25166,13 @@ var flow = superClass => class FlowParserMixin extends superClass {
node.typeAnnotation = this.flowParseTypeInitialiser();
return this.finishNode(node, "TypeAnnotation");
}
flowParseTypeAnnotatableIdentifier(allowPrimitiveOverride) {
const ident = allowPrimitiveOverride ? this.parseIdentifier() : this.flowParseRestrictedIdentifier();
flowParseTypeAnnotatableIdentifier() {
const node = this.startNode();
const name = this.parseIdentifierName();
if (this.match(14)) {
ident.typeAnnotation = this.flowParseTypeAnnotation();
this.resetEndLocation(ident);
node.typeAnnotation = this.flowParseTypeAnnotation();
}
return ident;
return this.createIdentifier(node, name);
}
typeCastToParameter(node) {
node.expression.typeAnnotation = node.typeAnnotation;
Expand Down Expand Up @@ -27381,6 +27399,7 @@ class CommentsParser extends BaseParser {
adjustInnerComments(node, node.properties, commentWS);
break;
case "CallExpression":
case "NewExpression":
case "OptionalCallExpression":
adjustInnerComments(node, node.arguments, commentWS);
break;
Expand All @@ -27393,6 +27412,7 @@ class CommentsParser extends BaseParser {
case "ObjectMethod":
case "ClassMethod":
case "ClassPrivateMethod":
case "TSTypeParameterDeclaration":
adjustInnerComments(node, node.params, commentWS);
break;
case "ArrayExpression":
Expand All @@ -27409,6 +27429,9 @@ class CommentsParser extends BaseParser {
case "TSEnumBody":
adjustInnerComments(node, node.members, commentWS);
break;
case "TSInterfaceBody":
adjustInnerComments(node, node.body, commentWS);
break;
default:
{
if (node.type === "RecordExpression") {
Expand Down Expand Up @@ -33711,7 +33734,7 @@ class ExpressionParser extends LValParser {
this.next();
return this.parseAsyncFunctionExpression(this.startNodeAtNode(id));
} else if (tokenIsIdentifier(type)) {
if (this.lookaheadCharCode() === 61) {
if (canBeArrow && this.lookaheadCharCode() === 61) {
return this.parseAsyncArrowUnaryFunction(this.startNodeAtNode(id));
} else {
return id;
Expand Down Expand Up @@ -43537,7 +43560,7 @@ function verify$1(visitor) {
}
if (shouldIgnoreKey(nodeType)) continue;
if (!TYPES.includes(nodeType)) {
throw new Error(`You gave us a visitor for the node type ${nodeType} but it's not a valid type in @babel/traverse ${"7.29.0"}`);
throw new Error(`You gave us a visitor for the node type ${nodeType} but it's not a valid type in @babel/traverse ${"7.29.7"}`);
}
const visitors = visitor[nodeType];
if (typeof visitors === "object") {
Expand Down
Loading
Loading