next_napi_bindings/
lib.rs1#![recursion_limit = "2048"]
30#![feature(arbitrary_self_types)]
32#![feature(arbitrary_self_types_pointers)]
33#![feature(iter_intersperse)]
34
35use std::sync::Arc;
36
37use napi::bindgen_prelude::*;
38use rustc_hash::{FxHashMap, FxHashSet};
39use swc_core::{
40 atoms::Atom,
41 base::{Compiler, TransformOutput},
42 common::{FilePathMapping, SourceMap},
43};
44
45pub mod code_frame;
46#[cfg(not(target_arch = "wasm32"))]
47pub mod css;
48pub mod lockfile;
49pub mod mdx;
50pub mod minify;
51#[cfg(not(target_arch = "wasm32"))]
52pub mod next_api;
53pub mod parse;
54pub mod react_compiler;
55pub mod rspack;
56pub mod transform;
57#[cfg(not(target_arch = "wasm32"))]
58pub mod turbo_trace_server;
59#[cfg(not(target_arch = "wasm32"))]
60pub mod turbopack;
61pub mod util;
62
63#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
64#[global_allocator]
65static ALLOC: turbo_tasks_malloc::TurboMalloc = turbo_tasks_malloc::TurboMalloc;
66
67#[cfg(feature = "__internal_dhat-heap")]
68#[global_allocator]
69static ALLOC: dhat::Alloc = dhat::Alloc;
70
71#[cfg(not(target_arch = "wasm32"))]
72#[napi::module_init]
73fn init() {
74 use std::{
75 cell::RefCell,
76 panic::{set_hook, take_hook},
77 thread::available_parallelism,
78 time::{Duration, Instant},
79 };
80
81 thread_local! {
82 static LAST_SWC_ATOM_GC_TIME: RefCell<Option<Instant>> = const { RefCell::new(None) };
83 }
84
85 use tokio::runtime::Builder;
86 use turbo_tasks::panic_hooks::handle_panic;
87 use turbo_tasks_malloc::TurboMalloc;
88
89 let prev_hook = take_hook();
90 set_hook(Box::new(move |info| {
91 handle_panic(info);
92 prev_hook(info);
93 }));
94
95 let worker_threads = available_parallelism().map(|n| n.get()).unwrap_or(1);
96
97 let rt = Builder::new_multi_thread()
98 .enable_all()
99 .on_thread_stop(|| {
100 TurboMalloc::thread_stop();
101 })
102 .on_thread_park(|| {
103 LAST_SWC_ATOM_GC_TIME.with_borrow_mut(|cell| {
104 if cell.is_none_or(|t| t.elapsed() > Duration::from_secs(2)) {
105 swc_core::ecma::atoms::hstr::global_atom_store_gc();
106 *cell = Some(Instant::now());
107 }
108 });
109 })
110 .worker_threads(worker_threads)
111 .max_blocking_threads(usize::MAX - worker_threads)
113 .disable_lifo_slot()
115 .build()
116 .unwrap();
117 create_custom_tokio_runtime(rt);
118}
119
120#[inline]
121fn get_compiler() -> Compiler {
122 let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
123
124 Compiler::new(cm)
125}
126
127pub fn complete_output(
128 env: &Env,
129 output: TransformOutput,
130 eliminated_packages: FxHashSet<Atom>,
131 use_cache_telemetry_tracker: FxHashMap<String, usize>,
132) -> napi::Result<Object> {
133 let mut js_output = env.create_object()?;
134 js_output.set_named_property("code", env.create_string_from_std(output.code)?)?;
135 if let Some(map) = output.map {
136 js_output.set_named_property("map", env.create_string_from_std(map)?)?;
137 }
138 if !eliminated_packages.is_empty() {
139 js_output.set_named_property(
140 "eliminatedPackages",
141 env.create_string_from_std(serde_json::to_string(&eliminated_packages)?)?,
142 )?;
143 }
144 if !use_cache_telemetry_tracker.is_empty() {
145 js_output.set_named_property(
146 "useCacheTelemetryTracker",
147 env.create_string_from_std(serde_json::to_string(
148 &use_cache_telemetry_tracker
149 .iter()
150 .map(|(k, v)| (k.clone(), *v))
151 .collect::<Vec<_>>(),
152 )?)?,
153 )?;
154 }
155
156 Ok(js_output)
157}