Skip to main content

nargo_bundler/
lib.rs

1#![warn(missing_docs)]
2
3use nargo_ir::{IRModule, JsExpr, JsStmt, TemplateNodeIR};
4use nargo_types::{CompileMode, Result};
5
6pub mod targets;
7use rayon::prelude::*;
8use std::{
9    collections::{HashMap, HashSet},
10    path::PathBuf,
11    sync::{Arc, Mutex},
12    thread,
13    time::SystemTime,
14};
15use targets::{js::JsBackend, CssBackend, DtsBackend, HtmlBackend};
16use ws::{listen, Handler, Handshake, Message, Result as WsResult};
17
18/// 文件指纹,用于检测文件变化
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct FileFingerprint {
21    /// 文件修改时间
22    pub modified_time: SystemTime,
23    /// 文件内容哈希
24    pub content_hash: u64,
25}
26
27/// 模块缓存项
28#[derive(Debug, Clone)]
29pub struct ModuleCache {
30    /// 模块的文件指纹
31    pub fingerprint: FileFingerprint,
32    /// 编译后的代码
33    pub compiled_code: String,
34    /// 模块的依赖列表
35    pub dependencies: HashSet<String>,
36    /// 模块的特征集
37    pub features: FeatureSet,
38}
39
40/// 代码分割策略枚举
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum SplitStrategy {
43    /// 单文件打包,不进行代码分割
44    SingleFile,
45    /// 按路由分割,每个路由生成一个 chunk
46    ByRoute,
47    /// 按组件分割,每个组件生成一个 chunk
48    ByComponent,
49    /// 自定义分割策略
50    Custom,
51}
52
53/// 代码生成目标格式枚举
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum OutputFormat {
56    /// JavaScript 代码
57    JavaScript,
58    /// CSS 代码
59    CSS,
60    /// HTML 代码
61    HTML,
62    /// TypeScript 类型定义
63    TypeScript,
64    /// WebAssembly 代码
65    WebAssembly,
66}
67
68/// 构建输出结果结构
69#[derive(Debug, Clone)]
70pub struct BuildOutput {
71    /// 生成的代码
72    pub code: Vec<u8>,
73    /// 输出格式
74    pub format: OutputFormat,
75    /// 文件名
76    pub filename: String,
77}
78
79/// 构建输出结果集合,用于代码分割
80#[derive(Debug, Clone)]
81pub struct BuildOutputs {
82    /// 输出文件集合
83    pub outputs: Vec<BuildOutput>,
84    /// 入口文件
85    pub entry_file: String,
86}
87
88/// 特征集,用于分析模块使用的功能
89#[derive(Debug, Clone, Default)]
90pub struct FeatureSet {
91    /// 是否使用了信号
92    pub has_signals: bool,
93    /// 是否使用了副作用
94    pub has_effects: bool,
95    /// 是否使用了虚拟 DOM
96    pub has_vdom: bool,
97    /// 是否使用了 SSR
98    pub has_ssr: bool,
99    /// 使用的核心函数
100    pub used_core_functions: HashSet<String>,
101    /// 使用的 DOM 函数
102    pub used_dom_functions: HashSet<String>,
103}
104
105impl FeatureSet {
106    /// 合并另一个特征集到当前集
107    pub fn merge(&mut self, other: &FeatureSet) {
108        self.has_signals |= other.has_signals;
109        self.has_effects |= other.has_effects;
110        self.has_vdom |= other.has_vdom;
111        self.has_ssr |= other.has_ssr;
112        self.used_core_functions.extend(other.used_core_functions.iter().cloned());
113        self.used_dom_functions.extend(other.used_dom_functions.iter().cloned());
114    }
115}
116
117/// HMR 服务器 WebSocket 处理器
118struct HmrHandler {
119    /// 连接列表
120    connections: Arc<Mutex<Vec<ws::Sender>>>,
121}
122
123impl Handler for HmrHandler {
124    fn on_open(&mut self, out: Handshake) -> WsResult<()> {
125        println!("HMR: Client connected");
126        // 将新连接添加到连接列表
127        // 简化实现,暂时不存储连接
128        Ok(())
129    }
130
131    fn on_message(&mut self, msg: Message) -> WsResult<()> {
132        println!("HMR: Received message: {:?}", msg);
133        Ok(())
134    }
135
136    fn on_close(&mut self, _code: ws::CloseCode, _reason: &str) {
137        println!("HMR: Client disconnected");
138        // 连接会自动关闭,不需要手动从列表中移除
139    }
140}
141
142/// Nargo 打包器,支持多格式代码生成、热模块替换和增量构建
143pub struct Bundler {
144    /// 特征集
145    pub feature_set: FeatureSet,
146    /// 运行时路径
147    pub runtime_path: Option<PathBuf>,
148    /// 是否启用热模块替换
149    pub hmr: bool,
150    /// HMR 端口
151    pub hmr_port: Option<u16>,
152    /// HMR 服务器运行状态
153    hmr_running: bool,
154    /// WebSocket 连接列表
155    connections: Arc<Mutex<Vec<ws::Sender>>>,
156    /// 模块缓存,键为模块名
157    module_cache: Arc<Mutex<HashMap<String, ModuleCache>>>,
158    /// 是否启用增量构建
159    incremental: bool,
160    /// 代码分割策略
161    split_strategy: SplitStrategy,
162    /// 是否启用动态导入支持
163    dynamic_import: bool,
164    /// 是否启用懒加载支持
165    lazy_loading: bool,
166}
167
168impl Bundler {
169    /// 创建新的打包器实例
170    pub fn new(runtime_path: Option<PathBuf>) -> Self {
171        Self { feature_set: FeatureSet::default(), runtime_path, hmr: false, hmr_port: None, hmr_running: false, connections: Arc::new(Mutex::new(vec![])), module_cache: Arc::new(Mutex::new(HashMap::new())), incremental: true, split_strategy: SplitStrategy::SingleFile, dynamic_import: false, lazy_loading: false }
172    }
173
174    /// 启用热模块替换
175    pub fn with_hmr(mut self, port: Option<u16>) -> Self {
176        self.hmr = true;
177        self.hmr_port = port;
178        self
179    }
180
181    /// 设置是否启用增量构建
182    pub fn with_incremental(mut self, incremental: bool) -> Self {
183        self.incremental = incremental;
184        self
185    }
186
187    /// 设置代码分割策略
188    pub fn with_split_strategy(mut self, strategy: SplitStrategy) -> Self {
189        self.split_strategy = strategy;
190        self
191    }
192
193    /// 设置是否启用动态导入支持
194    pub fn with_dynamic_import(mut self, dynamic_import: bool) -> Self {
195        self.dynamic_import = dynamic_import;
196        self
197    }
198
199    /// 设置是否启用懒加载支持
200    pub fn with_lazy_loading(mut self, lazy_loading: bool) -> Self {
201        self.lazy_loading = lazy_loading;
202        self
203    }
204
205    /// 计算文件指纹
206    fn compute_fingerprint(&self, module: &IRModule) -> FileFingerprint {
207        // 简单实现:使用模块名称和内容的哈希作为指纹
208        let content = format!("{}{:?}", module.name, module);
209        let content_hash = content.as_bytes().iter().fold(0u64, |acc, &b| acc.wrapping_mul(31).wrapping_add(b as u64));
210        FileFingerprint { modified_time: SystemTime::now(), content_hash }
211    }
212
213    /// 分析模块的依赖关系
214    fn analyze_dependencies(&self, module: &IRModule) -> HashSet<String> {
215        let mut dependencies = HashSet::new();
216
217        // 分析脚本中的导入
218        if let Some(script) = &module.script {
219            for stmt in &script.body {
220                self.analyze_stmt_for_dependencies(stmt, &mut dependencies);
221            }
222        }
223
224        if let Some(script) = &module.script_client {
225            for stmt in &script.body {
226                self.analyze_stmt_for_dependencies(stmt, &mut dependencies);
227            }
228        }
229
230        if let Some(script) = &module.script_server {
231            for stmt in &script.body {
232                self.analyze_stmt_for_dependencies(stmt, &mut dependencies);
233            }
234        }
235
236        dependencies
237    }
238
239    /// 分析语句中的依赖关系
240    fn analyze_stmt_for_dependencies(&self, stmt: &JsStmt, dependencies: &mut HashSet<String>) {
241        // 这里需要实现具体的依赖分析逻辑
242        // 暂时返回空集合
243    }
244
245    /// 并行分析所有模块的特征
246    pub fn analyze_all(&mut self, modules: &[IRModule]) {
247        let feature_set = Arc::new(Mutex::new(FeatureSet::default()));
248
249        modules.par_iter().for_each(|module| {
250            let mut local_features = FeatureSet::default();
251            self.analyze_module_into(module, &mut local_features);
252            let mut global_features = feature_set.lock().unwrap();
253            global_features.merge(&local_features);
254        });
255
256        self.feature_set = Arc::try_unwrap(feature_set).unwrap().into_inner().unwrap();
257    }
258
259    /// 分析单个模块的特征
260    fn analyze_module_into(&self, module: &IRModule, features: &mut FeatureSet) {
261        // 1. 分析模板中的 VDOM 和特定指令
262        if let Some(template) = &module.template {
263            if !template.nodes.is_empty() {
264                features.has_vdom = true;
265                features.used_dom_functions.insert("h".to_string());
266            }
267            for node in &template.nodes {
268                self.analyze_node_into(node, features);
269            }
270        }
271
272        // 2. 分析脚本中的响应式和核心函数
273        if let Some(script) = &module.script {
274            for stmt in &script.body {
275                self.analyze_stmt_into(stmt, features);
276            }
277        }
278
279        if let Some(script) = &module.script_client {
280            for stmt in &script.body {
281                self.analyze_stmt_into(stmt, features);
282            }
283        }
284
285        if let Some(script) = &module.script_server {
286            for stmt in &script.body {
287                self.analyze_stmt_into(stmt, features);
288                features.has_ssr = true;
289            }
290        }
291    }
292
293    /// 分析语句中的特征
294    fn analyze_stmt_into(&self, stmt: &JsStmt, features: &mut FeatureSet) {
295        match stmt {
296            JsStmt::Expr(expr, _, _) => self.analyze_expr_into(expr, features),
297            JsStmt::VariableDecl { init, .. } => {
298                if let Some(expr) = init {
299                    self.analyze_expr_into(expr, features);
300                }
301            }
302            JsStmt::Return(expr, _, _) => {
303                if let Some(expr) = expr {
304                    self.analyze_expr_into(expr, features);
305                }
306            }
307            JsStmt::If { test, consequent, alternate, .. } => {
308                self.analyze_expr_into(test, features);
309                self.analyze_stmt_into(consequent, features);
310                if let Some(alt) = alternate {
311                    self.analyze_stmt_into(alt, features);
312                }
313            }
314            JsStmt::While { test, body, .. } => {
315                self.analyze_expr_into(test, features);
316                self.analyze_stmt_into(body, features);
317            }
318            JsStmt::For { init, test, update, body, .. } => {
319                if let Some(init) = init {
320                    self.analyze_stmt_into(init, features);
321                }
322                if let Some(test) = test {
323                    self.analyze_expr_into(test, features);
324                }
325                if let Some(update) = update {
326                    self.analyze_expr_into(update, features);
327                }
328                self.analyze_stmt_into(body, features);
329            }
330            JsStmt::Block(stmts, _, _) => {
331                for s in stmts {
332                    self.analyze_stmt_into(s, features);
333                }
334            }
335            JsStmt::FunctionDecl { body, .. } => {
336                for s in body {
337                    self.analyze_stmt_into(s, features);
338                }
339            }
340            JsStmt::Export { declaration, .. } => self.analyze_stmt_into(declaration, features),
341            _ => {}
342        }
343    }
344
345    /// 分析表达式中的特征
346    fn analyze_expr_into(&self, expr: &JsExpr, features: &mut FeatureSet) {
347        match expr {
348            JsExpr::Call { callee, args, .. } => {
349                if let JsExpr::Identifier(name, _, _) = &**callee {
350                    match name.as_str() {
351                        "signal" | "createSignal" => {
352                            features.has_signals = true;
353                            features.used_core_functions.insert(name.clone());
354                        }
355                        "effect" | "createEffect" => {
356                            features.has_effects = true;
357                            features.used_core_functions.insert(name.clone());
358                        }
359                        "computed" | "createComputed" => {
360                            features.has_signals = true;
361                            features.used_core_functions.insert(name.clone());
362                        }
363                        _ => {
364                            features.used_core_functions.insert(name.clone());
365                        }
366                    }
367                }
368                for arg in args {
369                    self.analyze_expr_into(arg, features);
370                }
371            }
372            JsExpr::Binary { left, right, .. } => {
373                self.analyze_expr_into(left, features);
374                self.analyze_expr_into(right, features);
375            }
376            JsExpr::Unary { argument, .. } => {
377                self.analyze_expr_into(argument, features);
378            }
379            JsExpr::Array(exprs, _, _) => {
380                for e in exprs {
381                    self.analyze_expr_into(e, features);
382                }
383            }
384            JsExpr::Object(map, _, _) => {
385                for e in map.values() {
386                    self.analyze_expr_into(e, features);
387                }
388            }
389            JsExpr::ArrowFunction { body, .. } => {
390                self.analyze_expr_into(body, features);
391            }
392            JsExpr::Conditional { test, consequent, alternate, .. } => {
393                self.analyze_expr_into(test, features);
394                self.analyze_expr_into(consequent, features);
395                self.analyze_expr_into(alternate, features);
396            }
397            JsExpr::TemplateLiteral { expressions, .. } => {
398                for e in expressions {
399                    self.analyze_expr_into(e, features);
400                }
401            }
402            _ => {}
403        }
404    }
405
406    /// 分析节点中的特征
407    fn analyze_node_into(&self, node: &TemplateNodeIR, features: &mut FeatureSet) {
408        match node {
409            TemplateNodeIR::Element(el) => {
410                for attr in &el.attributes {
411                    if let Some(ast) = &attr.value_ast {
412                        self.analyze_expr_into(ast, features);
413                    }
414                    // 检查指令
415                    if attr.is_directive {
416                        features.has_effects = true;
417                        features.used_core_functions.insert("createEffect".to_string());
418                    }
419                }
420                for child in &el.children {
421                    self.analyze_node_into(child, features);
422                }
423            }
424            TemplateNodeIR::Interpolation(expr) => {
425                features.has_effects = true;
426                features.used_core_functions.insert("createEffect".to_string());
427                if let Some(ast) = &expr.ast {
428                    self.analyze_expr_into(ast, features);
429                }
430            }
431            _ => {}
432        }
433    }
434
435    /// 生成自定义运行时
436    pub fn generate_custom_runtime(&self) -> String {
437        let mut runtime = String::new();
438        runtime.push_str("// Nargo Standalone Runtime\n\n");
439
440        runtime.push_str("const runtime = (function() {\n");
441        runtime.push_str("  const queue = [];\n");
442        runtime.push_str("  let isFlushing = false;\n");
443        runtime.push_str("  const p = Promise.resolve();\n");
444        runtime.push_str("  function nextTick(fn) { return fn ? p.then(fn) : p; }\n");
445        runtime.push_str("  function queueJob(job) { if (!queue.includes(job)) { queue.push(job); scheduleFlush(); } }\n");
446        runtime.push_str("  function scheduleFlush() { if (!isFlushing) { isFlushing = true; nextTick(flushJobs); } }\n");
447        runtime.push_str("  function flushJobs() { try { for (let i = 0; i < queue.length; i++) queue[i](); } finally { isFlushing = false; queue.length = 0; } }\n\n");
448
449        runtime.push_str("  let currentEffect = null;\n");
450        runtime.push_str("  function createSignal(v) {\n");
451        runtime.push_str("    let val = v;\n");
452        runtime.push_str("    const subs = new Set();\n");
453        runtime.push_str("    return [\n");
454        runtime.push_str("      () => { if (currentEffect) subs.add(currentEffect); return val; },\n");
455        runtime.push_str("      (n) => { if (!Object.is(val, n)) { val = n; subs.forEach(s => queueJob(s)); } }\n");
456        runtime.push_str(
457            "    ];
458",
459        );
460        runtime.push_str("  }\n\n");
461
462        runtime.push_str("  function createEffect(fn) {\n");
463        runtime.push_str("    const effect = () => {\n");
464        runtime.push_str("      const prev = currentEffect;\n");
465        runtime.push_str("      currentEffect = effect;\n");
466        runtime.push_str("      try { fn(); } finally { currentEffect = prev; }\n");
467        runtime.push_str(
468            "    };
469",
470        );
471        runtime.push_str("    effect();\n");
472        runtime.push_str("  }\n\n");
473
474        runtime.push_str("  function createComputed(fn) {\n");
475        runtime.push_str("    const [g, s] = createSignal();\n");
476        runtime.push_str("    createEffect(() => s(fn()));\n");
477        runtime.push_str("    return g;\n");
478        runtime.push_str("  }\n\n");
479
480        runtime.push_str("  function h(tag, props, ...children) { return { tag, props, children: children.flat() }; }\n");
481        runtime.push_str("  function createStaticVNode(html) { return { tag: 'div', props: { innerHTML: html }, children: [], isStatic: true }; }\n");
482
483        runtime.push_str("  function mountElement(vnode, container) {\n");
484        runtime.push_str("    if (typeof vnode === 'string' || typeof vnode === 'number') {\n");
485        runtime.push_str("      const el = document.createTextNode(vnode);\n");
486        runtime.push_str("      container.appendChild(el);\n");
487        runtime.push_str("      return el;\n");
488        runtime.push_str("    }\n");
489        runtime.push_str("    if (vnode.isStatic) {\n");
490        runtime.push_str("      const el = document.createElement(vnode.tag);\n");
491        runtime.push_str("      el.innerHTML = vnode.props.innerHTML;\n");
492        runtime.push_str("      const actualRoot = el.firstChild || el;\n");
493        runtime.push_str("      container.appendChild(actualRoot);\n");
494        runtime.push_str("      return actualRoot;\n");
495        runtime.push_str("    }\n");
496        runtime.push_str("    if (typeof vnode.tag === 'object') {\n");
497        runtime.push_str("      return renderComponent(vnode.tag, container);\n");
498        runtime.push_str("    }\n");
499        runtime.push_str("    const el = document.createElement(vnode.tag);\n");
500        runtime.push_str("    if (vnode.props) {\n");
501        runtime.push_str("      for (const [key, value] of Object.entries(vnode.props)) {\n");
502        runtime.push_str("        if (key.startsWith('on')) el.addEventListener(key.toLowerCase().slice(2), value);\n");
503        runtime.push_str("        else el.setAttribute(key, value);\n");
504        runtime.push_str("      }\n");
505        runtime.push_str("    }\n");
506        runtime.push_str("    vnode.children.forEach(child => mountElement(child, el));\n");
507        runtime.push_str("    container.appendChild(el);\n");
508        runtime.push_str("    return el;\n");
509        runtime.push_str("  }\n\n");
510
511        runtime.push_str("  function renderComponent(comp, container) {\n");
512        runtime.push_str("    const setupContext = { i18n: comp.i18n || {} };\n");
513        runtime.push_str("    const state = comp.setup ? comp.setup({}, setupContext) : {};\n");
514        runtime.push_str("    let rootEl = null;\n");
515        runtime.push_str("    createEffect(() => {\n");
516        runtime.push_str("      const vnode = comp.render(state);\n");
517        runtime.push_str("      if (rootEl) { container.removeChild(rootEl); }\n");
518        runtime.push_str("      rootEl = mountElement(vnode, container);\n");
519        runtime.push_str("    });\n");
520        runtime.push_str("    return rootEl;\n");
521        runtime.push_str("  }\n\n");
522
523        runtime.push_str("  function useI18n(i18n) {\n");
524        runtime.push_str("    return { t: (key, params) => {\n");
525        runtime.push_str("      let msg = (i18n.en && i18n.en[key]) || key;\n");
526        runtime.push_str("      if (params) Object.keys(params).forEach(k => msg = msg.replace(`{${k}}`, params[k]));\n");
527        runtime.push_str("      return msg;\n");
528        runtime.push_str("    }};\n");
529        runtime.push_str("  }\n\n");
530
531        runtime.push_str("  function lazy(loader) {\n");
532        runtime.push_str("    let component = null;\n");
533        runtime.push_str("    return {\n");
534        runtime.push_str("      setup() {\n");
535        runtime.push_str("        const [loading, setLoading] = createSignal(true);\n");
536        runtime.push_str("        const [error, setError] = createSignal(null);\n");
537        runtime.push_str("        \n");
538        runtime.push_str("        loader().then(mod => {\n");
539        runtime.push_str("          component = mod.default || mod;\n");
540        runtime.push_str("          setLoading(false);\n");
541        runtime.push_str("        }).catch(err => {\n");
542        runtime.push_str("          setError(err);\n");
543        runtime.push_str("          setLoading(false);\n");
544        runtime.push_str("        });\n");
545        runtime.push_str("        \n");
546        runtime.push_str("        return {\n");
547        runtime.push_str("          loading,\n");
548        runtime.push_str("          error,\n");
549        runtime.push_str("          component\n");
550        runtime.push_str("        };");
551        runtime.push_str("      },\n");
552        runtime.push_str("      render({ loading, error, component }) {\n");
553        runtime.push_str("        if (loading()) {\n");
554        runtime.push_str("          return h('div', null, 'Loading...');\n");
555        runtime.push_str("        }\n");
556        runtime.push_str("        if (error()) {\n");
557        runtime.push_str("          return h('div', null, `Error: ${error().message}`);\n");
558        runtime.push_str("        }\n");
559        runtime.push_str("        if (component) {\n");
560        runtime.push_str("          return h(component);\n");
561        runtime.push_str("        }\n");
562        runtime.push_str("        return null;\n");
563        runtime.push_str("      }\n");
564        runtime.push_str("    };");
565        runtime.push_str("  }\n\n");
566
567        runtime.push_str(
568            "  return { 
569",
570        );
571        runtime.push_str(
572            "    signal: createSignal, createSignal, 
573",
574        );
575        runtime.push_str(
576            "    effect: createEffect, createEffect, 
577",
578        );
579        runtime.push_str(
580            "    computed: createComputed, createComputed, 
581",
582        );
583        runtime.push_str(
584            "    nextTick, h, render: renderComponent, useI18n, createStaticVNode, lazy 
585",
586        );
587        runtime.push_str(
588            "  };
589",
590        );
591        runtime.push_str("})();\n\n");
592
593        runtime.push_str("const { signal, createSignal, effect, createEffect, computed, createComputed, nextTick, h, render, useI18n, createStaticVNode, lazy } = runtime;\n");
594        runtime.push_str("const t = useI18n({}).t;\n");
595
596        runtime
597    }
598
599    /// 生成 HMR 客户端代码
600    fn generate_hmr_client(&self) -> String {
601        let port = self.hmr_port.unwrap_or(3000);
602        let mut hmr_code = String::new();
603        hmr_code.push_str("// HMR Client\n\n");
604        hmr_code.push_str("// HMR 模块缓存\n");
605        hmr_code.push_str("window.__HMR_MODULES__ = window.__HMR_MODULES__ || {};\n");
606        hmr_code.push_str("window.__HMR_CLIENTS__ = window.__HMR_CLIENTS__ || [];\n");
607        hmr_code.push_str("\n");
608        hmr_code.push_str(&format!("const ws = new WebSocket('ws://localhost:{}');\n", port));
609        hmr_code.push_str("\n");
610        hmr_code.push_str("// 注册模块更新回调\n");
611        hmr_code.push_str("window.hmrRegisterModule = (moduleName, updateCallback) => {\n");
612        hmr_code.push_str("  window.__HMR_MODULES__[moduleName] = updateCallback;\n");
613        hmr_code.push_str("};\n");
614        hmr_code.push_str("\n");
615        hmr_code.push_str("// 发送模块注册信息\n");
616        hmr_code.push_str("window.hmrSendModuleInfo = () => {\n");
617        hmr_code.push_str("  if (ws.readyState === WebSocket.OPEN) {\n");
618        hmr_code.push_str("    ws.send(JSON.stringify({\n");
619        hmr_code.push_str("      type: 'register',\n");
620        hmr_code.push_str("      modules: Object.keys(window.__HMR_MODULES__)\n");
621        hmr_code.push_str("    }));\n");
622        hmr_code.push_str("  }\n");
623        hmr_code.push_str("};\n");
624        hmr_code.push_str("\n");
625        hmr_code.push_str("// 处理模块更新\n");
626        hmr_code.push_str("const handleModuleUpdate = async (moduleName, updateData) => {\n");
627        hmr_code.push_str("  console.log('HMR: Updating module', moduleName);\n");
628        hmr_code.push_str("  \n");
629        hmr_code.push_str("  try {\n");
630        hmr_code.push_str("    // 动态加载更新后的模块\n");
631        hmr_code.push_str("    const response = await fetch(`${moduleName}.js?_t=${Date.now()}`);\n");
632        hmr_code.push_str("    const code = await response.text();\n");
633        hmr_code.push_str("    \n");
634        hmr_code.push_str("    // 创建临时模块执行环境\n");
635        hmr_code.push_str("    const module = { exports: {} };\n");
636        hmr_code.push_str("    const require = (dep) => {\n");
637        hmr_code.push_str("      if (window.__HMR_MODULES__[dep]) {\n");
638        hmr_code.push_str("        return window.__HMR_MODULES__[dep];\n");
639        hmr_code.push_str("      }\n");
640        hmr_code.push_str("      throw new Error(`Module ${dep} not found`);\n");
641        hmr_code.push_str("    };\n");
642        hmr_code.push_str("    \n");
643        hmr_code.push_str("    // 执行模块代码\n");
644        hmr_code.push_str("    const exec = new Function('module', 'exports', 'require', code);\n");
645        hmr_code.push_str("    exec(module, module.exports, require);\n");
646        hmr_code.push_str("    \n");
647        hmr_code.push_str("    // 调用模块的更新回调\n");
648        hmr_code.push_str("    if (window.__HMR_MODULES__[moduleName]) {\n");
649        hmr_code.push_str("      window.__HMR_MODULES__[moduleName](module.exports);\n");
650        hmr_code.push_str("      console.log('HMR: Module updated successfully', moduleName);\n");
651        hmr_code.push_str("    }\n");
652        hmr_code.push_str("  } catch (error) {\n");
653        hmr_code.push_str("    console.error('HMR: Failed to update module', moduleName, error);\n");
654        hmr_code.push_str("    // 如果更新失败,回退到页面刷新\n");
655        hmr_code.push_str("    window.location.reload();\n");
656        hmr_code.push_str("  }\n");
657        hmr_code.push_str("};\n");
658        hmr_code.push_str("\n");
659        hmr_code.push_str("ws.onmessage = (event) => {\n");
660        hmr_code.push_str("  try {\n");
661        hmr_code.push_str("    const data = JSON.parse(event.data);\n");
662        hmr_code.push_str("    \n");
663        hmr_code.push_str("    switch (data.type) {\n");
664        hmr_code.push_str("      case 'update':\n");
665        hmr_code.push_str("        // 处理模块更新\n");
666        hmr_code.push_str("        handleModuleUpdate(data.module, data);\n");
667        hmr_code.push_str("        break;\n");
668        hmr_code.push_str("      case 'reload':\n");
669        hmr_code.push_str("        // 强制页面刷新\n");
670        hmr_code.push_str("        console.log('HMR: Reloading page');\n");
671        hmr_code.push_str("        window.location.reload();\n");
672        hmr_code.push_str("        break;\n");
673        hmr_code.push_str("      default:\n");
674        hmr_code.push_str("        console.log('HMR: Unknown message type', data.type);\n");
675        hmr_code.push_str("    }\n");
676        hmr_code.push_str("  } catch (error) {\n");
677        hmr_code.push_str("    console.error('HMR: Failed to process message', error);\n");
678        hmr_code.push_str("  }\n");
679        hmr_code.push_str("};\n");
680        hmr_code.push_str("\n");
681        hmr_code.push_str("ws.onopen = () => {\n");
682        hmr_code.push_str("  console.log('HMR: Connected');\n");
683        hmr_code.push_str("  // 发送模块注册信息\n");
684        hmr_code.push_str("  window.hmrSendModuleInfo();\n");
685        hmr_code.push_str("};\n");
686        hmr_code.push_str("\n");
687        hmr_code.push_str("ws.onclose = () => {\n");
688        hmr_code.push_str("  console.log('HMR: Connection closed');\n");
689        hmr_code.push_str("  // 尝试重连\n");
690        hmr_code.push_str("  setTimeout(() => {\n");
691        hmr_code.push_str("    console.log('HMR: Attempting to reconnect');\n");
692        hmr_code.push_str("    window.location.reload();\n");
693        hmr_code.push_str("  }, 1000);\n");
694        hmr_code.push_str("};\n");
695        hmr_code.push_str("\n");
696        hmr_code.push_str("ws.onerror = (error) => {\n");
697        hmr_code.push_str("  console.error('HMR: Connection error', error);\n");
698        hmr_code.push_str("};\n");
699        hmr_code
700    }
701
702    /// 启动 HMR 服务器
703    pub fn start_hmr_server(&mut self) -> Result<()> {
704        if !self.hmr || self.hmr_running {
705            return Ok(());
706        }
707
708        let port = self.hmr_port.unwrap_or(3000);
709        let connections = self.connections.clone();
710
711        thread::spawn(move || {
712            println!("HMR: Starting server on port {}", port);
713            if let Err(e) = listen(format!("127.0.0.1:{}", port), |_| HmrHandler { connections: connections.clone() }) {
714                println!("HMR: Server error: {:?}", e);
715            }
716        });
717
718        self.hmr_running = true;
719        Ok(())
720    }
721
722    /// 发送热更新通知
723    pub fn send_hmr_update(&self, module_name: &str) -> Result<()> {
724        let message = serde_json::json!({"type": "update", "module": module_name});
725        let message_str = message.to_string();
726
727        let mut connections = self.connections.lock().unwrap();
728        connections.retain(|conn| match conn.send(Message::text(message_str.clone())) {
729            Ok(_) => true,
730            Err(e) => {
731                println!("HMR: Failed to send update: {:?}", e);
732                false
733            }
734        });
735
736        Ok(())
737    }
738
739    /// 并行编译并链接所有模块,生成指定格式的代码
740    pub fn bundle_all(&mut self, modules: &[IRModule], format: OutputFormat) -> Result<BuildOutputs> {
741        match format {
742            OutputFormat::JavaScript => self.bundle_javascript(modules),
743            OutputFormat::CSS => self.bundle_css(modules),
744            OutputFormat::HTML => self.bundle_html(modules),
745            OutputFormat::TypeScript => self.bundle_typescript(modules),
746            OutputFormat::WebAssembly => self.bundle_wasm(modules),
747        }
748    }
749
750    /// 分析模块是否为路由组件
751    fn is_route_component(&self, module: &IRModule) -> bool {
752        // 检查模块是否包含路由相关的特征
753        if let Some(script) = &module.script {
754            for stmt in &script.body {
755                if self.analyze_stmt_for_route(stmt) {
756                    return true;
757                }
758            }
759        }
760        false
761    }
762
763    /// 分析语句是否包含路由相关代码
764    fn analyze_stmt_for_route(&self, stmt: &JsStmt) -> bool {
765        match stmt {
766            JsStmt::Expr(expr, _, _) => self.analyze_expr_for_route(expr),
767            JsStmt::VariableDecl { init, .. } => {
768                if let Some(expr) = init {
769                    self.analyze_expr_for_route(expr)
770                }
771                else {
772                    false
773                }
774            }
775            JsStmt::Return(expr, _, _) => {
776                if let Some(expr) = expr {
777                    self.analyze_expr_for_route(expr)
778                }
779                else {
780                    false
781                }
782            }
783            JsStmt::Block(stmts, _, _) => stmts.iter().any(|s| self.analyze_stmt_for_route(s)),
784            _ => false,
785        }
786    }
787
788    /// 分析表达式是否包含路由相关代码
789    fn analyze_expr_for_route(&self, expr: &JsExpr) -> bool {
790        match expr {
791            JsExpr::Call { callee, .. } => {
792                if let JsExpr::Identifier(name, _, _) = &**callee {
793                    // 检查是否使用了路由相关函数
794                    matches!(name.as_str(), "useRoute" | "useRouter" | "createRouter" | "createWebHistory" | "createWebHashHistory")
795                }
796                else {
797                    false
798                }
799            }
800            JsExpr::Object(map, _, _) => {
801                // 检查是否包含路由配置对象
802                map.contains_key("path") || map.contains_key("component") || map.contains_key("children")
803            }
804            _ => false,
805        }
806    }
807
808    /// 并行编译并链接所有模块,默认生成 JavaScript 代码
809    pub fn bundle_all_default(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
810        self.bundle_all(modules, OutputFormat::JavaScript)
811    }
812
813    /// 生成 JavaScript 代码
814    fn bundle_javascript(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
815        let updated_feature_set = Arc::new(Mutex::new(FeatureSet::default()));
816        let need_full_rebuild = Arc::new(Mutex::new(false));
817
818        // 1. 分析模块并检查缓存
819        let backend = JsBackend::new(false, false, None, CompileMode::Vue2);
820        let compiled_modules: Vec<Result<(String, String)>> = modules
821            .par_iter()
822            .map(|module| {
823                let mut module_needs_rebuild = false;
824                let mut module_features = FeatureSet::default();
825                let mut processed_code = String::new();
826
827                if self.incremental {
828                    let fingerprint = self.compute_fingerprint(module);
829                    let module_cache = self.module_cache.lock().unwrap();
830                    if let Some(cache) = module_cache.get(&module.name) {
831                        if cache.fingerprint == fingerprint {
832                            // 使用缓存的编译结果
833                            let mut features = updated_feature_set.lock().unwrap();
834                            features.merge(&cache.features);
835                            return Ok((module.name.clone(), cache.compiled_code.clone()));
836                        }
837                    }
838                    // 缓存未命中,需要重新编译
839                    module_needs_rebuild = true;
840                }
841
842                if module_needs_rebuild || !self.incremental {
843                    // 重新编译模块
844                    let (code, _) = backend.generate(module)?;
845
846                    // 后处理:移除模块化的导入导出,改为内部变量
847                    processed_code = code.replace("import {", "// import {").replace("} from '@nargo/core';", " } = runtime;").replace("} from '@nargo/dom';", " } = runtime;").replace("} from '@nargo/client';", " } = runtime;").replace("export default ", &format!("const {} = ", module.name));
848
849                    // 分析模块特征和依赖
850                    self.analyze_module_into(module, &mut module_features);
851                    let dependencies = self.analyze_dependencies(module);
852
853                    // 更新缓存
854                    if self.incremental {
855                        let fingerprint = self.compute_fingerprint(module);
856                        let mut cache = self.module_cache.lock().unwrap();
857                        cache.insert(module.name.clone(), ModuleCache { fingerprint, compiled_code: processed_code.clone(), dependencies, features: module_features.clone() });
858                    }
859
860                    // 更新全局特征集
861                    let mut features = updated_feature_set.lock().unwrap();
862                    features.merge(&module_features);
863
864                    // 标记需要完全重建
865                    let mut rebuild = need_full_rebuild.lock().unwrap();
866                    *rebuild = true;
867                }
868
869                Ok((module.name.clone(), processed_code))
870            })
871            .collect();
872
873        // 2. 更新全局特征集
874        let needs_rebuild = *need_full_rebuild.lock().unwrap();
875        if needs_rebuild || !self.incremental {
876            self.feature_set = Arc::try_unwrap(updated_feature_set).unwrap().into_inner().unwrap();
877        }
878
879        // 3. 生成运行时代码
880        let runtime_code = self.generate_custom_runtime();
881
882        // 4. 生成 HMR 客户端代码
883        let hmr_code = if self.hmr {
884            self.start_hmr_server()?;
885            self.generate_hmr_client()
886        }
887        else {
888            String::new()
889        };
890
891        // 5. 根据分割策略生成输出
892        match self.split_strategy {
893            SplitStrategy::SingleFile => {
894                // 单文件打包
895                let mut output = String::new();
896                output.push_str(&runtime_code);
897                output.push_str(&hmr_code);
898                output.push_str("\n// --- Components --\n");
899
900                for res in compiled_modules {
901                    let (name, code) = res?;
902                    output.push_str(&format!("\n// --- Component: {} --\n{}\n", name, code));
903                }
904
905                if let Some(main) = modules.first() {
906                    output.push_str(&format!("\n// --- Mount --\n"));
907                    output.push_str(&format!("render(h({}, null), document.getElementById('app') || document.body);\n", main.name));
908                }
909
910                let build_output = BuildOutput { code: output.into_bytes(), format: OutputFormat::JavaScript, filename: "bundle.js".to_string() };
911
912                Ok(BuildOutputs { outputs: vec![build_output], entry_file: "bundle.js".to_string() })
913            }
914            SplitStrategy::ByComponent => {
915                // 按组件分割
916                let mut outputs = Vec::new();
917
918                // 生成运行时文件
919                let runtime_output = BuildOutput { code: runtime_code.into_bytes(), format: OutputFormat::JavaScript, filename: "runtime.js".to_string() };
920                outputs.push(runtime_output);
921
922                // 生成 HMR 客户端文件
923                if !hmr_code.is_empty() {
924                    let hmr_output = BuildOutput { code: hmr_code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: "hmr.js".to_string() };
925                    outputs.push(hmr_output);
926                }
927
928                // 为每个组件生成单独的文件
929                for res in compiled_modules {
930                    let (name, code) = res?;
931                    let component_output = BuildOutput { code: code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: format!("{}.js", name) };
932                    outputs.push(component_output);
933                }
934
935                // 生成入口文件
936                let mut entry_code = String::new();
937                entry_code.push_str("// Entry Point\n");
938                entry_code.push_str("import './runtime.js';\n");
939                if !hmr_code.is_empty() {
940                    entry_code.push_str("import './hmr.js';\n");
941                }
942
943                for module in modules {
944                    entry_code.push_str(&format!("import {} from './{}.js';\n", module.name, module.name));
945                }
946
947                if let Some(main) = modules.first() {
948                    entry_code.push_str(&format!("\n// Mount\n"));
949                    entry_code.push_str(&format!("render(h({}, null), document.getElementById('app') || document.body);\n", main.name));
950                }
951
952                let entry_output = BuildOutput { code: entry_code.into_bytes(), format: OutputFormat::JavaScript, filename: "index.js".to_string() };
953                outputs.push(entry_output);
954
955                Ok(BuildOutputs { outputs, entry_file: "index.js".to_string() })
956            }
957            SplitStrategy::ByRoute => {
958                // 按路由分割
959                let mut outputs = Vec::new();
960                let mut route_components = Vec::new();
961                let mut regular_components = Vec::new();
962
963                // 生成运行时文件
964                let runtime_output = BuildOutput { code: runtime_code.into_bytes(), format: OutputFormat::JavaScript, filename: "runtime.js".to_string() };
965                outputs.push(runtime_output);
966
967                // 生成 HMR 客户端文件
968                if !hmr_code.is_empty() {
969                    let hmr_output = BuildOutput { code: hmr_code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: "hmr.js".to_string() };
970                    outputs.push(hmr_output);
971                }
972
973                // 分离路由组件和普通组件
974                for (i, module) in modules.iter().enumerate() {
975                    if self.is_route_component(module) {
976                        route_components.push((i, module));
977                    }
978                    else {
979                        regular_components.push((i, module));
980                    }
981                }
982
983                // 生成普通组件文件(共享 chunk)
984                let mut shared_code = String::new();
985                for (i, module) in &regular_components {
986                    if let Ok((name, code)) = &compiled_modules[*i] {
987                        shared_code.push_str(&format!("// Component: {}\n{}\n", name, code));
988                    }
989                }
990
991                if !shared_code.is_empty() {
992                    let shared_output = BuildOutput { code: shared_code.into_bytes(), format: OutputFormat::JavaScript, filename: "shared.js".to_string() };
993                    outputs.push(shared_output);
994                }
995
996                // 为每个路由组件生成单独的文件
997                for (i, module) in &route_components {
998                    if let Ok((name, code)) = &compiled_modules[*i] {
999                        let route_output = BuildOutput { code: code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: format!("route-{}.js", name) };
1000                        outputs.push(route_output);
1001                    }
1002                }
1003
1004                // 生成入口文件
1005                let mut entry_code = String::new();
1006                entry_code.push_str("// Entry Point\n");
1007                entry_code.push_str("import './runtime.js';\n");
1008                if !hmr_code.is_empty() {
1009                    entry_code.push_str("import './hmr.js';\n");
1010                }
1011                if !regular_components.is_empty() {
1012                    entry_code.push_str("import './shared.js';\n");
1013                }
1014
1015                // 动态导入路由组件
1016                for (i, module) in &route_components {
1017                    if let Ok((name, _)) = &compiled_modules[*i] {
1018                        entry_code.push_str(&format!("const {} = () => import('./route-{}.js');\n", name, name));
1019                    }
1020                }
1021
1022                // 导入普通组件
1023                for (i, module) in &regular_components {
1024                    if let Ok((name, _)) = &compiled_modules[*i] {
1025                        entry_code.push_str(&format!("import {} from './shared.js';\n", name));
1026                    }
1027                }
1028
1029                if let Some(main) = modules.first() {
1030                    entry_code.push_str(&format!("\n// Mount\n"));
1031                    entry_code.push_str(&format!("render(h({}, null), document.getElementById('app') || document.body);\n", main.name));
1032                }
1033
1034                let entry_output = BuildOutput { code: entry_code.into_bytes(), format: OutputFormat::JavaScript, filename: "index.js".to_string() };
1035                outputs.push(entry_output);
1036
1037                Ok(BuildOutputs { outputs, entry_file: "index.js".to_string() })
1038            }
1039            SplitStrategy::Custom => {
1040                // 自定义分割策略:基于模块大小和依赖关系
1041                let mut outputs = Vec::new();
1042                let mut large_modules = Vec::new();
1043                let mut small_modules = Vec::new();
1044
1045                // 生成运行时文件
1046                let runtime_output = BuildOutput { code: runtime_code.into_bytes(), format: OutputFormat::JavaScript, filename: "runtime.js".to_string() };
1047                outputs.push(runtime_output);
1048
1049                // 生成 HMR 客户端文件
1050                if !hmr_code.is_empty() {
1051                    let hmr_output = BuildOutput { code: hmr_code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: "hmr.js".to_string() };
1052                    outputs.push(hmr_output);
1053                }
1054
1055                // 根据模块大小分离模块
1056                for (i, module) in modules.iter().enumerate() {
1057                    let code_size = if let Ok((_, code)) = &compiled_modules[i] { code.len() } else { 0 };
1058
1059                    // 大于10KB的模块作为单独chunk
1060                    if code_size > 10 * 1024 {
1061                        large_modules.push((i, module));
1062                    }
1063                    else {
1064                        small_modules.push((i, module));
1065                    }
1066                }
1067
1068                // 生成小模块的共享chunk
1069                let mut shared_code = String::new();
1070                for (i, module) in &small_modules {
1071                    if let Ok((name, code)) = &compiled_modules[*i] {
1072                        shared_code.push_str(&format!("// Component: {}\n{}\n", name, code));
1073                    }
1074                }
1075
1076                if !shared_code.is_empty() {
1077                    let shared_output = BuildOutput { code: shared_code.into_bytes(), format: OutputFormat::JavaScript, filename: "shared.js".to_string() };
1078                    outputs.push(shared_output);
1079                }
1080
1081                // 为每个大模块生成单独的文件
1082                for (i, module) in &large_modules {
1083                    if let Ok((name, code)) = &compiled_modules[*i] {
1084                        let large_output = BuildOutput { code: code.clone().into_bytes(), format: OutputFormat::JavaScript, filename: format!("chunk-{}.js", name) };
1085                        outputs.push(large_output);
1086                    }
1087                }
1088
1089                // 生成入口文件
1090                let mut entry_code = String::new();
1091                entry_code.push_str("// Entry Point\n");
1092                entry_code.push_str("import './runtime.js';\n");
1093                if !hmr_code.is_empty() {
1094                    entry_code.push_str("import './hmr.js';\n");
1095                }
1096                if !small_modules.is_empty() {
1097                    entry_code.push_str("import './shared.js';\n");
1098                }
1099
1100                // 动态导入大模块
1101                for (i, module) in &large_modules {
1102                    if let Ok((name, _)) = &compiled_modules[*i] {
1103                        entry_code.push_str(&format!("const {} = () => import('./chunk-{}.js');\n", name, name));
1104                    }
1105                }
1106
1107                // 导入小模块
1108                for (i, module) in &small_modules {
1109                    if let Ok((name, _)) = &compiled_modules[*i] {
1110                        entry_code.push_str(&format!("import {} from './shared.js';\n", name));
1111                    }
1112                }
1113
1114                if let Some(main) = modules.first() {
1115                    entry_code.push_str(&format!("\n// Mount\n"));
1116                    entry_code.push_str(&format!("render(h({}, null), document.getElementById('app') || document.body);\n", main.name));
1117                }
1118
1119                let entry_output = BuildOutput { code: entry_code.into_bytes(), format: OutputFormat::JavaScript, filename: "index.js".to_string() };
1120                outputs.push(entry_output);
1121
1122                Ok(BuildOutputs { outputs, entry_file: "index.js".to_string() })
1123            }
1124        }
1125    }
1126
1127    /// 生成 CSS 代码
1128    fn bundle_css(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
1129        let mut output = String::new();
1130        let backend = CssBackend::new(false);
1131
1132        for module in modules {
1133            let css = backend.generate(module)?;
1134            if !css.is_empty() {
1135                output.push_str(&format!("/* Component: {} */\n", module.name));
1136                output.push_str(&css);
1137                output.push_str("\n");
1138            }
1139        }
1140
1141        let build_output = BuildOutput { code: output.into_bytes(), format: OutputFormat::CSS, filename: "bundle.css".to_string() };
1142        Ok(BuildOutputs { outputs: vec![build_output], entry_file: "bundle.css".to_string() })
1143    }
1144
1145    /// 生成 HTML 代码
1146    fn bundle_html(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
1147        let mut output = String::new();
1148        let backend = HtmlBackend::new();
1149
1150        for module in modules {
1151            let html = backend.generate(module)?;
1152            if !html.is_empty() {
1153                output.push_str(&format!("<!-- Component: {} -->\n", module.name));
1154                output.push_str(&html);
1155                output.push_str("\n");
1156            }
1157        }
1158
1159        let build_output = BuildOutput { code: output.into_bytes(), format: OutputFormat::HTML, filename: "bundle.html".to_string() };
1160        Ok(BuildOutputs { outputs: vec![build_output], entry_file: "bundle.html".to_string() })
1161    }
1162
1163    /// 生成 TypeScript 类型定义
1164    fn bundle_typescript(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
1165        let mut output = String::new();
1166        let backend = DtsBackend::new();
1167
1168        for module in modules {
1169            let dts = backend.generate(module)?;
1170            if !dts.is_empty() {
1171                output.push_str(&format!("// Component: {}\n", module.name));
1172                output.push_str(&dts);
1173                output.push_str("\n");
1174            }
1175        }
1176
1177        let build_output = BuildOutput { code: output.into_bytes(), format: OutputFormat::TypeScript, filename: "bundle.d.ts".to_string() };
1178        Ok(BuildOutputs { outputs: vec![build_output], entry_file: "bundle.d.ts".to_string() })
1179    }
1180
1181    /// 生成 WebAssembly 代码
1182    fn bundle_wasm(&mut self, modules: &[IRModule]) -> Result<BuildOutputs> {
1183        // 目前不支持 WebAssembly
1184        let build_output = BuildOutput { code: vec![], format: OutputFormat::WebAssembly, filename: "bundle.wasm".to_string() };
1185        Ok(BuildOutputs { outputs: vec![build_output], entry_file: "bundle.wasm".to_string() })
1186    }
1187}
1188
1189impl Default for Bundler {
1190    fn default() -> Self {
1191        Self::new(None)
1192    }
1193}