Skip to content

Commit

Permalink
Collect packages are used and eliminated in getServerSideProps
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Mar 22, 2022
1 parent 860c97c commit a6ecdf1
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 20 deletions.
7 changes: 6 additions & 1 deletion packages/next-swc/crates/core/src/lib.rs
Expand Up @@ -31,6 +31,7 @@ DEALINGS IN THE SOFTWARE.

use auto_cjs::contains_cjs;
use either::Either;
use fxhash::FxHashSet;
use serde::Deserialize;
use std::cell::RefCell;
use std::rc::Rc;
Expand Down Expand Up @@ -113,6 +114,7 @@ pub fn custom_before_pass<'a, C: Comments + 'a>(
file: Arc<SourceFile>,
opts: &'a TransformOptions,
comments: C,
eliminated_packages: Rc<RefCell<FxHashSet<String>>>,
) -> impl Fold + 'a {
#[cfg(target_arch = "wasm32")]
let relay_plugin = noop();
Expand Down Expand Up @@ -148,7 +150,10 @@ pub fn custom_before_pass<'a, C: Comments + 'a>(
Either::Right(noop())
}
},
Optional::new(next_ssg::next_ssg(), !opts.disable_next_ssg),
Optional::new(
next_ssg::next_ssg(eliminated_packages),
!opts.disable_next_ssg
),
amp_attributes::amp_attributes(),
next_dynamic::next_dynamic(
opts.is_development,
Expand Down
21 changes: 18 additions & 3 deletions packages/next-swc/crates/core/src/next_ssg.rs
@@ -1,6 +1,8 @@
use easy_error::{bail, Error};
use fxhash::FxHashSet;
use std::cell::RefCell;
use std::mem::take;
use std::rc::Rc;
use swc_common::pass::{Repeat, Repeated};
use swc_common::DUMMY_SP;
use swc_ecmascript::ast::*;
Expand All @@ -12,9 +14,12 @@ use swc_ecmascript::{
};

/// Note: This paths requires running `resolver` **before** running this.
pub fn next_ssg() -> impl Fold {
pub fn next_ssg(eliminated_packages: Rc<RefCell<FxHashSet<String>>>) -> impl Fold {
Repeat::new(NextSsg {
state: Default::default(),
state: State {
eliminated_packages,
..Default::default()
},
in_lhs_of_var: false,
})
}
Expand All @@ -41,6 +46,10 @@ struct State {
done: bool,

should_run_again: bool,

/// Track the import packages which are eliminated in the
/// `getServerSideProps`
pub eliminated_packages: Rc<RefCell<FxHashSet<String>>>,
}

impl State {
Expand Down Expand Up @@ -288,7 +297,7 @@ impl Fold for Analyzer<'_> {

/// Actual implementation of the transform.
struct NextSsg {
state: State,
pub state: State,
in_lhs_of_var: bool,
}

Expand Down Expand Up @@ -349,6 +358,12 @@ impl Fold for NextSsg {
| ImportSpecifier::Default(ImportDefaultSpecifier { local, .. })
| ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => {
if self.should_remove(local.to_id()) {
if self.state.is_server_props {
self.state
.eliminated_packages
.borrow_mut()
.insert(local.sym.to_string());
}
tracing::trace!(
"Dropping import `{}{:?}` because it should be removed",
local.sym,
Expand Down
7 changes: 6 additions & 1 deletion packages/next-swc/crates/core/tests/errors.rs
Expand Up @@ -63,5 +63,10 @@ fn styled_jsx_errors(input: PathBuf) {
#[fixture("tests/errors/next-ssg/**/input.js")]
fn next_ssg_errors(input: PathBuf) {
let output = input.parent().unwrap().join("output.js");
test_fixture_allowing_error(syntax(), &|_tr| next_ssg(), &input, &output);
test_fixture_allowing_error(
syntax(),
&|_tr| next_ssg(Default::default()),
&input,
&output,
);
}
2 changes: 1 addition & 1 deletion packages/next-swc/crates/core/tests/fixture.rs
Expand Up @@ -113,7 +113,7 @@ fn next_ssg_fixture(input: PathBuf) {
},
top_level_mark,
);
chain!(next_ssg(), jsx)
chain!(next_ssg(Default::default()), jsx)
},
&input,
&output,
Expand Down
8 changes: 7 additions & 1 deletion packages/next-swc/crates/core/tests/full.rs
Expand Up @@ -73,7 +73,13 @@ fn test(input: &Path, minify: bool) {
&handler,
&options.swc,
|_, comments| {
custom_before_pass(cm.clone(), fm.clone(), &options, comments.clone())
custom_before_pass(
cm.clone(),
fm.clone(),
&options,
comments.clone(),
Default::default(),
)
},
|_, _| noop(),
) {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-swc/crates/napi/src/bundle/mod.rs
Expand Up @@ -121,7 +121,7 @@ impl Task for BundleTask {
}

fn resolve(self, env: napi::Env, output: Self::Output) -> napi::Result<Self::JsValue> {
complete_output(&env, output)
complete_output(&env, output, Default::default())
}
}

Expand Down
22 changes: 20 additions & 2 deletions packages/next-swc/crates/napi/src/lib.rs
Expand Up @@ -35,6 +35,7 @@ extern crate napi_derive;
extern crate swc_node_base;

use backtrace::Backtrace;
use fxhash::FxHashSet;
use napi::{CallContext, Env, JsObject, JsUndefined};
use std::{env, panic::set_hook, sync::Arc};
use swc::{Compiler, TransformOutput};
Expand Down Expand Up @@ -86,8 +87,25 @@ fn construct_compiler(ctx: CallContext) -> napi::Result<JsUndefined> {
ctx.env.get_undefined()
}

pub fn complete_output(env: &Env, output: TransformOutput) -> napi::Result<JsObject> {
env.to_js_value(&output)?.coerce_to_object()
pub fn complete_output(
env: &Env,
output: TransformOutput,
eliminated_packages: FxHashSet<String>,
) -> napi::Result<JsObject> {
let mut js_output = env.create_object()?;
js_output.set_named_property("code", env.create_string_from_std(output.code)?)?;
if let Some(map) = output.map {
js_output.set_named_property("map", env.create_string_from_std(map)?)?;
}
if !eliminated_packages.is_empty() {
js_output.set_named_property(
"eliminatedPackages",
env.create_string_from_std(serde_json::to_string(
&eliminated_packages.into_iter().collect::<Vec<String>>(),
)?)?,
)?;
}
Ok(js_output)
}

pub type ArcCompiler = Arc<Compiler>;
4 changes: 2 additions & 2 deletions packages/next-swc/crates/napi/src/minify.rs
Expand Up @@ -85,7 +85,7 @@ impl Task for MinifyTask {
}

fn resolve(self, env: napi::Env, output: Self::Output) -> napi::Result<Self::JsValue> {
complete_output(&env, output)
complete_output(&env, output, Default::default())
}
}

Expand Down Expand Up @@ -113,5 +113,5 @@ pub fn minify_sync(cx: CallContext) -> napi::Result<JsObject> {
let output = try_with_handler(c.cm.clone(), true, |handler| c.minify(fm, handler, &opts))
.convert_err()?;

complete_output(cx.env, output)
complete_output(cx.env, output, Default::default())
}
30 changes: 24 additions & 6 deletions packages/next-swc/crates/napi/src/transform.rs
Expand Up @@ -31,12 +31,15 @@ use crate::{
util::{deserialize_json, CtxtExt, MapErr},
};
use anyhow::{anyhow, bail, Context as _, Error};
use fxhash::FxHashSet;
use napi::{CallContext, Env, JsBoolean, JsBuffer, JsObject, JsString, JsUnknown, Status, Task};
use next_swc::{custom_before_pass, TransformOptions};
use std::fs::read_to_string;
use std::{
cell::RefCell,
convert::TryFrom,
panic::{catch_unwind, AssertUnwindSafe},
rc::Rc,
sync::Arc,
};
use swc::{try_with_handler, Compiler, TransformOutput};
Expand All @@ -60,10 +63,11 @@ pub struct TransformTask {
}

impl Task for TransformTask {
type Output = TransformOutput;
type Output = (TransformOutput, FxHashSet<String>);
type JsValue = JsObject;

fn compute(&mut self) -> napi::Result<Self::Output> {
let eliminated_packages: Rc<RefCell<fxhash::FxHashSet<String>>> = Default::default();
let res = catch_unwind(AssertUnwindSafe(|| {
try_with_handler(self.c.cm.clone(), true, |handler| {
self.c.run(|| {
Expand Down Expand Up @@ -102,7 +106,15 @@ impl Task for TransformTask {
None,
handler,
&options.swc,
|_, comments| custom_before_pass(cm, file, &options, comments.clone()),
|_, comments| {
custom_before_pass(
cm,
file,
&options,
comments.clone(),
eliminated_packages.clone(),
)
},
|_, _| noop(),
)
})
Expand All @@ -117,16 +129,22 @@ impl Task for TransformTask {
});

match res {
Ok(res) => res.convert_err(),
Ok(res) => res
.map(|o| (o, eliminated_packages.replace(Default::default())))
.convert_err(),
Err(err) => Err(napi::Error::new(
Status::GenericFailure,
format!("{:?}", err),
)),
}
}

fn resolve(self, env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
complete_output(&env, result)
fn resolve(
self,
env: Env,
(output, eliminated_packages): Self::Output,
) -> napi::Result<Self::JsValue> {
complete_output(&env, output, eliminated_packages)
}
}

Expand Down Expand Up @@ -189,7 +207,7 @@ where
})
.convert_err()?;

complete_output(cx.env, output)
complete_output(cx.env, output, Default::default())
}

#[js_function(4)]
Expand Down
4 changes: 3 additions & 1 deletion packages/next-swc/crates/wasm/src/lib.rs
Expand Up @@ -55,7 +55,9 @@ pub fn transform_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
None,
handler,
&opts.swc,
|_, comments| custom_before_pass(cm, file, &opts, comments.clone()),
|_, comments| {
custom_before_pass(cm, file, &opts, comments.clone(), Default::default())
},
|_, _| noop(),
)
.context("failed to process js file")?;
Expand Down
2 changes: 2 additions & 0 deletions packages/next/build/index.ts
Expand Up @@ -73,6 +73,7 @@ import {
eventTypeCheckCompleted,
EVENT_BUILD_FEATURE_USAGE,
EventBuildFeatureUsage,
eventPackageUsedInGetServerSideProps,
} from '../telemetry/events'
import { Telemetry } from '../telemetry/storage'
import { CompilerResult, runCompiler } from './compiler'
Expand Down Expand Up @@ -1945,6 +1946,7 @@ export default async function build(
if (telemetryPlugin) {
const events = eventBuildFeatureUsage(telemetryPlugin)
telemetry.record(events)
telemetry.record(eventPackageUsedInGetServerSideProps(telemetryPlugin))
}

if (ssgPages.size > 0) {
Expand Down
3 changes: 3 additions & 0 deletions packages/next/build/webpack/loaders/next-swc-loader.js
Expand Up @@ -88,6 +88,9 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {
const swcSpan = parentTrace.traceChild('next-swc-transform')
return swcSpan.traceAsyncFn(() =>
transform(source, programmaticOptions).then((output) => {
if (output.eliminatedPackages && this.eliminatedPackages) {
this.eliminatedPackages.push(...JSON.parse(output.eliminatedPackages))
}
return [output.code, output.map ? JSON.parse(output.map) : undefined]
})
)
Expand Down
17 changes: 16 additions & 1 deletion packages/next/build/webpack/plugins/telemetry-plugin.ts
@@ -1,4 +1,7 @@
import type { webpack5 as webpack } from 'next/dist/compiled/webpack/webpack'
import {
NormalModule,
webpack5 as webpack,
} from 'next/dist/compiled/webpack/webpack'

/**
* List of target triples next-swc native binary supports.
Expand Down Expand Up @@ -86,6 +89,8 @@ const BUILD_FEATURES: Array<Feature> = [
'swc/target/aarch64-pc-windows-msvc',
]

const ELIMINATED_PACKAGES: string[] = []

/**
* Plugin that queries the ModuleGraph to look for modules that correspond to
* certain features (e.g. next/image and next/script) and record how many times
Expand Down Expand Up @@ -137,11 +142,21 @@ export class TelemetryPlugin implements webpack.WebpackPluginInstance {
callback()
}
)
compiler.hooks.compilation.tap(TelemetryPlugin.name, (compilation) => {
const moduleHooks = NormalModule.getCompilationHooks(compilation)
moduleHooks.loader.tap(TelemetryPlugin.name, (loaderContext: any) => {
loaderContext.eliminatedPackages = ELIMINATED_PACKAGES
})
})
}

usages(): FeatureUsage[] {
return [...this.usageTracker.values()]
}

packagesUsedInServerSideProps(): string[] {
return Array.from(new Set(ELIMINATED_PACKAGES))
}
}

/**
Expand Down
18 changes: 18 additions & 0 deletions packages/next/telemetry/events/build.ts
Expand Up @@ -160,3 +160,21 @@ export function eventBuildFeatureUsage(
},
}))
}

export const EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS =
'NEXT_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS'

export type EventPackageUsedInGetServerSideProps = {
package: string
}

export function eventPackageUsedInGetServerSideProps(
telemetryPlugin: TelemetryPlugin
): Array<{ eventName: string; payload: EventPackageUsedInGetServerSideProps }> {
return telemetryPlugin.packagesUsedInServerSideProps().map((packageName) => ({
eventName: EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS,
payload: {
package: packageName,
},
}))
}

0 comments on commit a6ecdf1

Please sign in to comment.