Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pubspec.lock
node_modules/
package-lock.json
*.log

docs/pakage_handler
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
Expand Down Expand Up @@ -37,3 +37,6 @@ packages/flutterjs_engine/dist/
.idea/
*.iml
pubspec_overrides.yaml

# ✅ NEW: Ignore build info files
**/.build_info.json
96 changes: 96 additions & 0 deletions PROJECT_HANDOVER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# FlutterJS Project Handover

## 🌟 Project Vision
**FlutterJS** is an experimental framework that brings the Flutter development experience to the web without the heavy runtime cost of CanvasKit or Wasm. Instead of drawing pixels to a canvas, **FlutterJS transpiles Dart code into idiomatic, readable JavaScript** that manipulates the DOM directly using a lightweight Virtual DOM (VNode) system.

**Goal**: Write Dart (Widgets, State, Logic) -> Run as optimized HTML/CSS/JS.

## 🏗️ System Architecture

The project consists of three main layers that work together to transform Dart code into a running web application:

### 1. The Compiler (Dart Side)
Located in `packages/flutterjs_tools` and `packages/flutterjs_gen`.
* **Role**: Analyzes Dart source code, extracts an Intermediate Representation (IR), and transpiles it to JavaScript.
* **Key Logic**:
* `IRGenerator`: Parses Dart code to understand classes, builds methods, and widget structures.
* `JSCodeGenerator`: Converts the IR into valid ES Module JavaScript.
* **Expression Handling**: Handles complex Dart concepts like `throw` expressions, `as` casts, and `??` operators during transpilation.

### 2. The Engine (Node.js Side)
Located in `packages/flutterjs_engine`.
* **Role**: Orchestrates the build process, manages dependencies, and serves the application.
* **Key Components**:
* **Build Pipeline**: Analyzing, Transforming, and Generating outputs.
* **Dev Server**: Express-based server with Hot Module Replacement (HMR) support.
* **Asset Generation**: Creates `index.html`, `app.js`, and `styles.css`.

### 3. The Runtime (Browser Side)
Located in `packages/flutterjs_runtime`, `packages/flutterjs_widgets`, `packages/flutterjs_material`, etc.
* **Role**: The JavaScript libraries that run in the browser.
* **Key Concepts**:
* **VNode System**: A lightweight virtual DOM implementation.
* **Widget Tree**: Replicates Flutter's widget tree structure (Stateless/Stateful).
* **Reconciliation**: Diffs VNodes to update the real DOM efficiently.

## 📂 Repository Structure

```text
flutterjs/
├── bin/ # Global CLI entry point (flutterjs.dart)
├── examples/ # Test applications
│ ├── counter/ # The canonical "Hello World"
│ └── pub_test_app/ # Complex dependency integration tests
├── packages/
│ ├── flutterjs_tools/ # Main Dart CLI & Transpiler logic
│ ├── flutterjs_engine/ # Node.js Build System & Dev Server
│ ├── flutterjs_gen/ # IR Generation & Code Gen utilities
│ ├── flutterjs_runtime/ # Core JS Runtime (runApp, setState)
│ ├── flutterjs_widgets/ # Base Widget implementations
│ ├── flutterjs_material/ # Material Design components
│ └── flutterjs_analyzer/ # JS-based Analysis tools
```

## 🚀 Workflows & Usage

### Standard Development Cycle
1. **Write Dart**: User writes standard Flutter code in `lib/`.
2. **Run CLI**: `dart bin/flutterjs.dart run --to-js --serve`.
3. **Transpilation**:
* CLI compiles Dart -> `.js` (ESM) in `build/flutterjs/src/`.
* CLI generates `flutterjs.config.js`.
4. **Serving**:
* Engine starts, reads config.
* Generates `app.js` (bootstrap) and `index.html`.
* Serves assets via localhost.

### Build Implementation Details
* **Direct JS Generation**: We now generate `.js` files directly (no intermediate `.fjs`).
* **Entry Point**: The system defaults to `src/main.js`.
* **Config**: `flutterjs.config.js` controls the engine's behavior.

## 📍 Current Technical Status

### ✅ What Works
* **Direct JS Transpilation**: `.dart` files are successfully converted to `.js` ES Modules.
* **Expression Support**: `throw`, `as`, `is`, `??` are correctly handled in JS.
* **Basic Widgets**: `Container`, `Column`, `Row`, `Text`, `Scaffold`, `AppBar`, `FloatingActionButton`.
* **State Management**: `setState` triggers re-renders via the VNode system.
* **Dev Server**: Starts, serves assets, and supports HMR signals.
* **Package Support**: Can compile dependencies like `collection` (with some caveats on complex exports).

### 🚧 Works in Progress / Limitations
* **Layout System**: Flex layout (Row/Column) is basic CSS-based; complex main/cross axis behavior may need tuning.
* **Dart Core Polyfills**: `dart:core` mapping is partial. Missing advanced `Map`, `Set`, or `List` methods might cause runtime errors.
* **Complex Dependencies**: Packages with heavy use of `dart:io` or `dart:isolate` will fail.

## 🐛 Known Issues / Debugging Tips
1. **"Entry file not found"**: Usually means `flutterjs.config.js` is stale (pointing to `.fjs`). **Fix**: Delete the config file and re-run the build.
2. **Engine Version Mismatch**: If `dart run` fails to start the server, it might be running a stale `flutterjs-win.exe`. **Fix**: Ensure `engine_bridge.dart` is prioritizing `packages/flutterjs_engine/bin/index.js` (Node source).
3. **Port Conflicts**: If the CLI crashes, the Node server might stay persistent. **Fix**: Kill the `node` process manually.
3. **Missing Imports**: If generated JS is missing imports, check `file_code_gen.dart` in `flutterjs_gen`.

## 🔮 Roadmap
1. **Complete Runtime Polyfills**: Solidify `@flutterjs/dart` to fully emulate Dart's core library behavior.
2. **Layout System V2**: Implement a more robust layout solver for `Stack`, `Positioned`, and advanced Flex scenarios.
3. **Production Minification**: Hook up `terser` or `esbuild` in the engine for production builds (`flutterjs build`).
43 changes: 21 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,32 +263,31 @@ flutterjs build --output ./dist # Custom output directory

Application renders in the browser. Good for SPAs.

```javascript
// flutter.config.js
module.exports = {
mode: 'csr'
};
```

### SSR (Server-Side Rendering)
### CSR (Client-Side Rendering) — Default

Pre-renders on server. Best for SEO.
Application renders entirely in the browser using JavaScript.
- **Best for**: Dynamic web apps, Dashboards, Admin panels.
- **CLI**: `flutterjs run --target spa` (or just `flutterjs run`)
- **Config**: `mode: 'csr'`

```javascript
module.exports = {
mode: 'ssr'
};
```
### SSR (Server-Side Rendering)

### Hybrid
Pre-renders HTML on the server (build time) and hydrates on the client.
- **Best for**: Marketing sites, Blogs, SEO-critical content.
- **CLI**: `flutterjs run --target ssr`
- **Config**: `mode: 'ssr'`
- **How it works**:
1. Build generates a pre-rendered `index.html`.
2. Client downloads HTML (instant paint).
3. Client hydrates (attaches event listeners).

SSR for initial load, CSR for interactions.
### Hybrid (Coming Soon)

```javascript
module.exports = {
mode: 'hybrid'
};
```
A mix of Static Site Generation (SSG) and SPA.
- **Best for**: Large sites with mixed content.
- **CLI**: `flutterjs run --target hybrid`
- **Config**: `mode: 'hybrid'`
- **Note**: Currently experimental. Use SSR for best SEO results.

---

Expand Down Expand Up @@ -348,7 +347,7 @@ FlutterJS supports the most commonly used Flutter widgets:

## Configuration

Create `flutter.config.js` in your project root:
Create `flutterjs.config.js` in your project root:

```javascript
module.exports = {
Expand Down
61 changes: 34 additions & 27 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
analyzer:
exclude:
- "**/builder/**"
- "**/.dart_tool/**"
- "**/build/**"
- "**/*.g.dart"
- "**/*.freezed.dart"
- "**/test/**" # Exclude all test directories
- "**/node_modules/**" # Exclude node_modules
- "packages/**/dist/**" # Exclude flutterjs_material dist
- "examples/**/build/**" # Exclude example build folders
- "**/*.js" # Exclude all JavaScript files
- "**/*.fjs" # Exclude ES modules

# Performance optimizations
language:
strict-casts: false
strict-inference: false
strict-raw-types: false

# Reduce analysis scope
errors:
# Downgrade some checks to improve speed
todo: ignore
deprecated_member_use: ignore

# Enable strong mode for better performance
strong-mode:
implicit-casts: true
implicit-dynamic: true

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
linter:
rules:
# Disable heavy lint rules if needed
# - avoid_print: false
42 changes: 3 additions & 39 deletions bin/flutterjs.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:flutterjs_tools/command.dart';
import 'package:flutterjs_dev_tools/dev_tools.dart';

/// ============================================================================
/// Flutter.js CLI Entry Point
Expand Down Expand Up @@ -99,13 +98,8 @@ const String kVersion = '2.0.0';
const String kAppName = 'Flutter.js';

Future<void> main(List<String> args) async {
final debugFile = File(
'c:/Jay/_Plugin/flutterjs/examples/routing_app/debug_main.txt',
);
debugFile.writeAsStringSync('DEBUG: BIN MAIN START\n');
print('DEBUG: BIN MAIN START');
print('🦖 FLUTTERJS CLI - DEBUG MODE ACTIVE 🦖');

print('--- [SANITY CHECK] FLUTTERJS CLI STARTING ---');
print('--- [SANITY CHECK] ARGS: $args ---');
// Parse verbose flags early
final bool veryVerbose = args.contains('-vv');
final bool verbose =
Expand Down Expand Up @@ -134,56 +128,26 @@ Future<void> main(List<String> args) async {
final bool muteCommandLogging = (help || doctor) && !veryVerbose;
final bool verboseHelp = help && verbose;

debugFile.writeAsStringSync(
'DEBUG: Parsed args. Creating runner...\n',
mode: FileMode.append,
);
// ✅ INITIALIZE DEBUGGER HERE
/*
FlutterJSIntegratedDebugger.initFromCliFlags(
verbose: verbose,
verboseHelp: veryVerbose,
watch: watch,
);
*/
// Create and run command runner
print('DEBUG: Creating runner...');
final runner = FlutterJSCommandRunner(
verbose: verbose,
verboseHelp: verboseHelp,
muteCommandLogging: muteCommandLogging,
);
print('DEBUG: Runner created');
debugFile.writeAsStringSync('DEBUG: Runner created\n', mode: FileMode.append);

try {
print('DEBUG: Calling runner.run(args)...');
debugFile.writeAsStringSync(
'DEBUG: Calling runner.run(args)...\n',
mode: FileMode.append,
);
await runner.run(args);
print('DEBUG: runner.run(args) returned');
debugFile.writeAsStringSync(
'DEBUG: runner.run(args) returned\n',
mode: FileMode.append,
);
} on UsageException catch (e) {
print('${e.message}\n');
print(e.usage);
exit(64); // Command line usage error
} catch (e, st) {
debugFile.writeAsStringSync(
'ERROR: $e\nSTACK: $st\n',
mode: FileMode.append,
);
} catch (e) {
if (verbose) {
print('Error: $e');
} else {
print('Error: $e');
print('Run with -v for more details.');
}
debugger.printSummary(); // ✅ Print metrics on exit
exit(1);
}
}
2 changes: 1 addition & 1 deletion examples/flutterjs_website
Submodule flutterjs_website updated from dfe40a to f73e72
57 changes: 57 additions & 0 deletions examples/pub_test_app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
build/

# VS Code
.vscode/

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/coverage/

# FlutterJS Generated Artifacts - ✅ NEW
build/
.dev/
dist/
node_modules/
flutterjs.config.js
package.json
package-lock.json
public/index.html

# Generated JS files in source (if any)
src/**/*.js
!src/**/*.dart

# Symbolication related
app.*.symbols

# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp":"2026-01-28T23:23:07.989672","totalNodes":1,"totalEdges":0,"graph":{"totalNodes":1,"totalEdges":0,"nodes":{"C:\\Jay\\_Plugin\\flutterjs\\examples\\pub_test_app\\lib\\main.dart":{"dependencies":[],"dependents":[],"dependencyCount":0,"dependentCount":0,"transitiveDependencies":[],"transitiveDependents":[]}},"cycles":[],"statistics":{"avgDependenciesPerFile":0.0,"cycleCount":0}},"topologicalOrder":["C:\\Jay\\_Plugin\\flutterjs\\examples\\pub_test_app\\lib\\main.dart"],"hasCircularDependencies":false}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp":"2026-01-28T23:23:08.000483","internalImports":{},"externalImports":["package:uuid/uuid.dart"],"uniqueExternalCount":1}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"totalFiles":1,"processedFiles":1,"cachedFiles":0,"errorFiles":0,"durationMs":0,"changedFiles":1,"cacheHitRate":0.0,"errorRate":0.0,"avgTimePerFile":0.0,"throughput":0.0,"timestamp":"2026-01-28T23:23:08.007468","reportPath":"C:\\Jay\\_Plugin\\flutterjs\\examples\\pub_test_app\\build\\analysis_output"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp":"2026-01-28T23:23:08.003514","projectPath":"C:\\Jay\\_Plugin\\flutterjs\\examples\\pub_test_app","analysisDuration":"0ms","summary":{"totalFiles":1,"processedFiles":1,"errorFiles":0,"changedFiles":1,"errorRate":"0.0%"},"performance":{"avgTimePerFile":"0.00ms","throughput":"0 files/sec"},"output":{"dependencyGraphFile":"dependencies/graph.json","typeRegistryFile":"types/registry.json","importAnalysisFile":"imports/analysis.json","statisticsFile":"reports/statistics.json","summaryFile":"reports/summary.json"}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp":"2026-01-28T23:23:07.995832","totalTypes":0,"types":[],"statistics":{"typesByKind":{},"typesByFile":{},"filesWithTypes":0}}
Loading
Loading