@ape-egg/vibe 1.6.1 → 1.7.1
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 +62 -2
- package/README.md +19 -10
- package/boot.js +11 -0
- package/compiler/native/vibe-compiler-darwin-arm64 +0 -0
- package/compiler/native/vibe-compiler-linux-x64 +0 -0
- package/compiler/src/Cargo.lock +67 -197
- package/compiler/src/Cargo.toml +2 -2
- package/compiler/src/compiler/compile.rs +136 -38
- package/compiler/src/compiler/component_tagger.rs +68 -40
- package/compiler/src/compiler/value_stamper.rs +75 -5
- package/compiler/src/compiler/watcher.rs +69 -2
- package/compiler/src/config.rs +10 -5
- package/compiler/src/main.rs +38 -25
- package/compiler/src/parser/html.rs +204 -87
- package/index.js +34 -5
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/runtime/cleanup.js +0 -9
- package/runtime/component.js +18 -20
- package/runtime/index.js +20 -2
- package/runtime/iterate.js +63 -15
- package/runtime/parse.js +3 -2
- package/runtime/pre-compiled-manifest.js +115 -58
|
@@ -328,7 +328,7 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
328
328
|
|
|
329
329
|
// Keep compiler and parser alive to reuse component cache across incremental compilations
|
|
330
330
|
let mut watch_compiler = Compiler::new(config.clone(), false);
|
|
331
|
-
let parser = {
|
|
331
|
+
let mut parser = {
|
|
332
332
|
use crate::parser::HtmlParser;
|
|
333
333
|
let mut p = HtmlParser::new(config.components_path());
|
|
334
334
|
if let Err(e) = p.load_elements() {
|
|
@@ -396,10 +396,52 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
396
396
|
let dependent_pages = graph.get_all_dependent_pages(&path_canonical);
|
|
397
397
|
if !dependent_pages.is_empty() {
|
|
398
398
|
println!("{} {} changed", "[watch]".cyan(), relative_path.display());
|
|
399
|
+
|
|
400
|
+
// Invalidate component cache so stale content isn't used
|
|
401
|
+
watch_compiler.clear_component_cache();
|
|
402
|
+
|
|
403
|
+
// Reload the changed component in the parser's element cache
|
|
404
|
+
// (used for custom element syntax like <Layout>)
|
|
405
|
+
if path.exists() {
|
|
406
|
+
let _ = parser.reload_element(path);
|
|
407
|
+
}
|
|
408
|
+
|
|
399
409
|
pages_to_recompile.extend(dependent_pages);
|
|
400
410
|
}
|
|
401
411
|
} else if let Some(ext) = path.extension() {
|
|
402
412
|
if ext == "html" {
|
|
413
|
+
// Check if file still exists (handle deletions)
|
|
414
|
+
if !path.exists() {
|
|
415
|
+
// File was deleted - clean up dependency graph
|
|
416
|
+
println!("{} {} deleted", "[watch]".yellow(), relative_path.display());
|
|
417
|
+
|
|
418
|
+
if let Some(old_deps) = graph.page_to_components.remove(path) {
|
|
419
|
+
for dep in old_deps {
|
|
420
|
+
if let Some(pages) = graph.component_to_pages.get_mut(&dep) {
|
|
421
|
+
pages.remove(path);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Delete corresponding compiled output
|
|
427
|
+
let output_path = canonical_output.join(relative_path);
|
|
428
|
+
if output_path.exists() {
|
|
429
|
+
if let Err(e) = std::fs::remove_file(&output_path) {
|
|
430
|
+
eprintln!("{}: Failed to delete {}: {}", "Warning".yellow(), output_path.display(), e);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Delete corresponding manifest
|
|
435
|
+
let manifest_path = canonical_output.join("vibe-hyperspeed").join(format!("{}.manifest.js", relative_path.display()));
|
|
436
|
+
if manifest_path.exists() {
|
|
437
|
+
if let Err(e) = std::fs::remove_file(&manifest_path) {
|
|
438
|
+
eprintln!("{}: Failed to delete manifest {}: {}", "Warning".yellow(), manifest_path.display(), e);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
403
445
|
// Page changed - recompile just this page
|
|
404
446
|
println!("{} {} changed", "[watch]".cyan(), relative_path.display());
|
|
405
447
|
pages_to_recompile.insert(path.clone());
|
|
@@ -431,7 +473,10 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
431
473
|
}
|
|
432
474
|
|
|
433
475
|
// Separate HTML files (from dependency graph) and CSS/JS assets (from changed_paths)
|
|
434
|
-
|
|
476
|
+
// Filter out deleted files
|
|
477
|
+
let html_files: Vec<PathBuf> = pages_to_recompile.into_iter()
|
|
478
|
+
.filter(|p| p.exists())
|
|
479
|
+
.collect();
|
|
435
480
|
|
|
436
481
|
let mut asset_files: Vec<PathBuf> = Vec::new();
|
|
437
482
|
for path in &changed_paths {
|
|
@@ -446,6 +491,24 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
446
491
|
continue;
|
|
447
492
|
}
|
|
448
493
|
|
|
494
|
+
// Handle deleted asset files
|
|
495
|
+
if !path.exists() {
|
|
496
|
+
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
|
|
497
|
+
if ext == "css" || ext == "js" {
|
|
498
|
+
let relative_path = path.strip_prefix(&config.source).unwrap_or(path);
|
|
499
|
+
let output_path = canonical_output.join(relative_path);
|
|
500
|
+
if output_path.exists() {
|
|
501
|
+
if let Err(e) = std::fs::remove_file(&output_path) {
|
|
502
|
+
eprintln!("{}: Failed to delete {}: {}", "Warning".yellow(), output_path.display(), e);
|
|
503
|
+
} else {
|
|
504
|
+
println!("{} {} deleted", "[watch]".yellow(), relative_path.display());
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
449
512
|
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
|
|
450
513
|
if ext == "css" || ext == "js" {
|
|
451
514
|
asset_files.push(path.clone());
|
|
@@ -482,6 +545,10 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
482
545
|
|
|
483
546
|
// Compile HTML files
|
|
484
547
|
if !html_files.is_empty() {
|
|
548
|
+
// Always clear component cache before recompiling so components
|
|
549
|
+
// are read fresh from disk (prevents stale cache from previous triggers)
|
|
550
|
+
watch_compiler.clear_component_cache();
|
|
551
|
+
|
|
485
552
|
match watch_compiler.compile_specific_html_files(&html_files, &parser) {
|
|
486
553
|
Ok(stats) => {
|
|
487
554
|
total_stats.files_compiled = stats.files_compiled;
|
package/compiler/src/config.rs
CHANGED
|
@@ -31,8 +31,6 @@ pub struct VibeCompilerConfig {
|
|
|
31
31
|
#[serde(default)]
|
|
32
32
|
pub elements_as_is: bool,
|
|
33
33
|
#[serde(default)]
|
|
34
|
-
pub validate: bool,
|
|
35
|
-
#[serde(default)]
|
|
36
34
|
pub source_maps: bool,
|
|
37
35
|
#[serde(default)]
|
|
38
36
|
pub reserved_elements: Vec<String>,
|
|
@@ -44,6 +42,10 @@ pub struct VibeCompilerConfig {
|
|
|
44
42
|
pub runtime_as_is: bool,
|
|
45
43
|
#[serde(default)]
|
|
46
44
|
pub iterations_as_is: bool,
|
|
45
|
+
#[serde(default)]
|
|
46
|
+
pub no_clean: bool,
|
|
47
|
+
#[serde(default)]
|
|
48
|
+
pub fouc_as_is: bool,
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
fn default_source() -> String { "./".to_string() }
|
|
@@ -92,13 +94,14 @@ impl Default for VibeCompilerConfig {
|
|
|
92
94
|
root: None,
|
|
93
95
|
minify: false,
|
|
94
96
|
elements_as_is: false,
|
|
95
|
-
validate: false,
|
|
96
97
|
source_maps: false,
|
|
97
98
|
reserved_elements: vec![],
|
|
98
99
|
node_modules_as_is: false,
|
|
99
100
|
components_as_is: false,
|
|
100
101
|
runtime_as_is: false,
|
|
101
102
|
iterations_as_is: false,
|
|
103
|
+
no_clean: false,
|
|
104
|
+
fouc_as_is: false,
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
}
|
|
@@ -115,13 +118,14 @@ pub struct Config {
|
|
|
115
118
|
pub _root: Option<String>,
|
|
116
119
|
pub minify: bool,
|
|
117
120
|
pub elements_as_is: bool,
|
|
118
|
-
pub validate: bool,
|
|
119
121
|
pub source_maps: bool,
|
|
120
122
|
pub reserved_elements: Vec<String>,
|
|
121
123
|
pub node_modules_as_is: bool,
|
|
122
124
|
pub components_as_is: bool,
|
|
123
125
|
pub runtime_as_is: bool,
|
|
124
126
|
pub iterations_as_is: bool,
|
|
127
|
+
pub no_clean: bool,
|
|
128
|
+
pub fouc_as_is: bool,
|
|
125
129
|
pub working_dir: PathBuf,
|
|
126
130
|
}
|
|
127
131
|
|
|
@@ -161,13 +165,14 @@ impl Config {
|
|
|
161
165
|
_root: config.root,
|
|
162
166
|
minify: config.minify,
|
|
163
167
|
elements_as_is: config.elements_as_is,
|
|
164
|
-
validate: config.validate,
|
|
165
168
|
source_maps: config.source_maps,
|
|
166
169
|
reserved_elements,
|
|
167
170
|
node_modules_as_is: config.node_modules_as_is,
|
|
168
171
|
components_as_is: config.components_as_is,
|
|
169
172
|
runtime_as_is: config.runtime_as_is,
|
|
170
173
|
iterations_as_is: config.iterations_as_is,
|
|
174
|
+
no_clean: config.no_clean,
|
|
175
|
+
fouc_as_is: config.fouc_as_is,
|
|
171
176
|
working_dir,
|
|
172
177
|
}
|
|
173
178
|
}
|
package/compiler/src/main.rs
CHANGED
|
@@ -14,7 +14,6 @@ use compiler::Compiler;
|
|
|
14
14
|
struct ConfigOverrides {
|
|
15
15
|
minify: bool,
|
|
16
16
|
elements_as_is: bool,
|
|
17
|
-
validate: bool,
|
|
18
17
|
source_maps: bool,
|
|
19
18
|
node_modules_as_is: bool,
|
|
20
19
|
components_as_is: bool,
|
|
@@ -53,10 +52,6 @@ struct Args {
|
|
|
53
52
|
#[arg(long, name = "source-maps")]
|
|
54
53
|
source_maps: bool,
|
|
55
54
|
|
|
56
|
-
/// Validate HTML syntax
|
|
57
|
-
#[arg(long)]
|
|
58
|
-
validate: bool,
|
|
59
|
-
|
|
60
55
|
/// Initialize configuration in package.json
|
|
61
56
|
#[arg(long)]
|
|
62
57
|
init: bool,
|
|
@@ -84,6 +79,14 @@ struct Args {
|
|
|
84
79
|
/// Skip iteration optimization - use runtime DOM cloning instead of compiled batch functions
|
|
85
80
|
#[arg(long, name = "iterations-as-is")]
|
|
86
81
|
iterations_as_is: bool,
|
|
82
|
+
|
|
83
|
+
/// Skip cleaning output directory before compilation
|
|
84
|
+
#[arg(long, name = "no-clean", hide = true)]
|
|
85
|
+
no_clean: bool,
|
|
86
|
+
|
|
87
|
+
/// Keep FOUC prevention class/attribute in compiled output
|
|
88
|
+
#[arg(long, name = "fouc-as-is")]
|
|
89
|
+
fouc_as_is: bool,
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
fn main() {
|
|
@@ -119,7 +122,6 @@ fn main() {
|
|
|
119
122
|
// Store original config values before applying flag overrides
|
|
120
123
|
let original_minify = config.minify;
|
|
121
124
|
let original_elements_as_is = config.elements_as_is;
|
|
122
|
-
let original_validate = config.validate;
|
|
123
125
|
let original_source_maps = config.source_maps;
|
|
124
126
|
let original_node_modules_as_is = config.node_modules_as_is;
|
|
125
127
|
let original_components_as_is = config.components_as_is;
|
|
@@ -137,10 +139,6 @@ fn main() {
|
|
|
137
139
|
overrides.elements_as_is = !original_elements_as_is;
|
|
138
140
|
config.elements_as_is = true;
|
|
139
141
|
}
|
|
140
|
-
if args.validate {
|
|
141
|
-
overrides.validate = !original_validate;
|
|
142
|
-
config.validate = true;
|
|
143
|
-
}
|
|
144
142
|
if args.source_maps {
|
|
145
143
|
overrides.source_maps = !original_source_maps;
|
|
146
144
|
config.source_maps = true;
|
|
@@ -161,6 +159,12 @@ fn main() {
|
|
|
161
159
|
overrides.iterations_as_is = !original_iterations_as_is;
|
|
162
160
|
config.iterations_as_is = true;
|
|
163
161
|
}
|
|
162
|
+
if args.no_clean {
|
|
163
|
+
config.no_clean = true;
|
|
164
|
+
}
|
|
165
|
+
if args.fouc_as_is {
|
|
166
|
+
config.fouc_as_is = true;
|
|
167
|
+
}
|
|
164
168
|
|
|
165
169
|
if args.verbose {
|
|
166
170
|
println!("{}", format!("Vibe Compiler v{}", env!("CARGO_PKG_VERSION")).cyan().bold());
|
|
@@ -191,21 +195,30 @@ fn main() {
|
|
|
191
195
|
format!("{} (config: {})", value.to_string().green(), value.to_string().yellow())
|
|
192
196
|
}
|
|
193
197
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
println!(" {}: {}", format!("{:<
|
|
205
|
-
println!(" {}: {}", format!("{:<
|
|
206
|
-
println!(" {}: {}", format!("{:<
|
|
207
|
-
println!(" {}: {}", format!("{:<
|
|
208
|
-
println!(" {}: {}", format!("{:<
|
|
198
|
+
fn format_reserved_elements(elements: &[String]) -> String {
|
|
199
|
+
if elements.len() <= 2 {
|
|
200
|
+
format!("{:?}", elements)
|
|
201
|
+
} else {
|
|
202
|
+
let remaining = elements.len() - 2;
|
|
203
|
+
format!("[\"component\", \"div\", ... + {} more]", remaining)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Alphabetically ordered with padding (longest key is "reservedElements" = 16 chars)
|
|
208
|
+
println!(" {}: {}", format!("{:<16}", "assets").cyan(), format_value_no_flag(&config._assets));
|
|
209
|
+
println!(" {}: {}", format!("{:<16}", "components").cyan(), format_value_no_flag(&config.components));
|
|
210
|
+
println!(" {}: {}", format!("{:<16}", "componentsAsIs").cyan(), format_bool_with_flag(config.components_as_is, overrides.components_as_is, original_components_as_is));
|
|
211
|
+
println!(" {}: {}", format!("{:<16}", "elementsAsIs").cyan(), format_bool_with_flag(config.elements_as_is, overrides.elements_as_is, original_elements_as_is));
|
|
212
|
+
println!(" {}: {}", format!("{:<16}", "iterationsAsIs").cyan(), format_bool_with_flag(config.iterations_as_is, overrides.iterations_as_is, original_iterations_as_is));
|
|
213
|
+
println!(" {}: {}", format!("{:<16}", "minify").cyan(), format_bool_with_flag(config.minify, overrides.minify, original_minify));
|
|
214
|
+
println!(" {}: {}", format!("{:<16}", "nodeModulesAsIs").cyan(), format_bool_with_flag(config.node_modules_as_is, overrides.node_modules_as_is, original_node_modules_as_is));
|
|
215
|
+
println!(" {}: {}", format!("{:<16}", "output").cyan(), format_value_no_flag(&config._output_str));
|
|
216
|
+
println!(" {}: {}", format!("{:<16}", "pages").cyan(), format_value_no_flag(&config.pages));
|
|
217
|
+
println!(" {}: {}", format!("{:<16}", "reservedElements").cyan(), format_value_no_flag(format_reserved_elements(&config.reserved_elements)));
|
|
218
|
+
println!(" {}: {}", format!("{:<16}", "root").cyan(), format_value_no_flag(config._root.as_ref().map(|s| s.as_str()).unwrap_or("null")));
|
|
219
|
+
println!(" {}: {}", format!("{:<16}", "runtimeAsIs").cyan(), format_bool_with_flag(config.runtime_as_is, overrides.runtime_as_is, original_runtime_as_is));
|
|
220
|
+
println!(" {}: {}", format!("{:<16}", "source").cyan(), format_value_no_flag(&config._source_str));
|
|
221
|
+
println!(" {}: {}", format!("{:<16}", "sourceMaps").cyan(), format_bool_with_flag(config.source_maps, overrides.source_maps, original_source_maps));
|
|
209
222
|
println!();
|
|
210
223
|
} else {
|
|
211
224
|
// Show version in non-verbose mode
|