Skip to content

Commit 915e4c1

Browse files
committed
feat(pack): add target: node support for library builds
- Make library endpoint platform-aware: dispatch compile-time info, module options, and resolve options based on Platform (Web/Node) - Create Node.js-compatible runtime backend (runtime-backend-node.ts) without DOM APIs (no document.createElement, importScripts, etc.) - Conditionally select runtime backend in runtime_code.rs based on is_node_platform flag on LibraryChunkingContext - Always use EdgeWorker environment for library chunking context (ChunkLoading::Edge prevents async chunk splitting for single-file output) - Move and organize target_node snapshot tests under target_node/ - Add library_build_node_target test with dynamic import() to verify single-chunk enforcement and correct Node.js built-in externals
1 parent b0ecb21 commit 915e4c1

26 files changed

Lines changed: 364 additions & 133 deletions

File tree

crates/pack-api/src/app.rs

Lines changed: 52 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use pack_core::client::context::{
44
get_client_runtime_entries,
55
};
66
use pack_core::config::Platform;
7+
78
use pack_core::server::contexts::{
89
get_server_module_options_context, get_server_resolve_options_context,
910
};
@@ -265,17 +266,16 @@ impl AppEntrypoint {
265266
asset_context: Vc<Box<dyn AssetContext>>,
266267
runtime_entries: Vc<EvaluatableAssets>,
267268
) -> Result<Vc<OutputAssets>> {
268-
let platform = &*self.project().platform().await?;
269-
let chunk_group_assets = match platform {
270-
Platform::Web => {
269+
let chunk_group_assets = match &*self.project().platform().await? {
270+
Platform::Node => {
271271
*self
272-
.client_chunk_group(asset_context, runtime_entries)
272+
.server_chunk_group(asset_context, runtime_entries)
273273
.await?
274274
.assets
275275
}
276-
Platform::Node => {
276+
Platform::Web => {
277277
*self
278-
.server_chunk_group(asset_context, runtime_entries)
278+
.client_chunk_group(asset_context, runtime_entries)
279279
.await?
280280
.assets
281281
}
@@ -299,49 +299,37 @@ impl AppEndpoint {
299299

300300
#[turbo_tasks::function]
301301
pub async fn app_runtime_entries(self: Vc<Self>) -> Result<Vc<EvaluatableAssets>> {
302-
match &*self.project().platform().await? {
302+
let project = self.project();
303+
match &*project.platform().await? {
304+
Platform::Node => Ok(EvaluatableAssets::empty()),
303305
Platform::Web => {
304-
let watch = self.project().await?.watch.enable;
306+
let watch = project.await?.watch.enable;
305307
Ok(get_client_runtime_entries(
306-
self.project().project_path().owned().await?,
307-
self.project().mode(),
308-
self.project().config(),
309-
self.project().execution_context(),
310-
self.project().pack_path().owned().await?,
308+
project.project_path().owned().await?,
309+
project.mode(),
310+
project.config(),
311+
project.execution_context(),
312+
project.pack_path().owned().await?,
311313
Vc::cell(watch),
312-
Vc::cell(
313-
watch
314-
&& self
315-
.project()
316-
.config()
317-
.dev_server()
318-
.await?
319-
.hot
320-
.unwrap_or_default(),
321-
),
314+
Vc::cell(watch && project.config().dev_server().await?.hot.unwrap_or_default()),
322315
)
323316
.resolve_entries(Vc::upcast(self.app_module_context())))
324317
}
325-
Platform::Node => Ok(EvaluatableAssets::empty()),
326318
}
327319
}
328320

329321
#[turbo_tasks::function]
330322
pub async fn app_module_context(self: Vc<Self>) -> Result<Vc<ModuleAssetContext>> {
331-
let platform = &*self.project().platform().await?;
332-
333-
let compile_time_info = match platform {
334-
Platform::Web => self.project().client_compile_time_info(),
335-
Platform::Node => self.project().server_compile_time_info(),
336-
};
323+
let project = self.project();
324+
let platform = &*project.platform().await?;
337325

338326
let layer = match platform {
339-
Platform::Web => {
340-
Layer::new_with_user_friendly_name(rcstr!("client"), rcstr!("Browser"))
341-
}
342327
Platform::Node => {
343328
Layer::new_with_user_friendly_name(rcstr!("server"), rcstr!("Nodejs"))
344329
}
330+
Platform::Web => {
331+
Layer::new_with_user_friendly_name(rcstr!("client"), rcstr!("Browser"))
332+
}
345333
};
346334

347335
Ok(ModuleAssetContext::new(
@@ -350,7 +338,7 @@ impl AppEndpoint {
350338
..Default::default()
351339
}
352340
.cell(),
353-
compile_time_info,
341+
project.compile_time_info_for_platform(),
354342
self.app_module_options_context(),
355343
self.app_resolve_options_context(),
356344
layer,
@@ -359,42 +347,44 @@ impl AppEndpoint {
359347

360348
#[turbo_tasks::function]
361349
async fn app_module_options_context(self: Vc<Self>) -> Result<Vc<ModuleOptionsContext>> {
362-
match &*self.project().platform().await? {
363-
Platform::Web => Ok(get_client_module_options_context(
364-
self.project().project_path().owned().await?,
365-
self.project().execution_context(),
366-
self.project().client_compile_time_info().environment(),
367-
self.project().mode(),
368-
self.project().config(),
369-
Vc::cell(self.project().await?.watch.enable),
370-
self.project().pack_path().owned().await?,
371-
)),
350+
let project = self.project();
351+
match &*project.platform().await? {
372352
Platform::Node => Ok(get_server_module_options_context(
373-
self.project().project_path().owned().await?,
374-
self.project().execution_context(),
375-
self.project().server_compile_time_info().environment(),
376-
self.project().mode(),
377-
self.project().config(),
353+
project.project_path().owned().await?,
354+
project.execution_context(),
355+
project.server_compile_time_info().environment(),
356+
project.mode(),
357+
project.config(),
358+
)),
359+
Platform::Web => Ok(get_client_module_options_context(
360+
project.project_path().owned().await?,
361+
project.execution_context(),
362+
project.client_compile_time_info().environment(),
363+
project.mode(),
364+
project.config(),
365+
Vc::cell(project.await?.watch.enable),
366+
project.pack_path().owned().await?,
378367
)),
379368
}
380369
}
381370

382371
#[turbo_tasks::function]
383372
async fn app_resolve_options_context(self: Vc<Self>) -> Result<Vc<ResolveOptionsContext>> {
384-
match &*self.project().platform().await? {
385-
Platform::Web => Ok(get_client_resolve_options_context(
386-
self.project().project_path().owned().await?,
387-
self.project().mode(),
388-
self.project().config(),
389-
self.project().execution_context(),
390-
self.project().pack_path().owned().await?,
391-
)),
373+
let project = self.project();
374+
match &*project.platform().await? {
392375
Platform::Node => Ok(get_server_resolve_options_context(
393-
self.project().project_path().owned().await?,
394-
self.project().mode(),
395-
self.project().config(),
396-
self.project().execution_context(),
397-
self.project().pack_path().owned().await?,
376+
project.project_path().owned().await?,
377+
project.mode(),
378+
project.config(),
379+
project.execution_context(),
380+
project.pack_path().owned().await?,
381+
)),
382+
Platform::Web => Ok(get_client_resolve_options_context(
383+
project.project_path().owned().await?,
384+
project.mode(),
385+
project.config(),
386+
project.execution_context(),
387+
project.pack_path().owned().await?,
398388
)),
399389
}
400390
}

crates/pack-api/src/library.rs

Lines changed: 80 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use anyhow::{Result, bail};
2-
use pack_core::{
3-
client::context::{
4-
get_client_module_options_context, get_client_resolve_options_context,
5-
get_client_runtime_entries,
6-
},
7-
library::contexts::{LibraryChunkingContextOptions, get_library_chunking_context},
8-
util::convert_to_project_relative,
2+
use pack_core::client::context::{
3+
get_client_module_options_context, get_client_resolve_options_context,
4+
get_client_runtime_entries,
5+
};
6+
use pack_core::config::Platform;
7+
8+
use pack_core::library::contexts::{LibraryChunkingContextOptions, get_library_chunking_context};
9+
use pack_core::server::contexts::{
10+
get_server_module_options_context, get_server_resolve_options_context,
911
};
12+
use pack_core::util::convert_to_project_relative;
1013
use tracing::{Instrument, trace_span};
1114
use turbo_rcstr::{RcStr, rcstr};
1215
use turbo_tasks::{Completion, JoinIterExt, ResolvedVc, ValueToString, Vc};
@@ -125,56 +128,96 @@ impl LibraryEndpoint {
125128

126129
#[turbo_tasks::function]
127130
async fn library_module_context(self: Vc<Self>) -> Result<Vc<ModuleAssetContext>> {
131+
let project = self.project();
132+
let platform = &*project.platform().await?;
133+
134+
let layer = match platform {
135+
Platform::Node => Layer::new_with_user_friendly_name(
136+
rcstr!("library-server"),
137+
rcstr!("Library (Node)"),
138+
),
139+
Platform::Web => Layer::new_with_user_friendly_name(
140+
rcstr!("library-client"),
141+
rcstr!("Library (Web)"),
142+
),
143+
};
144+
128145
Ok(ModuleAssetContext::new(
129146
// FIXME:
130147
TransitionOptions {
131148
..Default::default()
132149
}
133150
.cell(),
134-
self.project().client_compile_time_info(),
151+
project.compile_time_info_for_platform(),
135152
self.library_module_options_context(),
136153
self.library_resolve_options_context(),
137-
Layer::new_with_user_friendly_name(rcstr!("library"), rcstr!("Umd")),
154+
layer,
138155
))
139156
}
140157

141158
#[turbo_tasks::function]
142159
async fn library_module_options_context(self: Vc<Self>) -> Result<Vc<ModuleOptionsContext>> {
143-
Ok(get_client_module_options_context(
144-
self.project().project_path().owned().await?,
145-
self.project().execution_context(),
146-
self.project().client_compile_time_info().environment(),
147-
self.project().mode(),
148-
self.project().config(),
149-
Vc::cell(false),
150-
self.project().pack_path().owned().await?,
151-
))
160+
let project = self.project();
161+
match &*project.platform().await? {
162+
Platform::Node => Ok(get_server_module_options_context(
163+
project.project_path().owned().await?,
164+
project.execution_context(),
165+
project.server_compile_time_info().environment(),
166+
project.mode(),
167+
project.config(),
168+
)),
169+
Platform::Web => Ok(get_client_module_options_context(
170+
project.project_path().owned().await?,
171+
project.execution_context(),
172+
project.client_compile_time_info().environment(),
173+
project.mode(),
174+
project.config(),
175+
Vc::cell(false),
176+
project.pack_path().owned().await?,
177+
)),
178+
}
152179
}
153180

154181
#[turbo_tasks::function]
155182
async fn library_resolve_options_context(self: Vc<Self>) -> Result<Vc<ResolveOptionsContext>> {
156-
Ok(get_client_resolve_options_context(
157-
self.project().project_path().owned().await?,
158-
self.project().mode(),
159-
self.project().config(),
160-
self.project().execution_context(),
161-
self.project().pack_path().owned().await?,
162-
))
183+
let project = self.project();
184+
match &*project.platform().await? {
185+
Platform::Node => Ok(get_server_resolve_options_context(
186+
project.project_path().owned().await?,
187+
project.mode(),
188+
project.config(),
189+
project.execution_context(),
190+
project.pack_path().owned().await?,
191+
)),
192+
Platform::Web => Ok(get_client_resolve_options_context(
193+
project.project_path().owned().await?,
194+
project.mode(),
195+
project.config(),
196+
project.execution_context(),
197+
project.pack_path().owned().await?,
198+
)),
199+
}
163200
}
164201

165202
#[turbo_tasks::function]
166203
async fn library_runtime_entries(self: Vc<Self>) -> Result<Vc<EvaluatableAssets>> {
167-
Ok(get_client_runtime_entries(
168-
self.project().project_path().owned().await?,
169-
self.project().mode(),
170-
self.project().config(),
171-
self.project().execution_context(),
172-
self.project().pack_path().owned().await?,
173-
// Library project not support watch mode
174-
Vc::cell(false),
175-
Vc::cell(false),
176-
)
177-
.resolve_entries(Vc::upcast(self.library_module_context())))
204+
let project = self.project();
205+
match &*project.platform().await? {
206+
Platform::Node => Ok(EvaluatableAssets::empty()),
207+
Platform::Web => {
208+
Ok(get_client_runtime_entries(
209+
project.project_path().owned().await?,
210+
project.mode(),
211+
project.config(),
212+
project.execution_context(),
213+
project.pack_path().owned().await?,
214+
// Library project not support watch mode
215+
Vc::cell(false),
216+
Vc::cell(false),
217+
)
218+
.resolve_entries(Vc::upcast(self.library_module_context())))
219+
}
220+
}
178221
}
179222

180223
#[turbo_tasks::function]
@@ -257,6 +300,7 @@ impl LibraryEndpoint {
257300
config: project.config(),
258301
export_usage: project.export_usage(),
259302
unused_references: project.unused_references(),
303+
platform: project.platform(),
260304
},
261305
))
262306
}

crates/pack-api/src/project.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,27 @@ impl Project {
10361036
))
10371037
}
10381038

1039+
/// Returns the appropriate compile-time info for the given platform.
1040+
#[turbo_tasks::function]
1041+
pub(super) async fn compile_time_info_for_platform(&self) -> Result<Vc<CompileTimeInfo>> {
1042+
let define_env = (*self.config.define_env().await?).clone();
1043+
let target = (*self.config.target().await?).clone();
1044+
let define_env_vc = Vc::cell(define_env);
1045+
match &*self.config.platform().await? {
1046+
Platform::Web => Ok(get_client_compile_time_info(
1047+
target,
1048+
define_env_vc,
1049+
self.config.mode(),
1050+
self.config.provider_config(),
1051+
)),
1052+
Platform::Node => Ok(get_server_compile_time_info(
1053+
target,
1054+
define_env_vc,
1055+
self.config.provider_config(),
1056+
)),
1057+
}
1058+
}
1059+
10391060
#[turbo_tasks::function]
10401061
pub async fn client_chunking_context(self: Vc<Self>) -> Result<Vc<Box<dyn ChunkingContext>>> {
10411062
let mode = self.mode();

0 commit comments

Comments
 (0)