turbopack_ecmascript/references/
exports_info.rs1use anyhow::Result;
2use bincode::{Decode, Encode};
3use swc_core::{
4 common::DUMMY_SP,
5 ecma::ast::{Expr, Ident, KeyValueProp, ObjectLit, PropName, PropOrSpread},
6 quote,
7};
8use turbo_rcstr::rcstr;
9use turbo_tasks::{NonLocalValue, ResolvedVc, Vc, debug::ValueDebugFormat, trace::TraceRawVcs};
10use turbopack_core::chunk::ChunkingContext;
11
12use crate::{
13 chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
14 code_gen::{CodeGen, CodeGeneration},
15 create_visitor, magic_identifier,
16 references::AstPath,
17};
18
19#[derive(
27 PartialEq, Eq, TraceRawVcs, ValueDebugFormat, NonLocalValue, Hash, Debug, Encode, Decode,
28)]
29pub struct ExportsInfoBinding {}
30
31impl ExportsInfoBinding {
32 #[allow(clippy::new_without_default)]
33 pub fn new() -> Self {
34 ExportsInfoBinding {}
35 }
36
37 pub async fn code_generation(
38 &self,
39 chunking_context: Vc<Box<dyn ChunkingContext>>,
40 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
41 exports: ResolvedVc<EcmascriptExports>,
42 ) -> Result<CodeGeneration> {
43 let export_usage_info = chunking_context
44 .module_export_usage(*ResolvedVc::upcast(module))
45 .await?;
46 let export_usage_info = export_usage_info.export_usage.await?;
47
48 let props = if let EcmascriptExports::EsmExports(exports) = &*exports.await? {
49 exports
50 .await?
51 .exports
52 .keys()
53 .map(|e| {
54 let used: Expr = export_usage_info.is_export_used(e).into();
55 PropOrSpread::Prop(Box::new(swc_core::ecma::ast::Prop::KeyValue(
56 KeyValueProp {
57 key: PropName::Str(e.as_str().into()),
58 value: quote!("{ used: $v }" as Box<Expr>, v: Expr = used),
59 },
60 )))
61 })
62 .collect()
63 } else {
64 vec![]
65 };
66
67 let data = Expr::Object(ObjectLit {
68 props,
69 span: DUMMY_SP,
70 });
71
72 Ok(CodeGeneration::hoisted_stmt(
73 rcstr!("__webpack_exports_info__"),
74 quote!(
75 "const $name = $data;" as Stmt,
76 name = exports_ident(),
77 data: Expr = data
78 ),
79 ))
80 }
81}
82
83impl From<ExportsInfoBinding> for CodeGen {
84 fn from(val: ExportsInfoBinding) -> Self {
85 CodeGen::ExportsInfoBinding(val)
86 }
87}
88
89#[derive(
95 PartialEq, Eq, TraceRawVcs, ValueDebugFormat, NonLocalValue, Hash, Debug, Encode, Decode,
96)]
97pub struct ExportsInfoRef {
98 ast_path: AstPath,
99}
100
101impl ExportsInfoRef {
102 pub fn new(ast_path: AstPath) -> Self {
103 ExportsInfoRef { ast_path }
104 }
105
106 pub async fn code_generation(
107 &self,
108 _chunking_context: Vc<Box<dyn ChunkingContext>>,
109 ) -> Result<CodeGeneration> {
110 let visitor = create_visitor!(self.ast_path, visit_mut_expr, |expr: &mut Expr| {
111 *expr = Expr::Ident(exports_ident());
112 });
113
114 Ok(CodeGeneration::visitors(vec![visitor]))
115 }
116}
117
118impl From<ExportsInfoRef> for CodeGen {
119 fn from(val: ExportsInfoRef) -> Self {
120 CodeGen::ExportsInfoRef(val)
121 }
122}
123
124fn exports_ident() -> Ident {
125 Ident::new(
126 magic_identifier::mangle("__webpack_exports_info__").into(),
127 DUMMY_SP,
128 Default::default(),
129 )
130}