Skip to content

Commit 0c6496f

Browse files
wmertensshairez
andauthored
feat(optimizer): don't qwik-transform lib builds (#6850)
* feat(optimizer): don't qwik-transform lib builds this way libraries won't use internal APIs that may break between minor versions * formatted changeset --------- Co-authored-by: Shai Reznik <shairez@users.noreply.github.com>
1 parent d918278 commit 0c6496f

File tree

6 files changed

+180
-149
lines changed

6 files changed

+180
-149
lines changed

.changeset/moody-squids-listen.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@builder.io/qwik': patch
3+
---
4+
5+
✨ Lib builds no longer perform qwik transformation.
6+
7+
This prevents using unstable internal APIs, and doesn't make a difference for the end user. Library authors are strongly urged to push a new library patch version built with this qwik version, and to add `| ^2.0.0` to their accepted qwik version range.

Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ test:
3030

3131
test-update:
3232
if ! cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; then \
33-
cd packages/qwik/src/optimizer/core/src/snapshots/ && for i in *.new; do f=$$(basename $$i .new); mv $$i $$f; done; \
33+
cd packages/qwik/src/optimizer/core/src/snapshots/; \
34+
for i in *.new; do f=$$(basename $$i .new); mv $$i $$f; done; \
35+
cd -; \
3436
cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; \
3537
fi
3638

packages/qwik/src/optimizer/core/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ pub fn transform_fs(config: TransformFsOptions) -> Result<TransformOutput, Error
154154
strip_ctx_name: config.strip_ctx_name.as_deref(),
155155
strip_event_handlers: config.strip_event_handlers,
156156
// If you don't specify is_server, the safe value is true
157-
// For libraries, is_server has to be true because we neet to emit extra code
158-
is_server: config.mode == EmitMode::Lib || config.is_server.unwrap_or(true),
157+
is_server: config.is_server.unwrap_or(true),
159158
})
160159
})
161160
.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)))?;
@@ -200,8 +199,7 @@ pub fn transform_modules(config: TransformModulesOptions) -> Result<TransformOut
200199
strip_ctx_name: config.strip_ctx_name.as_deref(),
201200
strip_event_handlers: config.strip_event_handlers,
202201
// If you don't specify is_server, the safe value is true
203-
// For libraries, is_server has to be true because we neet to emit extra code
204-
is_server: config.mode == EmitMode::Lib || config.is_server.unwrap_or(true),
202+
is_server: config.is_server.unwrap_or(true),
205203
})
206204
});
207205

packages/qwik/src/optimizer/core/src/parse.rs

+155-128
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::const_replace::ConstReplacerVisitor;
1313
use crate::entry_strategy::EntryPolicy;
1414
use crate::filter_exports::StripExportsVisitor;
1515
use crate::props_destructuring::transform_props_destructuring;
16-
use crate::transform::{QwikTransform, QwikTransformOptions, SegmentKind};
16+
use crate::transform::{QwikTransform, QwikTransformOptions, Segment, SegmentKind};
1717
use crate::utils::{Diagnostic, DiagnosticCategory, DiagnosticScope, SourceLocation};
1818
use crate::EntryStrategy;
1919
use path_slash::PathExt;
@@ -68,6 +68,7 @@ pub enum EmitMode {
6868
Prod,
6969
Lib,
7070
Dev,
71+
Test,
7172
}
7273

7374
pub struct TransformCodeOptions<'a> {
@@ -294,64 +295,57 @@ pub fn transform_code(config: TransformCodeOptions) -> Result<TransformOutput, a
294295
// Collect import/export metadata
295296
let mut collect = global_collect(&program);
296297

297-
transform_props_destructuring(&mut program, &mut collect, &config.core_module);
298+
let mut qt: Option<QwikTransform<'_>> = None;
299+
let mut segments: Vec<Segment> = Vec::new();
298300

299-
// Replace const values
301+
// Don't further process library code
302+
// It will be processed during client build
303+
// This way no internal API usage is published
300304
if config.mode != EmitMode::Lib {
301305
let is_dev = config.mode == EmitMode::Dev;
302-
let mut const_replacer =
303-
ConstReplacerVisitor::new(config.is_server, is_dev, &collect);
304-
program.visit_mut_with(&mut const_replacer);
305-
}
306-
let mut qwik_transform = QwikTransform::new(QwikTransformOptions {
307-
path_data: &path_data,
308-
entry_policy: config.entry_policy,
309-
explicit_extensions: config.explicit_extensions,
310-
extension: extension.clone(),
311-
comments: Some(&comments),
312-
global_collect: collect,
313-
scope: config.scope,
314-
mode: config.mode,
315-
core_module: config.core_module,
316-
entry_strategy: config.entry_strategy,
317-
reg_ctx_name: config.reg_ctx_name,
318-
strip_ctx_name: config.strip_ctx_name,
319-
strip_event_handlers: config.strip_event_handlers,
320-
is_server: config.is_server,
321-
cm: Lrc::clone(&source_map),
322-
});
323306

324-
// Run main transform
325-
program = program.fold_with(&mut qwik_transform);
307+
// reconstruct destructured props for signal forwarding
308+
transform_props_destructuring(
309+
&mut program,
310+
&mut collect,
311+
&config.core_module,
312+
);
313+
314+
// replace const values
315+
if config.mode != EmitMode::Test {
316+
let mut const_replacer =
317+
ConstReplacerVisitor::new(config.is_server, is_dev, &collect);
318+
program.visit_mut_with(&mut const_replacer);
319+
}
326320

327-
let mut treeshaker = Treeshaker::new();
321+
// split into segments
322+
let mut qwik_transform = QwikTransform::new(QwikTransformOptions {
323+
path_data: &path_data,
324+
entry_policy: config.entry_policy,
325+
explicit_extensions: config.explicit_extensions,
326+
extension: extension.clone(),
327+
comments: Some(&comments),
328+
global_collect: collect,
329+
scope: config.scope,
330+
mode: config.mode,
331+
core_module: config.core_module,
332+
entry_strategy: config.entry_strategy,
333+
reg_ctx_name: config.reg_ctx_name,
334+
strip_ctx_name: config.strip_ctx_name,
335+
strip_event_handlers: config.strip_event_handlers,
336+
is_server: config.is_server,
337+
cm: Lrc::clone(&source_map),
338+
});
339+
program = program.fold_with(&mut qwik_transform);
328340

329-
if config.minify != MinifyMode::None {
330-
program.visit_mut_with(&mut treeshaker.marker);
341+
let mut treeshaker = Treeshaker::new();
342+
if config.minify != MinifyMode::None {
343+
// remove all side effects from client, step 1
344+
if !config.is_server {
345+
program.visit_mut_with(&mut treeshaker.marker);
346+
}
331347

332-
program = program.fold_with(&mut simplify::simplifier(
333-
unresolved_mark,
334-
simplify::Config {
335-
dce: simplify::dce::Config {
336-
preserve_imports_with_side_effects: false,
337-
..Default::default()
338-
},
339-
..Default::default()
340-
},
341-
));
342-
}
343-
if matches!(
344-
config.entry_strategy,
345-
EntryStrategy::Inline | EntryStrategy::Hoist
346-
) {
347-
program.visit_mut_with(&mut SideEffectVisitor::new(
348-
&qwik_transform.options.global_collect,
349-
&path_data,
350-
config.src_dir,
351-
));
352-
} else if config.minify != MinifyMode::None && !config.is_server {
353-
program.visit_mut_with(&mut treeshaker.cleaner);
354-
if treeshaker.cleaner.did_drop {
348+
// simplify & strip unused code
355349
program = program.fold_with(&mut simplify::simplifier(
356350
unresolved_mark,
357351
simplify::Config {
@@ -363,90 +357,123 @@ pub fn transform_code(config: TransformCodeOptions) -> Result<TransformOutput, a
363357
},
364358
));
365359
}
360+
if matches!(
361+
config.entry_strategy,
362+
EntryStrategy::Inline | EntryStrategy::Hoist
363+
) {
364+
program.visit_mut_with(&mut SideEffectVisitor::new(
365+
&qwik_transform.options.global_collect,
366+
&path_data,
367+
config.src_dir,
368+
));
369+
} else if config.minify != MinifyMode::None && !config.is_server {
370+
// remove all side effects from client, step 2
371+
program.visit_mut_with(&mut treeshaker.cleaner);
372+
if treeshaker.cleaner.did_drop {
373+
program = program.fold_with(&mut simplify::simplifier(
374+
unresolved_mark,
375+
simplify::Config {
376+
dce: simplify::dce::Config {
377+
preserve_imports_with_side_effects: false,
378+
..Default::default()
379+
},
380+
..Default::default()
381+
},
382+
));
383+
}
384+
}
385+
segments = qwik_transform.segments.clone();
386+
qt = Some(qwik_transform);
366387
}
367388
program.visit_mut_with(&mut hygiene_with_config(Default::default()));
368389
program.visit_mut_with(&mut fixer(None));
369390

370-
let segments = qwik_transform.segments;
371391
let mut modules: Vec<TransformModule> = Vec::with_capacity(segments.len() + 10);
372392

373393
let comments_maps = comments.clone().take_all();
374-
for h in segments.into_iter() {
375-
let is_entry = h.entry.is_none();
376-
let path_str = h.data.path.to_string();
377-
let path = if path_str.is_empty() {
378-
path_str
379-
} else {
380-
[&path_str, "/"].concat()
381-
};
382-
let segment_path = [
383-
path,
384-
[&h.canonical_filename, ".", &h.data.extension].concat(),
385-
]
386-
.concat();
387-
let need_handle_watch =
388-
might_need_handle_watch(&h.data.ctx_kind, &h.data.ctx_name);
389-
390-
let (mut segment_module, comments) = new_module(NewModuleCtx {
391-
expr: h.expr,
392-
path: &path_data,
393-
name: &h.name,
394-
local_idents: &h.data.local_idents,
395-
scoped_idents: &h.data.scoped_idents,
396-
need_transform: h.data.need_transform,
397-
explicit_extensions: qwik_transform.options.explicit_extensions,
398-
global: &qwik_transform.options.global_collect,
399-
core_module: &qwik_transform.options.core_module,
400-
need_handle_watch,
401-
leading_comments: comments_maps.0.clone(),
402-
trailing_comments: comments_maps.1.clone(),
403-
})?;
404-
if config.minify != MinifyMode::None {
405-
segment_module = segment_module.fold_with(&mut simplify::simplifier(
406-
unresolved_mark,
407-
simplify::Config {
408-
dce: simplify::dce::Config {
409-
preserve_imports_with_side_effects: false,
410-
..Default::default()
411-
},
412-
..Default::default()
413-
},
414-
));
394+
// Now process each segment
395+
if !segments.is_empty() {
396+
let q = qt.as_ref().unwrap();
397+
for h in segments.into_iter() {
398+
let is_entry = h.entry.is_none();
399+
let path_str = h.data.path.to_string();
400+
let path = if path_str.is_empty() {
401+
path_str
402+
} else {
403+
[&path_str, "/"].concat()
404+
};
405+
let segment_path = [
406+
path,
407+
[&h.canonical_filename, ".", &h.data.extension].concat(),
408+
]
409+
.concat();
410+
let need_handle_watch =
411+
might_need_handle_watch(&h.data.ctx_kind, &h.data.ctx_name);
412+
413+
let (mut segment_module, comments) = new_module(NewModuleCtx {
414+
expr: h.expr,
415+
path: &path_data,
416+
name: &h.name,
417+
local_idents: &h.data.local_idents,
418+
scoped_idents: &h.data.scoped_idents,
419+
need_transform: h.data.need_transform,
420+
explicit_extensions: q.options.explicit_extensions,
421+
global: &q.options.global_collect,
422+
core_module: &q.options.core_module,
423+
need_handle_watch,
424+
leading_comments: comments_maps.0.clone(),
425+
trailing_comments: comments_maps.1.clone(),
426+
})?;
427+
// we don't need to remove side effects because the optimizer only moves what's really used
428+
if config.minify != MinifyMode::None {
429+
segment_module =
430+
segment_module.fold_with(&mut simplify::simplifier(
431+
unresolved_mark,
432+
simplify::Config {
433+
dce: simplify::dce::Config {
434+
preserve_imports_with_side_effects: false,
435+
..Default::default()
436+
},
437+
..Default::default()
438+
},
439+
));
440+
}
441+
segment_module
442+
.visit_mut_with(&mut hygiene_with_config(Default::default()));
443+
segment_module.visit_mut_with(&mut fixer(None));
444+
445+
let (code, map) = emit_source_code(
446+
Lrc::clone(&source_map),
447+
Some(comments),
448+
&segment_module,
449+
config.root_dir,
450+
config.source_maps,
451+
)
452+
.unwrap();
453+
454+
modules.push(TransformModule {
455+
code,
456+
map,
457+
is_entry,
458+
path: segment_path,
459+
order: h.hash,
460+
segment: Some(SegmentAnalysis {
461+
origin: h.data.origin,
462+
name: h.name,
463+
entry: h.entry,
464+
extension: h.data.extension,
465+
canonical_filename: h.canonical_filename,
466+
path: h.data.path,
467+
parent: h.data.parent_segment,
468+
ctx_kind: h.data.ctx_kind,
469+
ctx_name: h.data.ctx_name,
470+
captures: !h.data.scoped_idents.is_empty(),
471+
display_name: h.data.display_name,
472+
hash: h.data.hash,
473+
loc: (h.span.lo.0, h.span.hi.0),
474+
}),
475+
});
415476
}
416-
segment_module.visit_mut_with(&mut hygiene_with_config(Default::default()));
417-
segment_module.visit_mut_with(&mut fixer(None));
418-
419-
let (code, map) = emit_source_code(
420-
Lrc::clone(&source_map),
421-
Some(comments),
422-
&segment_module,
423-
config.root_dir,
424-
config.source_maps,
425-
)
426-
.unwrap();
427-
428-
modules.push(TransformModule {
429-
code,
430-
map,
431-
is_entry,
432-
path: segment_path,
433-
order: h.hash,
434-
segment: Some(SegmentAnalysis {
435-
origin: h.data.origin,
436-
name: h.name,
437-
entry: h.entry,
438-
extension: h.data.extension,
439-
canonical_filename: h.canonical_filename,
440-
path: h.data.path,
441-
parent: h.data.parent_segment,
442-
ctx_kind: h.data.ctx_kind,
443-
ctx_name: h.data.ctx_name,
444-
captures: !h.data.scoped_idents.is_empty(),
445-
display_name: h.data.display_name,
446-
hash: h.data.hash,
447-
loc: (h.span.lo.0, h.span.hi.0),
448-
}),
449-
});
450477
}
451478

452479
let (code, map) = match program {

0 commit comments

Comments
 (0)