Skip to main content

next_napi_bindings/
lib.rs

1/*
2Copyright (c) 2017 The swc Project Developers
3
4Permission is hereby granted, free of charge, to any
5person obtaining a copy of this software and associated
6documentation files (the "Software"), to deal in the
7Software without restriction, including without
8limitation the rights to use, copy, modify, merge,
9publish, distribute, sublicense, and/or sell copies of
10the Software, and to permit persons to whom the Software
11is furnished to do so, subject to the following
12conditions:
13
14The above copyright notice and this permission notice
15shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26DEALINGS IN THE SOFTWARE.
27*/
28
29#![recursion_limit = "2048"]
30//#![deny(clippy::all)]
31#![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        // Avoid a limit on threads to avoid deadlocks due to usage of block_in_place
112        .max_blocking_threads(usize::MAX - worker_threads)
113        // Avoid the extra lifo slot to avoid stalling tasks when doing cpu-heavy work
114        .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}