@ape-egg/vibe 2.1.1 → 2.1.3
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 +13 -0
- package/compiler/native/vibe-compiler-darwin-arm64 +0 -0
- package/compiler/native/vibe-compiler-linux-x64 +0 -0
- package/compiler/src/Cargo.lock +1 -1
- package/compiler/src/Cargo.toml +1 -1
- package/compiler/src/compiler/compile.rs +62 -13
- package/compiler/src/compiler/watcher.rs +10 -9
- package/compiler/src/config.rs +14 -2
- package/compiler/src/main.rs +10 -1
- package/package.json +1 -1
- package/runtime/pre-compiled-manifest.js +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.3] - 2026-06-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Compiler 1.8.2 → 1.9.0 — `skipFiles` config option** (`compiler/src/config.rs`, `compiler/src/compiler/compile.rs`, `compiler/src/compiler/watcher.rs`, `compiler/src/main.rs`) — projects can now add their own exclude patterns on top of the compiler's built-in skip list (test files, `*.config.js`, `node_modules`, dotfiles, build dirs). Like `reservedElements`, user values **append** to the built-ins rather than replacing them, so the sensible defaults always hold. `Config::load` merges the built-in `SKIP_FILES` const with the user array into one effective `config.skip_files`, which is now threaded into `should_skip_path` at every call site (compile pass + watch mode) instead of the function reading a hard-coded const. Matching: a bare name (`server`) matches any file or directory with that name; a pattern containing `*` is a glob (`**/*.bak`) matched against both filename and full path; dotfiles are always skipped. This removes the need for app-side post-build pruning of directories the deploy never serves (a backend `server/`, build `scripts/`, a stale `dist/`). Config-only (no CLI flag, like `reservedElements`); surfaced in `--verbose` output. Repro: `tests/compiler/skip-files`.
|
|
8
|
+
- Docs: the compiler **Configuration** page documents `skipFiles` (example config + full section) and adds two collapsible panels revealing the built-in `reservedElements` and `skipFiles` default lists.
|
|
9
|
+
|
|
10
|
+
## [2.1.2] - 2026-06-18
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Compiler 1.8.0 → 1.8.1 — `--minify` mangled tags whose attributes span multiple lines** (`compiler/src/compiler/compile.rs`) — `minify_html` joined trimmed source lines with no separator, so a newline *inside* a tag vanished instead of collapsing to a space. A multi-line `<meta name="viewport" content="...">` became `<metaname="viewport"content="...">`, which the downstream stamping stage then re-parsed into deeper garbage (`initial-scale="1.0,"`, `"`, a bogus `</metaname...>` close). The inter-line break is now collapsed to a single space like any other whitespace run; the existing `>\s+<` → `><` pass re-tightens genuine tag boundaries. Generic fix — applies to any multi-line tag or text node, not just `<meta>`. Repro: `tests/compiler/minify-meta`.
|
|
15
|
+
|
|
3
16
|
## [2.1.1] - 2026-06-18
|
|
4
17
|
|
|
5
18
|
### Added
|
|
Binary file
|
|
Binary file
|
package/compiler/src/Cargo.lock
CHANGED
package/compiler/src/Cargo.toml
CHANGED
|
@@ -12,6 +12,32 @@ use rayon::prelude::*;
|
|
|
12
12
|
use crate::config::Config;
|
|
13
13
|
use crate::parser::HtmlParser;
|
|
14
14
|
|
|
15
|
+
/// Map an output-relative HTML path to the URL path the runtime resolves a
|
|
16
|
+
/// manifest from. Strips the `root` dir (served at /) and collapses dynamic
|
|
17
|
+
/// `$param` segments to a `$` token, e.g. with root `pages`:
|
|
18
|
+
/// pages/armory.html -> armory.html
|
|
19
|
+
/// pages/the-arena/$id.html -> the-arena/$.html
|
|
20
|
+
fn manifest_url_path(relative_path: &str, root: Option<&str>) -> String {
|
|
21
|
+
let stripped = match root {
|
|
22
|
+
Some(r) if relative_path == r => "",
|
|
23
|
+
Some(r) if relative_path.starts_with(&format!("{}/", r)) => &relative_path[r.len() + 1..],
|
|
24
|
+
_ => relative_path,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
stripped
|
|
28
|
+
.split('/')
|
|
29
|
+
.map(|seg| match seg.strip_prefix('$') {
|
|
30
|
+
// $id.html -> $.html ; $id -> $
|
|
31
|
+
Some(rest) => match rest.find('.') {
|
|
32
|
+
Some(dot) => format!("${}", &rest[dot..]),
|
|
33
|
+
None => "$".to_string(),
|
|
34
|
+
},
|
|
35
|
+
None => seg.to_string(),
|
|
36
|
+
})
|
|
37
|
+
.collect::<Vec<_>>()
|
|
38
|
+
.join("/")
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
// =============================================================================
|
|
16
42
|
// MIRROR_MODE: Copy asset files from source to output as-is, preserving
|
|
17
43
|
// directory structure. HTML files are compiled separately.
|
|
@@ -38,7 +64,10 @@ const MIRROR_EXTENSIONS: &[&str] = &[
|
|
|
38
64
|
"json", "xml", "csv",
|
|
39
65
|
];
|
|
40
66
|
|
|
41
|
-
//
|
|
67
|
+
// Built-in files and directories to skip when walking source (supports glob
|
|
68
|
+
// patterns). User-supplied `skipFiles` are appended to these in Config::load,
|
|
69
|
+
// so the effective list lives on `config.skip_files` and is passed into
|
|
70
|
+
// should_skip_path() at every call site.
|
|
42
71
|
// Note: Output directory is checked dynamically (not hardcoded here)
|
|
43
72
|
// Note: Dotfiles are handled by starts_with('.') check in should_skip_path()
|
|
44
73
|
pub const SKIP_FILES: &[&str] = &[
|
|
@@ -53,20 +82,21 @@ pub const SKIP_FILES: &[&str] = &[
|
|
|
53
82
|
"**/*.config.ts", // Config files
|
|
54
83
|
];
|
|
55
84
|
|
|
56
|
-
/// Check if a path should be skipped based on
|
|
57
|
-
|
|
85
|
+
/// Check if a path should be skipped based on the effective skip patterns
|
|
86
|
+
/// (built-in SKIP_FILES + user `skipFiles`, merged in Config::load).
|
|
87
|
+
pub fn should_skip_path(path: &Path, name: &str, patterns: &[String]) -> bool {
|
|
58
88
|
// Check if name starts with dot (dotfiles/directories)
|
|
59
89
|
if name.starts_with('.') {
|
|
60
90
|
return true;
|
|
61
91
|
}
|
|
62
92
|
|
|
63
93
|
// Check exact name match (for directories and simple filenames)
|
|
64
|
-
if
|
|
94
|
+
if patterns.iter().any(|p| p == name) {
|
|
65
95
|
return true;
|
|
66
96
|
}
|
|
67
97
|
|
|
68
98
|
// Check glob patterns (e.g., **/*.test.js)
|
|
69
|
-
for pattern_str in
|
|
99
|
+
for pattern_str in patterns {
|
|
70
100
|
if pattern_str.contains('*') {
|
|
71
101
|
if let Ok(pattern) = Pattern::new(pattern_str) {
|
|
72
102
|
// Try matching against just the filename
|
|
@@ -794,6 +824,7 @@ impl Compiler {
|
|
|
794
824
|
self.config.iterations_as_is,
|
|
795
825
|
self.config.components_as_is,
|
|
796
826
|
&self.config.source,
|
|
827
|
+
self.config.root.as_deref(),
|
|
797
828
|
) {
|
|
798
829
|
Ok(()) => {
|
|
799
830
|
pages_processed += 1;
|
|
@@ -826,6 +857,7 @@ impl Compiler {
|
|
|
826
857
|
iterations_as_is: bool,
|
|
827
858
|
components_as_is: bool,
|
|
828
859
|
source_root: &Path,
|
|
860
|
+
manifest_root: Option<&str>,
|
|
829
861
|
) -> Result<(), String> {
|
|
830
862
|
use crate::compiler::manifest_builder::ManifestBuilder;
|
|
831
863
|
use crate::compiler::component_tagger::ComponentTagger;
|
|
@@ -841,10 +873,17 @@ impl Compiler {
|
|
|
841
873
|
let manifest_builder = ManifestBuilder::new();
|
|
842
874
|
let manifest = manifest_builder.build_from_html(html, &state, iterations_as_is)?;
|
|
843
875
|
|
|
876
|
+
// Map the output-relative path to the served-URL path: drop the `root`
|
|
877
|
+
// dir (the folder served at /, e.g. `pages`) and collapse dynamic
|
|
878
|
+
// `$param` segments to a single `$` token. This lets the runtime resolve
|
|
879
|
+
// a manifest from a clean URL — `/armory` and `/the-arena/123` find
|
|
880
|
+
// `armory.html.manifest.js` and `the-arena/$.html.manifest.js`.
|
|
881
|
+
let manifest_rel = manifest_url_path(relative_path, manifest_root);
|
|
882
|
+
|
|
844
883
|
// Write manifest
|
|
845
884
|
let manifest_path = output_dir
|
|
846
885
|
.join("vibe-hyperspeed")
|
|
847
|
-
.join(format!("{}.manifest.js",
|
|
886
|
+
.join(format!("{}.manifest.js", manifest_rel));
|
|
848
887
|
|
|
849
888
|
// Ensure directory exists
|
|
850
889
|
if let Some(parent) = manifest_path.parent() {
|
|
@@ -857,7 +896,7 @@ impl Compiler {
|
|
|
857
896
|
|
|
858
897
|
let manifest_js = format!(
|
|
859
898
|
"// Pre-compiled manifest for /{}\n// Generated by Vibe compiler\n\nexport default {};\n",
|
|
860
|
-
|
|
899
|
+
manifest_rel,
|
|
861
900
|
manifest_json
|
|
862
901
|
);
|
|
863
902
|
|
|
@@ -901,6 +940,7 @@ impl Compiler {
|
|
|
901
940
|
let verbose = self.verbose;
|
|
902
941
|
let iterations_as_is = self.config.iterations_as_is;
|
|
903
942
|
let components_as_is = self.config.components_as_is;
|
|
943
|
+
let manifest_root = self.config.root.clone();
|
|
904
944
|
|
|
905
945
|
let results: Vec<_> = html_files
|
|
906
946
|
.par_iter()
|
|
@@ -917,7 +957,7 @@ impl Compiler {
|
|
|
917
957
|
};
|
|
918
958
|
|
|
919
959
|
// Try to generate manifest for this file (skip on error)
|
|
920
|
-
match Self::generate_file_manifest(&html, html_path, &output_dir, relative_path, verbose, iterations_as_is, components_as_is, &source_root) {
|
|
960
|
+
match Self::generate_file_manifest(&html, html_path, &output_dir, relative_path, verbose, iterations_as_is, components_as_is, &source_root, manifest_root.as_deref()) {
|
|
921
961
|
Ok(()) => (true, None),
|
|
922
962
|
Err(e) => {
|
|
923
963
|
if verbose {
|
|
@@ -974,7 +1014,7 @@ impl Compiler {
|
|
|
974
1014
|
}
|
|
975
1015
|
|
|
976
1016
|
// Skip special directories
|
|
977
|
-
if should_skip_path(&path, file_name) {
|
|
1017
|
+
if should_skip_path(&path, file_name, &self.config.skip_files) {
|
|
978
1018
|
continue;
|
|
979
1019
|
}
|
|
980
1020
|
|
|
@@ -1059,7 +1099,7 @@ impl Compiler {
|
|
|
1059
1099
|
}
|
|
1060
1100
|
|
|
1061
1101
|
// Skip special directories
|
|
1062
|
-
if should_skip_path(&path, file_name) {
|
|
1102
|
+
if should_skip_path(&path, file_name, &self.config.skip_files) {
|
|
1063
1103
|
continue;
|
|
1064
1104
|
}
|
|
1065
1105
|
|
|
@@ -1093,7 +1133,7 @@ impl Compiler {
|
|
|
1093
1133
|
self.process_directory_assets_only(&path, &new_relative, canonical_output, canonical_source, stats)?;
|
|
1094
1134
|
} else if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
|
|
1095
1135
|
// Skip files matching skip patterns
|
|
1096
|
-
if should_skip_path(&path, file_name) {
|
|
1136
|
+
if should_skip_path(&path, file_name, &self.config.skip_files) {
|
|
1097
1137
|
continue;
|
|
1098
1138
|
}
|
|
1099
1139
|
|
|
@@ -1546,7 +1586,7 @@ impl Compiler {
|
|
|
1546
1586
|
let file_name_str = file_name.to_string_lossy();
|
|
1547
1587
|
|
|
1548
1588
|
// Skip specific directories/patterns (includes dotfiles via SKIP_FILES)
|
|
1549
|
-
if should_skip_path(&path, &file_name_str) {
|
|
1589
|
+
if should_skip_path(&path, &file_name_str, &self.config.skip_files) {
|
|
1550
1590
|
continue;
|
|
1551
1591
|
}
|
|
1552
1592
|
|
|
@@ -1765,7 +1805,7 @@ impl Compiler {
|
|
|
1765
1805
|
let file_name = path.file_name().unwrap().to_str().unwrap();
|
|
1766
1806
|
|
|
1767
1807
|
// Skip files/directories matching skip patterns
|
|
1768
|
-
if should_skip_path(&path, file_name) {
|
|
1808
|
+
if should_skip_path(&path, file_name, &self.config.skip_files) {
|
|
1769
1809
|
continue;
|
|
1770
1810
|
}
|
|
1771
1811
|
|
|
@@ -1945,7 +1985,16 @@ fn minify_html(html: &str) -> String {
|
|
|
1945
1985
|
if in_pre {
|
|
1946
1986
|
result.push_str(line);
|
|
1947
1987
|
result.push('\n');
|
|
1988
|
+
last_was_space = false;
|
|
1948
1989
|
} else {
|
|
1990
|
+
// The line break preceding this line is whitespace: collapse it to a
|
|
1991
|
+
// single space so attributes/text split across lines don't glue
|
|
1992
|
+
// together (e.g. a multi-line <meta name=... content=...> tag).
|
|
1993
|
+
// The >\s+< pass below re-tightens genuine tag boundaries.
|
|
1994
|
+
if !last_was_space && !result.is_empty() {
|
|
1995
|
+
result.push(' ');
|
|
1996
|
+
last_was_space = true;
|
|
1997
|
+
}
|
|
1949
1998
|
for c in trimmed.chars() {
|
|
1950
1999
|
if c.is_whitespace() {
|
|
1951
2000
|
if !last_was_space {
|
|
@@ -128,11 +128,11 @@ fn to_kebab_case(s: &str) -> String {
|
|
|
128
128
|
|
|
129
129
|
/// Check if a path should be blacklisted based on SKIP_FILES patterns
|
|
130
130
|
/// This checks both the filename and all path components relative to source root
|
|
131
|
-
fn is_path_blacklisted(path: &Path, source_root: &Path) -> bool {
|
|
131
|
+
fn is_path_blacklisted(path: &Path, source_root: &Path, skip_files: &[String]) -> bool {
|
|
132
132
|
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
|
|
133
133
|
|
|
134
134
|
// Check filename against blacklist
|
|
135
|
-
if should_skip_path(path, file_name) {
|
|
135
|
+
if should_skip_path(path, file_name, skip_files) {
|
|
136
136
|
return true;
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -140,7 +140,7 @@ fn is_path_blacklisted(path: &Path, source_root: &Path) -> bool {
|
|
|
140
140
|
if let Ok(relative) = path.strip_prefix(source_root) {
|
|
141
141
|
for component in relative.components() {
|
|
142
142
|
if let Some(component_str) = component.as_os_str().to_str() {
|
|
143
|
-
if should_skip_path(path, component_str) {
|
|
143
|
+
if should_skip_path(path, component_str, skip_files) {
|
|
144
144
|
return true;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -159,7 +159,7 @@ pub fn build_dependency_graph(config: &Config) -> std::result::Result<Dependency
|
|
|
159
159
|
.unwrap_or_else(|_| config.output.clone());
|
|
160
160
|
|
|
161
161
|
// Scan all HTML files in source directory
|
|
162
|
-
scan_directory(&config.source, &config.source, &config.components, &canonical_output, &mut graph)?;
|
|
162
|
+
scan_directory(&config.source, &config.source, &config.components, &canonical_output, &config.skip_files, &mut graph)?;
|
|
163
163
|
|
|
164
164
|
Ok(graph)
|
|
165
165
|
}
|
|
@@ -169,6 +169,7 @@ fn scan_directory(
|
|
|
169
169
|
source_root: &Path,
|
|
170
170
|
components_dir: &str,
|
|
171
171
|
output_dir: &Path,
|
|
172
|
+
skip_files: &[String],
|
|
172
173
|
graph: &mut DependencyGraph,
|
|
173
174
|
) -> std::result::Result<(), std::io::Error> {
|
|
174
175
|
if !dir.is_dir() {
|
|
@@ -190,11 +191,11 @@ fn scan_directory(
|
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
// Skip directories using shared skip logic
|
|
193
|
-
if should_skip_path(&path, file_name) {
|
|
194
|
+
if should_skip_path(&path, file_name, skip_files) {
|
|
194
195
|
continue;
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
scan_directory(&path, source_root, components_dir, output_dir, graph)?;
|
|
198
|
+
scan_directory(&path, source_root, components_dir, output_dir, skip_files, graph)?;
|
|
198
199
|
} else if let Some(ext) = path.extension() {
|
|
199
200
|
if ext == "html" {
|
|
200
201
|
let html = std::fs::read_to_string(&path)?;
|
|
@@ -354,7 +355,7 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
354
355
|
for event in events {
|
|
355
356
|
for path in &event.paths {
|
|
356
357
|
// Skip blacklisted files/directories (check entire path, not just filename)
|
|
357
|
-
if is_path_blacklisted(path, &config.source) {
|
|
358
|
+
if is_path_blacklisted(path, &config.source, &config.skip_files) {
|
|
358
359
|
continue;
|
|
359
360
|
}
|
|
360
361
|
|
|
@@ -381,7 +382,7 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
381
382
|
}
|
|
382
383
|
|
|
383
384
|
// Skip blacklisted files/directories
|
|
384
|
-
if is_path_blacklisted(path, &config.source) {
|
|
385
|
+
if is_path_blacklisted(path, &config.source, &config.skip_files) {
|
|
385
386
|
continue;
|
|
386
387
|
}
|
|
387
388
|
|
|
@@ -487,7 +488,7 @@ pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn s
|
|
|
487
488
|
}
|
|
488
489
|
|
|
489
490
|
// Skip blacklisted files/directories
|
|
490
|
-
if is_path_blacklisted(path, &config.source) {
|
|
491
|
+
if is_path_blacklisted(path, &config.source, &config.skip_files) {
|
|
491
492
|
continue;
|
|
492
493
|
}
|
|
493
494
|
|
package/compiler/src/config.rs
CHANGED
|
@@ -35,6 +35,8 @@ pub struct VibeCompilerConfig {
|
|
|
35
35
|
#[serde(default)]
|
|
36
36
|
pub reserved_elements: Vec<String>,
|
|
37
37
|
#[serde(default)]
|
|
38
|
+
pub skip_files: Vec<String>,
|
|
39
|
+
#[serde(default)]
|
|
38
40
|
pub node_modules_as_is: bool,
|
|
39
41
|
#[serde(default)]
|
|
40
42
|
pub components_as_is: bool,
|
|
@@ -96,6 +98,7 @@ impl Default for VibeCompilerConfig {
|
|
|
96
98
|
elements_as_is: false,
|
|
97
99
|
source_maps: false,
|
|
98
100
|
reserved_elements: vec![],
|
|
101
|
+
skip_files: vec![],
|
|
99
102
|
node_modules_as_is: false,
|
|
100
103
|
components_as_is: false,
|
|
101
104
|
runtime_as_is: false,
|
|
@@ -115,11 +118,12 @@ pub struct Config {
|
|
|
115
118
|
pub components: String,
|
|
116
119
|
pub pages: String,
|
|
117
120
|
pub _assets: String,
|
|
118
|
-
pub
|
|
121
|
+
pub root: Option<String>,
|
|
119
122
|
pub minify: bool,
|
|
120
123
|
pub elements_as_is: bool,
|
|
121
124
|
pub source_maps: bool,
|
|
122
125
|
pub reserved_elements: Vec<String>,
|
|
126
|
+
pub skip_files: Vec<String>,
|
|
123
127
|
pub node_modules_as_is: bool,
|
|
124
128
|
pub components_as_is: bool,
|
|
125
129
|
pub runtime_as_is: bool,
|
|
@@ -154,6 +158,13 @@ impl Config {
|
|
|
154
158
|
let mut reserved_elements = get_default_reserved_elements();
|
|
155
159
|
reserved_elements.extend(config.reserved_elements);
|
|
156
160
|
|
|
161
|
+
// Combine built-in skip patterns with user-provided ones (append, not replace)
|
|
162
|
+
let mut skip_files: Vec<String> = crate::compiler::compile::SKIP_FILES
|
|
163
|
+
.iter()
|
|
164
|
+
.map(|s| s.to_string())
|
|
165
|
+
.collect();
|
|
166
|
+
skip_files.extend(config.skip_files);
|
|
167
|
+
|
|
157
168
|
Self {
|
|
158
169
|
source,
|
|
159
170
|
output,
|
|
@@ -162,11 +173,12 @@ impl Config {
|
|
|
162
173
|
components: config.components,
|
|
163
174
|
pages: config.pages,
|
|
164
175
|
_assets: config.assets,
|
|
165
|
-
|
|
176
|
+
root: config.root,
|
|
166
177
|
minify: config.minify,
|
|
167
178
|
elements_as_is: config.elements_as_is,
|
|
168
179
|
source_maps: config.source_maps,
|
|
169
180
|
reserved_elements,
|
|
181
|
+
skip_files,
|
|
170
182
|
node_modules_as_is: config.node_modules_as_is,
|
|
171
183
|
components_as_is: config.components_as_is,
|
|
172
184
|
runtime_as_is: config.runtime_as_is,
|
package/compiler/src/main.rs
CHANGED
|
@@ -204,6 +204,14 @@ fn main() {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
fn format_list_preview(items: &[String]) -> String {
|
|
208
|
+
if items.len() <= 2 {
|
|
209
|
+
format!("{:?}", items)
|
|
210
|
+
} else {
|
|
211
|
+
format!("[{:?}, {:?}, ... + {} more]", items[0], items[1], items.len() - 2)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
207
215
|
// Alphabetically ordered with padding (longest key is "reservedElements" = 16 chars)
|
|
208
216
|
println!(" {}: {}", format!("{:<16}", "assets").cyan(), format_value_no_flag(&config._assets));
|
|
209
217
|
println!(" {}: {}", format!("{:<16}", "components").cyan(), format_value_no_flag(&config.components));
|
|
@@ -215,8 +223,9 @@ fn main() {
|
|
|
215
223
|
println!(" {}: {}", format!("{:<16}", "output").cyan(), format_value_no_flag(&config._output_str));
|
|
216
224
|
println!(" {}: {}", format!("{:<16}", "pages").cyan(), format_value_no_flag(&config.pages));
|
|
217
225
|
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.
|
|
226
|
+
println!(" {}: {}", format!("{:<16}", "root").cyan(), format_value_no_flag(config.root.as_ref().map(|s| s.as_str()).unwrap_or("null")));
|
|
219
227
|
println!(" {}: {}", format!("{:<16}", "runtimeAsIs").cyan(), format_bool_with_flag(config.runtime_as_is, overrides.runtime_as_is, original_runtime_as_is));
|
|
228
|
+
println!(" {}: {}", format!("{:<16}", "skipFiles").cyan(), format_value_no_flag(format_list_preview(&config.skip_files)));
|
|
220
229
|
println!(" {}: {}", format!("{:<16}", "source").cyan(), format_value_no_flag(&config._source_str));
|
|
221
230
|
println!(" {}: {}", format!("{:<16}", "sourceMaps").cyan(), format_bool_with_flag(config.source_maps, overrides.source_maps, original_source_maps));
|
|
222
231
|
println!();
|
package/package.json
CHANGED
|
@@ -193,6 +193,17 @@ const detectHyperspeed = async () => {
|
|
|
193
193
|
);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// Strategy 4: dynamic routes. The compiler collapses a `$param` segment to a
|
|
197
|
+
// single `$` token (the-arena/$id.html -> the-arena/$.html.manifest.js), so a
|
|
198
|
+
// concrete URL only matches once its trailing segment is tokenized. Tried
|
|
199
|
+
// after the literal strategies, so static pages still win on an exact hit.
|
|
200
|
+
const dot = fileName.indexOf(".");
|
|
201
|
+
const tokenized = dot >= 0 ? "$" + fileName.slice(dot) : "$";
|
|
202
|
+
if (tokenized !== fileName) {
|
|
203
|
+
const dirPrefix = dirSegments.length ? `/${dirSegments.join("/")}` : "";
|
|
204
|
+
possiblePaths.push(`/vibe-hyperspeed${dirPrefix}/${tokenized}.manifest.js`);
|
|
205
|
+
}
|
|
206
|
+
|
|
196
207
|
if (!skipNetwork) {
|
|
197
208
|
// Fully-runtime dynamic import. Hidden behind `new Function` so any
|
|
198
209
|
// bundler's static-analysis can't read into it — there's nothing we
|