@rspack/binding 0.0.2 → 0.0.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/Cargo.toml DELETED
@@ -1,44 +0,0 @@
1
- [package]
2
- edition = "2021"
3
- name = "rspack_node"
4
- publish = false
5
- version = "0.1.0"
6
-
7
- # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
-
9
- [lib]
10
- crate-type = ["cdylib"]
11
-
12
- [dependencies]
13
- anyhow = {version = "1", features = ["backtrace"]}
14
- async-trait = "0.1.53"
15
- backtrace = "0.3"
16
- dashmap = "5.0.0"
17
- futures = "0.3"
18
- napi = {git = "https://github.com/speedy-js/napi-rs", branch = "speedy-release", default-features = false, features = [
19
- "async",
20
- "tokio_rt",
21
- "serde-json",
22
- ]}
23
- napi-derive = {git = "https://github.com/speedy-js/napi-rs", branch = "speedy-release"}
24
- napi-sys = {git = "https://github.com/speedy-js/napi-rs", branch = "speedy-release"}
25
- once_cell = "1"
26
- regex = "1.6.0"
27
- rspack = {path = "../rspack"}
28
- rspack_binding_options = {path = "../rspack_binding_options", features = ["node-api"]}
29
- rspack_core = {path = "../rspack_core"}
30
- rspack_error = {path = "../rspack_error"}
31
- rspack_plugin_html = {path = "../rspack_plugin_html"}
32
- serde = {version = "1", features = ["derive"]}
33
- serde_json = "1"
34
- tokio = {version = "1.17.0", features = ["full"]}
35
- tracing = "0.1.34"
36
-
37
- [target.'cfg(all(not(all(target_os = "linux", target_arch = "aarch64", target_env = "musl"))))'.dependencies]
38
- mimalloc-rust = {version = "0.1"}
39
-
40
- [build-dependencies]
41
- napi-build = {git = "https://github.com/speedy-js/napi-rs", branch = "speedy-release"}
42
-
43
- [dev-dependencies]
44
- testing_macros = {version = "0.2.5"}
package/build.rs DELETED
@@ -1,5 +0,0 @@
1
- extern crate napi_build;
2
-
3
- fn main() {
4
- napi_build::setup();
5
- }
package/napirs.rc.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "napi": {
3
- "name": "rspack",
4
- "triples": {
5
- "defaults": true,
6
- "additional": [
7
- "x86_64-unknown-linux-musl",
8
- "aarch64-unknown-linux-gnu",
9
- "i686-pc-windows-msvc",
10
- "armv7-unknown-linux-gnueabihf",
11
- "aarch64-apple-darwin",
12
- "x86_64-unknown-freebsd",
13
- "aarch64-unknown-linux-musl",
14
- "aarch64-pc-windows-msvc",
15
- "aarch64-linux-android",
16
- "armv7-linux-androideabi"
17
- ]
18
- }
19
- }
20
- }
@@ -1,11 +0,0 @@
1
- use std::sync::Arc;
2
-
3
- use dashmap::DashMap;
4
- use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction};
5
- use once_cell::sync::Lazy;
6
- use tokio::sync::oneshot::Sender;
7
-
8
- pub type ThreadsafeRspackCallback = ThreadsafeFunction<String, ErrorStrategy::CalleeHandled>;
9
-
10
- pub static REGISTERED_DONE_SENDERS: Lazy<Arc<DashMap<usize, Sender<()>>>> =
11
- Lazy::new(Default::default);
@@ -1,124 +0,0 @@
1
- use std::fmt::Debug;
2
- use std::sync::atomic::{AtomicUsize, Ordering};
3
-
4
- use rspack_core::{Plugin, PluginBuildEndHookOutput};
5
-
6
- use anyhow::Context;
7
- use async_trait::async_trait;
8
- use napi::threadsafe_function::ThreadsafeFunctionCallMode;
9
- use napi::Error;
10
- use napi_derive::napi;
11
- use once_cell::sync::Lazy;
12
- use serde::{Deserialize, Serialize};
13
- use tokio::sync::oneshot;
14
-
15
- mod common;
16
- pub mod utils;
17
- pub use utils::create_node_adapter_from_plugin_callbacks;
18
-
19
- use common::ThreadsafeRspackCallback;
20
- use common::REGISTERED_DONE_SENDERS;
21
-
22
- pub static CALL_ID: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(1));
23
-
24
- pub struct RspackPluginNodeAdapter {
25
- pub done_tsfn: ThreadsafeRspackCallback,
26
- }
27
-
28
- #[derive(Serialize, Deserialize, Debug)]
29
- #[serde(rename_all = "camelCase")]
30
- pub struct RspackThreadsafeContext<T: Debug> {
31
- id: usize,
32
- inner: T,
33
- }
34
-
35
- impl<T: Debug> RspackThreadsafeContext<T> {
36
- pub fn new(payload: T) -> Self {
37
- Self {
38
- id: CALL_ID.fetch_add(1, Ordering::SeqCst),
39
- inner: payload,
40
- }
41
- }
42
-
43
- #[inline(always)]
44
- pub fn get_call_id(&self) -> usize {
45
- self.id
46
- }
47
- }
48
-
49
- #[derive(Serialize, Deserialize, Debug)]
50
- #[serde(rename_all = "camelCase")]
51
- pub struct RspackThreadsafeResult<T: Debug> {
52
- id: usize,
53
- inner: T,
54
- }
55
-
56
- impl<T: Debug> RspackThreadsafeResult<T> {
57
- #[inline(always)]
58
- pub fn get_call_id(&self) -> usize {
59
- self.id
60
- }
61
- }
62
-
63
- #[derive(Serialize, Deserialize, Debug)]
64
- #[napi(object)]
65
- pub struct OnLoadContext {
66
- pub id: String,
67
- }
68
-
69
- impl Debug for RspackPluginNodeAdapter {
70
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71
- f.debug_struct("RspackPluginNodeAdapter").finish()
72
- }
73
- }
74
-
75
- #[async_trait]
76
- impl Plugin for RspackPluginNodeAdapter {
77
- fn name(&self) -> &'static str {
78
- "rspack_plugin_node_adapter"
79
- }
80
- #[tracing::instrument(skip_all)]
81
- async fn done(&self) -> PluginBuildEndHookOutput {
82
- let context = RspackThreadsafeContext::new(());
83
-
84
- let (tx, rx) = oneshot::channel::<()>();
85
-
86
- match REGISTERED_DONE_SENDERS.entry(context.get_call_id()) {
87
- dashmap::mapref::entry::Entry::Vacant(v) => {
88
- v.insert(tx);
89
- }
90
- dashmap::mapref::entry::Entry::Occupied(_) => {
91
- let err = Error::new(
92
- napi::Status::Unknown,
93
- format!(
94
- "duplicated call id encountered {}, please file an issue.",
95
- context.get_call_id(),
96
- ),
97
- );
98
- self
99
- .done_tsfn
100
- .call(Err(err.clone()), ThreadsafeFunctionCallMode::Blocking);
101
-
102
- let any_error = anyhow::Error::from(err);
103
- return Err(any_error.into());
104
- }
105
- }
106
-
107
- let value = serde_json::to_string(&context).map_err(|_| {
108
- Error::new(
109
- napi::Status::Unknown,
110
- "unable to convert context".to_owned(),
111
- )
112
- });
113
-
114
- self
115
- .done_tsfn
116
- .call(value, ThreadsafeFunctionCallMode::Blocking);
117
-
118
- let t = rx
119
- .await
120
- .context("failed to receive done result")
121
- .map_err(|err| err.into());
122
- return t;
123
- }
124
- }
@@ -1,62 +0,0 @@
1
- use napi::bindgen_prelude::*;
2
- use napi::{
3
- threadsafe_function::{ErrorStrategy, ThreadSafeResultContext, ThreadsafeFunction},
4
- Env,
5
- };
6
-
7
- use super::common::REGISTERED_DONE_SENDERS;
8
- use crate::PluginCallbacks;
9
-
10
- pub fn create_node_adapter_from_plugin_callbacks(
11
- env: &Env,
12
- plugin_callbacks: Option<PluginCallbacks>,
13
- ) -> Result<Option<super::RspackPluginNodeAdapter>> {
14
- plugin_callbacks
15
- .map(|PluginCallbacks { done_callback }| {
16
- let mut done_tsfn: ThreadsafeFunction<String, ErrorStrategy::CalleeHandled> = done_callback
17
- .create_threadsafe_function(
18
- 0,
19
- |ctx| ctx.env.create_string_from_std(ctx.value).map(|v| vec![v]),
20
- |ctx: ThreadSafeResultContext<Promise<String>>| {
21
- let return_value = ctx.return_value;
22
-
23
- ctx
24
- .env
25
- .execute_tokio_future(
26
- async move {
27
- let result = return_value.await?;
28
-
29
- let result: super::RspackThreadsafeResult<()> =
30
- serde_json::from_str(&result).expect("failed to evaluate done result");
31
-
32
- tracing::debug!("build end result {:?}", result);
33
-
34
- let sender = REGISTERED_DONE_SENDERS.remove(&result.get_call_id());
35
-
36
- if let Some((_, sender)) = sender {
37
- sender.send(()).map_err(|m| {
38
- Error::new(
39
- napi::Status::GenericFailure,
40
- format!("failed to send result {:#?}", m),
41
- )
42
- })?;
43
- } else {
44
- return Err(Error::new(
45
- napi::Status::GenericFailure,
46
- "failed to get sender for plugin".to_owned(),
47
- ));
48
- }
49
-
50
- Ok(())
51
- },
52
- |_, ret| Ok(ret),
53
- )
54
- .expect("failed to execute tokio future");
55
- },
56
- )?;
57
- done_tsfn.unref(env)?;
58
-
59
- Ok(super::RspackPluginNodeAdapter { done_tsfn })
60
- })
61
- .transpose()
62
- }
package/src/lib.rs DELETED
@@ -1,272 +0,0 @@
1
- use std::fmt::Debug;
2
- // use std::path::Path;
3
- use std::sync::Arc;
4
-
5
- use napi::bindgen_prelude::*;
6
- use napi::{Env, Result};
7
- use napi_derive::napi;
8
- // use nodejs_resolver::Resolver;
9
- use tokio::sync::Mutex;
10
- mod adapter;
11
- // mod options;
12
- mod utils;
13
- use adapter::create_node_adapter_from_plugin_callbacks;
14
-
15
- use utils::get_named_property_value_string;
16
-
17
- // use adapter::utils::create_node_adapter_from_plugin_callbacks;
18
- pub use rspack_binding_options::{normalize_bundle_options, NodeLoaderAdapter, RawOptions};
19
-
20
- #[cfg(all(not(all(target_os = "linux", target_arch = "aarch64", target_env = "musl"))))]
21
- #[global_allocator]
22
- static ALLOC: mimalloc_rust::GlobalMiMalloc = mimalloc_rust::GlobalMiMalloc;
23
-
24
- pub fn create_external<T>(value: T) -> External<T> {
25
- External::new(value)
26
- }
27
-
28
- pub type Rspack = Arc<Mutex<rspack::Compiler>>;
29
-
30
- #[napi(object)]
31
-
32
- pub struct PluginCallbacks {
33
- pub done_callback: JsFunction,
34
- }
35
- impl Debug for PluginCallbacks {
36
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37
- f.debug_struct("PluginCallbacks")
38
- .field("done_callback", &"done_adapter")
39
- .finish()
40
- }
41
- }
42
-
43
- pub struct RspackBindingContext {
44
- pub rspack: Rspack,
45
- // pub resolver: Arc<Resolver>,
46
- }
47
- #[napi(object)]
48
- pub struct RspackError {
49
- pub message: String,
50
- }
51
- #[napi(object)]
52
- pub struct Stats {
53
- pub errors: Vec<RspackError>,
54
- }
55
-
56
- impl<'a> From<rspack_core::Stats<'a>> for Stats {
57
- fn from(rspack_stats: rspack_core::Stats) -> Self {
58
- Self {
59
- errors: rspack_stats
60
- .compilation
61
- .diagnostic
62
- .iter()
63
- .map(|d| RspackError {
64
- message: d.message.clone(),
65
- })
66
- .collect(),
67
- }
68
- }
69
- }
70
-
71
- #[napi]
72
- pub fn init_trace_subscriber(env: Env) -> Result<()> {
73
- utils::init_custom_trace_subscriber(env)
74
- }
75
-
76
- #[napi(ts_return_type = "ExternalObject<RspackInternal>")]
77
- #[allow(clippy::too_many_arguments)]
78
- pub fn new_rspack(
79
- env: Env,
80
- mut options: RawOptions,
81
- plugin_callbacks: Option<PluginCallbacks>,
82
- ) -> Result<External<RspackBindingContext>> {
83
- #[cfg(debug_assertions)]
84
- {
85
- if let Some(module) = options.module.as_mut() {
86
- for rule in &mut module.rules {
87
- if let Some(uses) = rule.uses.as_mut() {
88
- for item in uses {
89
- if let Some(loader) = item.loader.as_ref() {
90
- // let (env_ptr, loader_ptr) = unsafe { (env.raw(), loader.raw()) };
91
- if let Ok(display_name) = get_named_property_value_string(env, loader, "displayName")
92
- {
93
- item.__loader_name = Some(display_name);
94
- } else if let Ok(name) = get_named_property_value_string(env, loader, "name") {
95
- item.__loader_name = Some(name);
96
- }
97
- }
98
- }
99
- }
100
- }
101
- }
102
- }
103
- let node_adapter = create_node_adapter_from_plugin_callbacks(&env, plugin_callbacks)?;
104
- let mut compiler_options =
105
- normalize_bundle_options(options).map_err(|e| Error::from_reason(format!("{:?}", e)))?;
106
- if let Some(node_adapter) = node_adapter {
107
- compiler_options
108
- .plugins
109
- .push(Box::new(node_adapter) as Box<dyn rspack_core::Plugin>);
110
- }
111
- // TODO: this way or passing env as context to `normalize_bundle_option`?
112
- compiler_options
113
- .module
114
- .rules
115
- .iter_mut()
116
- .try_for_each(|rule| {
117
- rule.uses.iter_mut().try_for_each(|loader| {
118
- let casted = loader.as_any_mut();
119
- if let Some(adapter) = casted.downcast_mut::<NodeLoaderAdapter>() {
120
- adapter.unref(&env)
121
- } else {
122
- Ok(())
123
- }
124
- })
125
- })
126
- .map_err(|e| Error::from_reason(format!("failed to unref tsfn {:?}", e)))?;
127
-
128
- let rspack = rspack::rspack(compiler_options, vec![]);
129
-
130
- // let resolver = rspack.resolver.clone();
131
- Ok(create_external(RspackBindingContext {
132
- rspack: Arc::new(Mutex::new(rspack)),
133
- // resolver,
134
- }))
135
- }
136
-
137
- #[napi(
138
- ts_args_type = "rspack: ExternalObject<RspackInternal>",
139
- ts_return_type = "Promise<Stats>"
140
- )]
141
- pub fn build(env: Env, binding_context: External<RspackBindingContext>) -> Result<napi::JsObject> {
142
- let compiler = binding_context.rspack.clone();
143
- env.execute_tokio_future(
144
- async move {
145
- let mut compiler = compiler.lock().await;
146
- let rspack_stats = compiler
147
- .build()
148
- .await
149
- .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{:?}", e)))?;
150
-
151
- let stats: Stats = rspack_stats.into();
152
- if stats.errors.is_empty() {
153
- println!("build success");
154
- } else {
155
- println!("build failed");
156
- }
157
- Ok(stats)
158
- },
159
- |_env, ret| Ok(ret),
160
- )
161
- }
162
-
163
- #[napi(
164
- // ts_args_type = "rspack: ExternalObject<RspackInternal>, changedFile: string[]",
165
- ts_args_type = "rspack: ExternalObject<RspackInternal>",
166
- // ts_return_type = "Promise<[diff: Record<string, string>, map: Record<string, string>]>"
167
- ts_return_type = "Promise<Record<string, string>>"
168
- )]
169
- pub fn rebuild(
170
- env: Env,
171
- binding_context: External<RspackBindingContext>,
172
- changed_file: Vec<String>,
173
- ) -> Result<napi::JsObject> {
174
- let compiler = binding_context.rspack.clone();
175
- env.execute_tokio_future(
176
- async move {
177
- let mut compiler = compiler.lock().await;
178
- let _rspack_stats = compiler
179
- .rebuild(changed_file)
180
- .await
181
- .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{:?}", e)))?;
182
-
183
- let stats: Stats = _rspack_stats.into();
184
- println!("rebuild success");
185
- Ok(stats)
186
- },
187
- |_env, ret| Ok(ret),
188
- )
189
- }
190
-
191
- // #[napi(
192
- // ts_args_type = "rspack: ExternalObject<RspackInternal>, source: string, resolveOptions: ResolveOptions",
193
- // ts_return_type = "ResolveResult"
194
- // )]
195
- // pub fn resolve(
196
- // binding_context: External<RspackBindingContext>,
197
- // source: String,
198
- // resolve_options: ResolveOptions,
199
- // ) -> Result<ResolveResult> {
200
- // let resolver = (*binding_context).resolver.clone();
201
- // let res = resolver.resolve(Path::new(&resolve_options.resolve_dir), &source);
202
- // match res {
203
- // Ok(val) => {
204
- // if let nodejs_resolver::ResolveResult::Path(p) = val {
205
- // Ok(ResolveResult {
206
- // status: true,
207
- // path: Some(p.to_string_lossy().to_string()),
208
- // })
209
- // } else {
210
- // Ok(ResolveResult {
211
- // status: false,
212
- // path: None,
213
- // })
214
- // }
215
- // }
216
- // Err(err) => Err(Error::new(Status::GenericFailure, err)),
217
- // }
218
- // }
219
-
220
- // #[napi(object)]
221
- // pub struct ResolveOptions {
222
- // pub resolve_dir: String,
223
- // }
224
-
225
- // #[napi(object)]
226
- // pub struct ResolveResult {
227
- // pub status: bool,
228
- // pub path: Option<String>,
229
- // }
230
-
231
- // #[napi]
232
- // pub fn resolve_file(base_dir: String, import_path: String) -> Result<String> {
233
- // let resolver = Resolver::new(nodejs_resolver::ResolverOptions {
234
- // extensions: vec!["less", "css", "scss", "sass", "js"]
235
- // .into_iter()
236
- // .map(|s| s.to_owned())
237
- // .collect(),
238
- // ..Default::default()
239
- // });
240
- // match resolver.resolve(Path::new(&base_dir), &import_path) {
241
- // Ok(res) => {
242
- // if let nodejs_resolver::ResolveResult::Path(abs_path) = res {
243
- // match abs_path.to_str() {
244
- // Some(s) => Ok(s.to_owned()),
245
- // None => Err(Error::new(
246
- // napi::Status::GenericFailure,
247
- // "unable to create string from path".to_owned(),
248
- // )),
249
- // }
250
- // } else {
251
- // Ok(import_path)
252
- // }
253
- // }
254
- // Err(msg) => Err(Error::new(Status::GenericFailure, msg)),
255
- // }
256
- // }
257
-
258
- #[napi::module_init]
259
- fn init() {
260
- use backtrace::Backtrace;
261
- use std::panic::set_hook;
262
-
263
- set_hook(Box::new(|panic_info| {
264
- let backtrace = Backtrace::new();
265
- println!("Panic: {:?}\nBacktrace: {:?}", panic_info, backtrace);
266
- std::process::exit(1)
267
- }));
268
- }
269
-
270
- // for dts generation only
271
- #[napi(object)]
272
- pub struct RspackInternal {}
package/src/utils.rs DELETED
@@ -1,88 +0,0 @@
1
- use std::ffi::CStr;
2
- use std::io::Write;
3
- use std::ptr;
4
-
5
- use napi::{check_status, Env, Error, NapiRaw, Result};
6
- use napi_derive::napi;
7
- use once_cell::sync::OnceCell;
8
-
9
- static CUSTOM_TRACE_SUBSCRIBER: OnceCell<bool> = OnceCell::new();
10
-
11
- /// Try to resolve the string value of a given named property
12
- pub fn get_named_property_value_string<T: NapiRaw>(
13
- env: Env,
14
- object: T,
15
- property_name: &str,
16
- ) -> Result<String> {
17
- let mut bytes_with_nul: Vec<u8> = Vec::with_capacity(property_name.len() + 1);
18
-
19
- write!(&mut bytes_with_nul, "{}", property_name)?;
20
- write!(&mut bytes_with_nul, "{}", '\0')?;
21
-
22
- let mut value_ptr = ptr::null_mut();
23
-
24
- check_status!(
25
- unsafe {
26
- napi_sys::napi_get_named_property(
27
- env.raw(),
28
- object.raw(),
29
- CStr::from_bytes_with_nul_unchecked(&bytes_with_nul).as_ptr(),
30
- &mut value_ptr,
31
- )
32
- },
33
- "failed to get the value"
34
- )?;
35
-
36
- let mut str_len = 0;
37
- check_status!(
38
- unsafe {
39
- napi_sys::napi_get_value_string_utf8(env.raw(), value_ptr, ptr::null_mut(), 0, &mut str_len)
40
- },
41
- "failed to get the value"
42
- )?;
43
-
44
- str_len += 1;
45
- let mut buf = Vec::with_capacity(str_len);
46
- let mut copied_len = 0;
47
-
48
- check_status!(
49
- unsafe {
50
- napi_sys::napi_get_value_string_utf8(
51
- env.raw(),
52
- value_ptr,
53
- buf.as_mut_ptr(),
54
- str_len,
55
- &mut copied_len,
56
- )
57
- },
58
- "failed to get the value"
59
- )?;
60
-
61
- // Vec<i8> -> Vec<u8> See: https://stackoverflow.com/questions/59707349/cast-vector-of-i8-to-vector-of-u8-in-rust
62
- let mut buf = std::mem::ManuallyDrop::new(buf);
63
-
64
- let buf = unsafe { Vec::from_raw_parts(buf.as_mut_ptr() as *mut u8, copied_len, copied_len) };
65
-
66
- String::from_utf8(buf).map_err(|_| Error::from_reason("failed to get property"))
67
- }
68
-
69
- #[napi]
70
- pub fn init_custom_trace_subscriber(
71
- mut env: Env,
72
- // trace_out_file_path: Option<String>,
73
- ) -> Result<()> {
74
- CUSTOM_TRACE_SUBSCRIBER.get_or_init(|| {
75
- let guard = rspack_core::log::enable_tracing_by_env_with_chrome_layer();
76
- if let Some(guard) = guard {
77
- env
78
- .add_env_cleanup_hook(guard, |flush_guard| {
79
- flush_guard.flush();
80
- drop(flush_guard);
81
- })
82
- .expect("Should able to initialize cleanup for custom trace subscriber");
83
- }
84
- true
85
- });
86
-
87
- Ok(())
88
- }
package/tests/answer.js DELETED
@@ -1 +0,0 @@
1
- export const answer = 42
@@ -1,19 +0,0 @@
1
- import assert from 'assert'
2
- import path from 'path'
3
- import log from 'why-is-node-running'
4
- import binding from '..'
5
- import { RawOptions } from '../binding.d'
6
-
7
- describe('binding', () => {
8
- it('work', async () => {
9
- const options: RawOptions = {
10
- entries: { main: path.resolve(__dirname, './index.js') },
11
- // entryFilename: path.resolve(__dirname, 'dist/main.js'),
12
- }
13
- const instance = binding.newRspack(JSON.stringify(options))
14
- await binding.build(instance)
15
- // setTimeout(() => {
16
- // log();
17
- // }, 5000);
18
- })
19
- })
package/tests/index.js DELETED
@@ -1,2 +0,0 @@
1
- import { answer } from './answer'
2
- console.log({ answer })