Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(turbopack): Support marking packages as side-efffect-free #7863

Merged
merged 4 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions crates/turbopack-ecmascript/src/chunk/placeable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ pub trait EcmascriptChunkPlaceable: ChunkableModule + Module + Asset {
fn get_async_module(self: Vc<Self>) -> Vc<OptionAsyncModule> {
Vc::cell(None)
}
fn is_marked_as_side_effect_free(self: Vc<Self>) -> Vc<bool> {
is_marked_as_side_effect_free(self.ident().path())
fn is_marked_as_side_effect_free(
self: Vc<Self>,
side_effect_free_packages: Vc<Glob>,
) -> Vc<bool> {
is_marked_as_side_effect_free(self.ident().path(), side_effect_free_packages)
}
}

Expand Down Expand Up @@ -147,7 +150,14 @@ impl Issue for SideEffectsInPackageJsonIssue {
}

#[turbo_tasks::function]
pub async fn is_marked_as_side_effect_free(path: Vc<FileSystemPath>) -> Result<Vc<bool>> {
pub async fn is_marked_as_side_effect_free(
path: Vc<FileSystemPath>,
side_effect_free_packages: Vc<Glob>,
) -> Result<Vc<bool>> {
if side_effect_free_packages.await?.execute(&path.await?.path) {
return Ok(Vc::cell(true));
}

let find_package_json: turbo_tasks::ReadRef<FindContextFileResult> =
find_context_file(path.parent(), package_json()).await?;

Expand Down
17 changes: 14 additions & 3 deletions crates/turbopack-ecmascript/src/references/esm/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use swc_core::{
quote, quote_expr,
};
use turbo_tasks::{trace::TraceRawVcs, TryFlatJoinIterExt, ValueToString, Vc};
use turbo_tasks_fs::glob::Glob;
use turbopack_core::{
ident::AssetIdent,
issue::{analyze::AnalyzeIssue, IssueExt, IssueSeverity, StyledString},
Expand Down Expand Up @@ -62,8 +63,12 @@ pub struct FollowExportsResult {
pub async fn follow_reexports(
module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
export_name: String,
side_effect_free_packages: Vc<Glob>,
) -> Result<Vc<FollowExportsResult>> {
if !*module.is_marked_as_side_effect_free().await? {
if !*module
.is_marked_as_side_effect_free(side_effect_free_packages)
.await?
{
return Ok(FollowExportsResult::cell(FollowExportsResult {
module,
export_name: Some(export_name),
Expand All @@ -85,7 +90,9 @@ pub async fn follow_reexports(
// Try to find the export in the local exports
let exports_ref = exports.await?;
if let Some(export) = exports_ref.exports.get(&export_name) {
match handle_declared_export(module, export_name, export).await? {
match handle_declared_export(module, export_name, export, side_effect_free_packages)
.await?
{
ControlFlow::Continue((m, n)) => {
module = m;
export_name = n;
Expand Down Expand Up @@ -138,13 +145,17 @@ async fn handle_declared_export(
module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
export_name: String,
export: &EsmExport,
side_effect_free_packages: Vc<Glob>,
) -> Result<ControlFlow<FollowExportsResult, (Vc<Box<dyn EcmascriptChunkPlaceable>>, String)>> {
match export {
EsmExport::ImportedBinding(reference, name) => {
if let ReferencedAsset::Some(module) =
*ReferencedAsset::from_resolve_result(reference.resolve_reference()).await?
{
if !*module.is_marked_as_side_effect_free().await? {
if !*module
.is_marked_as_side_effect_free(side_effect_free_packages)
.await?
{
return Ok(ControlFlow::Break(FollowExportsResult {
module,
export_name: Some(name.to_string()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::BTreeMap;

use anyhow::{bail, Context, Result};
use turbo_tasks::Vc;
use turbo_tasks_fs::{File, FileContent};
use turbo_tasks_fs::{glob::Glob, File, FileContent};
use turbopack_core::{
asset::{Asset, AssetContent},
chunk::{ChunkableModule, ChunkingContext, EvaluatableAsset},
Expand Down Expand Up @@ -250,11 +250,14 @@ impl EcmascriptChunkPlaceable for EcmascriptModuleFacadeModule {
}

#[turbo_tasks::function]
async fn is_marked_as_side_effect_free(&self) -> Result<Vc<bool>> {
async fn is_marked_as_side_effect_free(
&self,
side_effect_free_packages: Vc<Glob>,
) -> Result<Vc<bool>> {
Ok(match *self.ty.await? {
ModulePart::Evaluation | ModulePart::Facade => {
self.module.is_marked_as_side_effect_free()
}
ModulePart::Evaluation | ModulePart::Facade => self
.module
.is_marked_as_side_effect_free(side_effect_free_packages),
ModulePart::Exports
| ModulePart::RenamedExport { .. }
| ModulePart::RenamedNamespace { .. } => Vc::cell(true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::BTreeMap;

use anyhow::{bail, Context, Result};
use turbo_tasks::Vc;
use turbo_tasks_fs::glob::Glob;
use turbopack_core::{
asset::{Asset, AssetContent},
chunk::{ChunkableModule, ChunkingContext},
Expand Down Expand Up @@ -94,8 +95,9 @@ impl EcmascriptChunkPlaceable for EcmascriptModuleLocalsModule {
}

#[turbo_tasks::function]
fn is_marked_as_side_effect_free(&self) -> Vc<bool> {
self.module.is_marked_as_side_effect_free()
fn is_marked_as_side_effect_free(&self, side_effect_free_packages: Vc<Glob>) -> Vc<bool> {
self.module
.is_marked_as_side_effect_free(side_effect_free_packages)
}

#[turbo_tasks::function]
Expand Down
37 changes: 33 additions & 4 deletions crates/turbopack/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use graph::{aggregate, AggregatedGraph, AggregatedGraphNodeContent};
use module_options::{ModuleOptions, ModuleOptionsContext, ModuleRuleEffect, ModuleType};
use tracing::Instrument;
use turbo_tasks::{Completion, Value, ValueToString, Vc};
use turbo_tasks_fs::FileSystemPath;
use turbo_tasks_fs::{glob::Glob, FileSystemPath};
pub use turbopack_core::condition;
use turbopack_core::{
asset::Asset,
Expand Down Expand Up @@ -171,11 +171,17 @@ async fn apply_module_type(
}
}
Some(TreeShakingMode::ReexportsOnly) => {
let side_effect_free_packages =
module_asset_context.side_effect_free_packages();

let module = builder.build();
if let Some(part) = part {
match *part.await? {
ModulePart::Evaluation => {
if *module.is_marked_as_side_effect_free().await? {
if *module
.is_marked_as_side_effect_free(side_effect_free_packages)
.await?
{
return Ok(ProcessResult::Ignore.cell());
}
if *module.get_exports().needs_facade().await? {
Expand All @@ -195,9 +201,14 @@ async fn apply_module_type(
ModulePart::exports(),
)),
part,
side_effect_free_packages,
)
} else {
apply_reexport_tree_shaking(Vc::upcast(module), part)
apply_reexport_tree_shaking(
Vc::upcast(module),
part,
side_effect_free_packages,
)
}
}
_ => bail!(
Expand Down Expand Up @@ -266,14 +277,15 @@ async fn apply_module_type(
async fn apply_reexport_tree_shaking(
module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
part: Vc<ModulePart>,
side_effect_free_packages: Vc<Glob>,
) -> Result<Vc<Box<dyn Module>>> {
if let ModulePart::Export(export) = *part.await? {
let export = export.await?;
let FollowExportsResult {
module: final_module,
export_name: new_export,
..
} = &*follow_reexports(module, export.clone_value()).await?;
} = &*follow_reexports(module, export.clone_value(), side_effect_free_packages).await?;
let module = if let Some(new_export) = new_export {
if *new_export == *export {
Vc::upcast(*final_module)
Expand Down Expand Up @@ -391,6 +403,23 @@ impl ModuleAssetContext {
) -> Vc<ProcessResult> {
process_default(self, source, reference_type, Vec::new())
}

#[turbo_tasks::function]
pub async fn side_effect_free_packages(self: Vc<Self>) -> Result<Vc<Glob>> {
let pkgs = &*self
.await?
.module_options_context
.await?
.side_effect_free_packages;

let mut globs = Vec::with_capacity(pkgs.len());

for pkg in pkgs {
globs.push(Glob::new(format!("**/node_modules/{{{}}}/**", pkg)));
}

Ok(Glob::alternatives(globs))
}
}

#[turbo_tasks::function]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ pub struct ModuleOptionsContext {
pub ignore_dynamic_requests: bool,

pub use_swc_css: bool,

pub side_effect_free_packages: Vec<String>,
}

#[turbo_tasks::value_impl]
Expand Down
Loading