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>
This commit is contained in:
7
.changeset/moody-squids-listen.md
Normal file
7
.changeset/moody-squids-listen.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@builder.io/qwik': patch
|
||||
---
|
||||
|
||||
✨ Lib builds no longer perform qwik transformation.
|
||||
|
||||
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.
|
||||
4
Makefile
4
Makefile
@@ -30,7 +30,9 @@ test:
|
||||
|
||||
test-update:
|
||||
if ! cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; then \
|
||||
cd packages/qwik/src/optimizer/core/src/snapshots/ && for i in *.new; do f=$$(basename $$i .new); mv $$i $$f; done; \
|
||||
cd packages/qwik/src/optimizer/core/src/snapshots/; \
|
||||
for i in *.new; do f=$$(basename $$i .new); mv $$i $$f; done; \
|
||||
cd -; \
|
||||
cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; \
|
||||
fi
|
||||
|
||||
|
||||
@@ -154,8 +154,7 @@ pub fn transform_fs(config: TransformFsOptions) -> Result<TransformOutput, Error
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
// If you don't specify is_server, the safe value is true
|
||||
// For libraries, is_server has to be true because we neet to emit extra code
|
||||
is_server: config.mode == EmitMode::Lib || config.is_server.unwrap_or(true),
|
||||
is_server: config.is_server.unwrap_or(true),
|
||||
})
|
||||
})
|
||||
.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)))?;
|
||||
@@ -200,8 +199,7 @@ pub fn transform_modules(config: TransformModulesOptions) -> Result<TransformOut
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
// If you don't specify is_server, the safe value is true
|
||||
// For libraries, is_server has to be true because we neet to emit extra code
|
||||
is_server: config.mode == EmitMode::Lib || config.is_server.unwrap_or(true),
|
||||
is_server: config.is_server.unwrap_or(true),
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::const_replace::ConstReplacerVisitor;
|
||||
use crate::entry_strategy::EntryPolicy;
|
||||
use crate::filter_exports::StripExportsVisitor;
|
||||
use crate::props_destructuring::transform_props_destructuring;
|
||||
use crate::transform::{QwikTransform, QwikTransformOptions, SegmentKind};
|
||||
use crate::transform::{QwikTransform, QwikTransformOptions, Segment, SegmentKind};
|
||||
use crate::utils::{Diagnostic, DiagnosticCategory, DiagnosticScope, SourceLocation};
|
||||
use crate::EntryStrategy;
|
||||
use path_slash::PathExt;
|
||||
@@ -68,6 +68,7 @@ pub enum EmitMode {
|
||||
Prod,
|
||||
Lib,
|
||||
Dev,
|
||||
Test,
|
||||
}
|
||||
|
||||
pub struct TransformCodeOptions<'a> {
|
||||
@@ -294,64 +295,57 @@ pub fn transform_code(config: TransformCodeOptions) -> Result<TransformOutput, a
|
||||
// Collect import/export metadata
|
||||
let mut collect = global_collect(&program);
|
||||
|
||||
transform_props_destructuring(&mut program, &mut collect, &config.core_module);
|
||||
let mut qt: Option<QwikTransform<'_>> = None;
|
||||
let mut segments: Vec<Segment> = Vec::new();
|
||||
|
||||
// Replace const values
|
||||
// Don't further process library code
|
||||
// It will be processed during client build
|
||||
// This way no internal API usage is published
|
||||
if config.mode != EmitMode::Lib {
|
||||
let is_dev = config.mode == EmitMode::Dev;
|
||||
let mut const_replacer =
|
||||
ConstReplacerVisitor::new(config.is_server, is_dev, &collect);
|
||||
program.visit_mut_with(&mut const_replacer);
|
||||
}
|
||||
let mut qwik_transform = QwikTransform::new(QwikTransformOptions {
|
||||
path_data: &path_data,
|
||||
entry_policy: config.entry_policy,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
extension: extension.clone(),
|
||||
comments: Some(&comments),
|
||||
global_collect: collect,
|
||||
scope: config.scope,
|
||||
mode: config.mode,
|
||||
core_module: config.core_module,
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name,
|
||||
strip_ctx_name: config.strip_ctx_name,
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
cm: Lrc::clone(&source_map),
|
||||
});
|
||||
|
||||
// Run main transform
|
||||
program = program.fold_with(&mut qwik_transform);
|
||||
// reconstruct destructured props for signal forwarding
|
||||
transform_props_destructuring(
|
||||
&mut program,
|
||||
&mut collect,
|
||||
&config.core_module,
|
||||
);
|
||||
|
||||
let mut treeshaker = Treeshaker::new();
|
||||
// replace const values
|
||||
if config.mode != EmitMode::Test {
|
||||
let mut const_replacer =
|
||||
ConstReplacerVisitor::new(config.is_server, is_dev, &collect);
|
||||
program.visit_mut_with(&mut const_replacer);
|
||||
}
|
||||
|
||||
if config.minify != MinifyMode::None {
|
||||
program.visit_mut_with(&mut treeshaker.marker);
|
||||
// split into segments
|
||||
let mut qwik_transform = QwikTransform::new(QwikTransformOptions {
|
||||
path_data: &path_data,
|
||||
entry_policy: config.entry_policy,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
extension: extension.clone(),
|
||||
comments: Some(&comments),
|
||||
global_collect: collect,
|
||||
scope: config.scope,
|
||||
mode: config.mode,
|
||||
core_module: config.core_module,
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name,
|
||||
strip_ctx_name: config.strip_ctx_name,
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
cm: Lrc::clone(&source_map),
|
||||
});
|
||||
program = program.fold_with(&mut qwik_transform);
|
||||
|
||||
program = program.fold_with(&mut simplify::simplifier(
|
||||
unresolved_mark,
|
||||
simplify::Config {
|
||||
dce: simplify::dce::Config {
|
||||
preserve_imports_with_side_effects: false,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
}
|
||||
if matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
program.visit_mut_with(&mut SideEffectVisitor::new(
|
||||
&qwik_transform.options.global_collect,
|
||||
&path_data,
|
||||
config.src_dir,
|
||||
));
|
||||
} else if config.minify != MinifyMode::None && !config.is_server {
|
||||
program.visit_mut_with(&mut treeshaker.cleaner);
|
||||
if treeshaker.cleaner.did_drop {
|
||||
let mut treeshaker = Treeshaker::new();
|
||||
if config.minify != MinifyMode::None {
|
||||
// remove all side effects from client, step 1
|
||||
if !config.is_server {
|
||||
program.visit_mut_with(&mut treeshaker.marker);
|
||||
}
|
||||
|
||||
// simplify & strip unused code
|
||||
program = program.fold_with(&mut simplify::simplifier(
|
||||
unresolved_mark,
|
||||
simplify::Config {
|
||||
@@ -363,90 +357,123 @@ pub fn transform_code(config: TransformCodeOptions) -> Result<TransformOutput, a
|
||||
},
|
||||
));
|
||||
}
|
||||
if matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
program.visit_mut_with(&mut SideEffectVisitor::new(
|
||||
&qwik_transform.options.global_collect,
|
||||
&path_data,
|
||||
config.src_dir,
|
||||
));
|
||||
} else if config.minify != MinifyMode::None && !config.is_server {
|
||||
// remove all side effects from client, step 2
|
||||
program.visit_mut_with(&mut treeshaker.cleaner);
|
||||
if treeshaker.cleaner.did_drop {
|
||||
program = program.fold_with(&mut simplify::simplifier(
|
||||
unresolved_mark,
|
||||
simplify::Config {
|
||||
dce: simplify::dce::Config {
|
||||
preserve_imports_with_side_effects: false,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
segments = qwik_transform.segments.clone();
|
||||
qt = Some(qwik_transform);
|
||||
}
|
||||
program.visit_mut_with(&mut hygiene_with_config(Default::default()));
|
||||
program.visit_mut_with(&mut fixer(None));
|
||||
|
||||
let segments = qwik_transform.segments;
|
||||
let mut modules: Vec<TransformModule> = Vec::with_capacity(segments.len() + 10);
|
||||
|
||||
let comments_maps = comments.clone().take_all();
|
||||
for h in segments.into_iter() {
|
||||
let is_entry = h.entry.is_none();
|
||||
let path_str = h.data.path.to_string();
|
||||
let path = if path_str.is_empty() {
|
||||
path_str
|
||||
} else {
|
||||
[&path_str, "/"].concat()
|
||||
};
|
||||
let segment_path = [
|
||||
path,
|
||||
[&h.canonical_filename, ".", &h.data.extension].concat(),
|
||||
]
|
||||
.concat();
|
||||
let need_handle_watch =
|
||||
might_need_handle_watch(&h.data.ctx_kind, &h.data.ctx_name);
|
||||
// Now process each segment
|
||||
if !segments.is_empty() {
|
||||
let q = qt.as_ref().unwrap();
|
||||
for h in segments.into_iter() {
|
||||
let is_entry = h.entry.is_none();
|
||||
let path_str = h.data.path.to_string();
|
||||
let path = if path_str.is_empty() {
|
||||
path_str
|
||||
} else {
|
||||
[&path_str, "/"].concat()
|
||||
};
|
||||
let segment_path = [
|
||||
path,
|
||||
[&h.canonical_filename, ".", &h.data.extension].concat(),
|
||||
]
|
||||
.concat();
|
||||
let need_handle_watch =
|
||||
might_need_handle_watch(&h.data.ctx_kind, &h.data.ctx_name);
|
||||
|
||||
let (mut segment_module, comments) = new_module(NewModuleCtx {
|
||||
expr: h.expr,
|
||||
path: &path_data,
|
||||
name: &h.name,
|
||||
local_idents: &h.data.local_idents,
|
||||
scoped_idents: &h.data.scoped_idents,
|
||||
need_transform: h.data.need_transform,
|
||||
explicit_extensions: qwik_transform.options.explicit_extensions,
|
||||
global: &qwik_transform.options.global_collect,
|
||||
core_module: &qwik_transform.options.core_module,
|
||||
need_handle_watch,
|
||||
leading_comments: comments_maps.0.clone(),
|
||||
trailing_comments: comments_maps.1.clone(),
|
||||
})?;
|
||||
if config.minify != MinifyMode::None {
|
||||
segment_module = segment_module.fold_with(&mut simplify::simplifier(
|
||||
unresolved_mark,
|
||||
simplify::Config {
|
||||
dce: simplify::dce::Config {
|
||||
preserve_imports_with_side_effects: false,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
let (mut segment_module, comments) = new_module(NewModuleCtx {
|
||||
expr: h.expr,
|
||||
path: &path_data,
|
||||
name: &h.name,
|
||||
local_idents: &h.data.local_idents,
|
||||
scoped_idents: &h.data.scoped_idents,
|
||||
need_transform: h.data.need_transform,
|
||||
explicit_extensions: q.options.explicit_extensions,
|
||||
global: &q.options.global_collect,
|
||||
core_module: &q.options.core_module,
|
||||
need_handle_watch,
|
||||
leading_comments: comments_maps.0.clone(),
|
||||
trailing_comments: comments_maps.1.clone(),
|
||||
})?;
|
||||
// we don't need to remove side effects because the optimizer only moves what's really used
|
||||
if config.minify != MinifyMode::None {
|
||||
segment_module =
|
||||
segment_module.fold_with(&mut simplify::simplifier(
|
||||
unresolved_mark,
|
||||
simplify::Config {
|
||||
dce: simplify::dce::Config {
|
||||
preserve_imports_with_side_effects: false,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
}
|
||||
segment_module
|
||||
.visit_mut_with(&mut hygiene_with_config(Default::default()));
|
||||
segment_module.visit_mut_with(&mut fixer(None));
|
||||
|
||||
let (code, map) = emit_source_code(
|
||||
Lrc::clone(&source_map),
|
||||
Some(comments),
|
||||
&segment_module,
|
||||
config.root_dir,
|
||||
config.source_maps,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
modules.push(TransformModule {
|
||||
code,
|
||||
map,
|
||||
is_entry,
|
||||
path: segment_path,
|
||||
order: h.hash,
|
||||
segment: Some(SegmentAnalysis {
|
||||
origin: h.data.origin,
|
||||
name: h.name,
|
||||
entry: h.entry,
|
||||
extension: h.data.extension,
|
||||
canonical_filename: h.canonical_filename,
|
||||
path: h.data.path,
|
||||
parent: h.data.parent_segment,
|
||||
ctx_kind: h.data.ctx_kind,
|
||||
ctx_name: h.data.ctx_name,
|
||||
captures: !h.data.scoped_idents.is_empty(),
|
||||
display_name: h.data.display_name,
|
||||
hash: h.data.hash,
|
||||
loc: (h.span.lo.0, h.span.hi.0),
|
||||
}),
|
||||
});
|
||||
}
|
||||
segment_module.visit_mut_with(&mut hygiene_with_config(Default::default()));
|
||||
segment_module.visit_mut_with(&mut fixer(None));
|
||||
|
||||
let (code, map) = emit_source_code(
|
||||
Lrc::clone(&source_map),
|
||||
Some(comments),
|
||||
&segment_module,
|
||||
config.root_dir,
|
||||
config.source_maps,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
modules.push(TransformModule {
|
||||
code,
|
||||
map,
|
||||
is_entry,
|
||||
path: segment_path,
|
||||
order: h.hash,
|
||||
segment: Some(SegmentAnalysis {
|
||||
origin: h.data.origin,
|
||||
name: h.name,
|
||||
entry: h.entry,
|
||||
extension: h.data.extension,
|
||||
canonical_filename: h.canonical_filename,
|
||||
path: h.data.path,
|
||||
parent: h.data.parent_segment,
|
||||
ctx_kind: h.data.ctx_kind,
|
||||
ctx_name: h.data.ctx_name,
|
||||
captures: !h.data.scoped_idents.is_empty(),
|
||||
display_name: h.data.display_name,
|
||||
hash: h.data.hash,
|
||||
loc: (h.span.lo.0, h.span.hi.0),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
let (code, map) = match program {
|
||||
|
||||
@@ -3285,7 +3285,7 @@ export const Local = component$(() => {
|
||||
source_maps: true,
|
||||
minify: MinifyMode::Simplify,
|
||||
explicit_extensions: true,
|
||||
mode: EmitMode::Lib,
|
||||
mode: EmitMode::Test,
|
||||
manual_chunks: None,
|
||||
entry_strategy: EntryStrategy::Segment,
|
||||
transpile_ts: true,
|
||||
@@ -3323,10 +3323,10 @@ export const Greeter = component$(() => {
|
||||
|
||||
"#;
|
||||
let options = vec![
|
||||
(EmitMode::Lib, EntryStrategy::Segment, true),
|
||||
(EmitMode::Lib, EntryStrategy::Single, true),
|
||||
(EmitMode::Lib, EntryStrategy::Component, true),
|
||||
// (EmitMode::Lib, EntryStrategy::Inline, true),
|
||||
(EmitMode::Test, EntryStrategy::Segment, true),
|
||||
(EmitMode::Test, EntryStrategy::Single, true),
|
||||
(EmitMode::Test, EntryStrategy::Component, true),
|
||||
// (EmitMode::Test, EntryStrategy::Inline, true),
|
||||
(EmitMode::Prod, EntryStrategy::Segment, true),
|
||||
(EmitMode::Prod, EntryStrategy::Single, true),
|
||||
(EmitMode::Prod, EntryStrategy::Component, true),
|
||||
@@ -3335,10 +3335,10 @@ export const Greeter = component$(() => {
|
||||
(EmitMode::Dev, EntryStrategy::Single, true),
|
||||
(EmitMode::Dev, EntryStrategy::Component, true),
|
||||
// (EmitMode::Dev, EntryStrategy::Inline, true),
|
||||
(EmitMode::Lib, EntryStrategy::Segment, false),
|
||||
(EmitMode::Lib, EntryStrategy::Single, false),
|
||||
(EmitMode::Lib, EntryStrategy::Component, false),
|
||||
// (EmitMode::Lib, EntryStrategy::Inline, false),
|
||||
(EmitMode::Test, EntryStrategy::Segment, false),
|
||||
(EmitMode::Test, EntryStrategy::Single, false),
|
||||
(EmitMode::Test, EntryStrategy::Component, false),
|
||||
// (EmitMode::Test, EntryStrategy::Inline, false),
|
||||
(EmitMode::Prod, EntryStrategy::Segment, false),
|
||||
(EmitMode::Prod, EntryStrategy::Single, false),
|
||||
(EmitMode::Prod, EntryStrategy::Component, false),
|
||||
@@ -3365,7 +3365,7 @@ export const Greeter = component$(() => {
|
||||
minify: MinifyMode::Simplify,
|
||||
root_dir: None,
|
||||
explicit_extensions: true,
|
||||
mode: EmitMode::Lib,
|
||||
mode: EmitMode::Test,
|
||||
manual_chunks: None,
|
||||
entry_strategy: EntryStrategy::Segment,
|
||||
transpile_ts: true,
|
||||
@@ -3556,9 +3556,6 @@ export const Counter = component$(() => {
|
||||
"#
|
||||
.to_string(),
|
||||
transpile_jsx: true,
|
||||
mode: EmitMode::Lib,
|
||||
// make sure it overrides it
|
||||
is_server: Some(false),
|
||||
..TestInput::default()
|
||||
});
|
||||
}
|
||||
@@ -3627,7 +3624,7 @@ impl TestInput {
|
||||
preserve_filenames: false,
|
||||
explicit_extensions: false,
|
||||
snapshot: true,
|
||||
mode: EmitMode::Lib,
|
||||
mode: EmitMode::Test,
|
||||
scope: None,
|
||||
core_module: None,
|
||||
reg_ctx_name: None,
|
||||
|
||||
@@ -335,7 +335,7 @@ impl<'a> QwikTransform<'a> {
|
||||
let hash = hasher.finish();
|
||||
let hash64 = base64(hash);
|
||||
|
||||
let symbol_name = if matches!(self.options.mode, EmitMode::Dev | EmitMode::Lib) {
|
||||
let symbol_name = if matches!(self.options.mode, EmitMode::Dev | EmitMode::Test) {
|
||||
format!("{}_{}", display_name, hash64)
|
||||
} else {
|
||||
format!("s_{}", hash64)
|
||||
@@ -386,7 +386,7 @@ impl<'a> QwikTransform<'a> {
|
||||
};
|
||||
parse_symbol_name(
|
||||
symbol_name,
|
||||
matches!(self.options.mode, EmitMode::Dev | EmitMode::Lib),
|
||||
matches!(self.options.mode, EmitMode::Dev | EmitMode::Test),
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user