2024년 5월 8일 작업일지
SWC 이슈 1
Minifier 버그가 있었는데 버그가 발생한 이유가 살짝 골때렸다. #8778 에서 한 함수의 상단부에 확인 코드를 추가했는데, 이 이슈의 input에 대해선 확인 코드가 false가 되면서 하단부의 로직이 실행됐고, 하단부 로직엔 버그가 있었다.
문제는 백슬래시 1개 + escape 문자인 경우에만 replace를 해야하는데, 백슬래시 2개 + escape 문자인 경우에 replace가 되는 것이었다. 정확한 이슈는 어제 발견했는데, 고친 건 오늘이다.
SWC 이슈 2
.jsx
파일에 대한 임포트가 module.resolveFuly
와 같이 썼을 때 잘못된 결과를 뱉는 게 이슈였는데, 고치는 건 간단했다.
터보팩 Tree shaking PR
내 메인 작업이다. 작업일지를 쓰는 이유중 하나가 이건데 디버깅 난이도가 상당해서 적으면서 해야한다. 원래는 Linear에 적는데 영어로 적는 것보다 한국어로 적는 게 디버깅에 훨씬 나아서 그냥 여기다 적기로 했다.
모듈 쪼갠 뒤에 Export("Postpone")
을 못 찾는다고 하길래 entrypoint 목록을 찍어봤다. TURBOPACK_reexport
가 생길 수 있는 경우는 딱 한가지뿐이다.
그래서 관련된 코드를 이렇게 바꿔줬다. 원래 코드에서는 exported
가 None
일 수 있고 그런 경우에 저런 이상한 Export 엔트리가 생기는데 그 경우를 막아준 것이다.
그 다음에 눈에 띄는 건
PAGE
, VAR_MODULE_APP
같은 파일들의 resolve 실패였다. next.js 는 템플릿 파일에서 몇몇 변수를 replace 해서 페이지를 실제 모듈로 바꾸는데, 페이지 템플릿까지 다 찢어져있는 관계로 replace를 못하는 것이라고 추측했다.
use std::io::Write;
use anyhow::{bail, Result};
use indexmap::indexmap;
use serde::Serialize;
use turbo_tasks::Vc;
use turbo_tasks_fs::FileSystemPath;
use turbopack_binding::{
turbo::{
tasks::Value,
tasks_fs::{rope::RopeBuilder, File},
},
turbopack::{
core::{
asset::{Asset, AssetContent},
context::AssetContext,
file_source::FileSource,
module::Module,
reference_type::{EntryReferenceSubType, ReferenceType},
source::Source,
virtual_source::VirtualSource,
},
ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs},
},
};
use crate::{
next_config::NextConfig,
next_edge::entry::wrap_edge_entry,
pages_structure::{PagesStructure, PagesStructureItem},
util::{file_content_rope, load_next_js_template, NextRuntime},
};
#[turbo_tasks::function]
pub async fn create_page_ssr_entry_module(
pathname: Vc<String>,
reference_type: Value<ReferenceType>,
project_root: Vc<FileSystemPath>,
ssr_module_context: Vc<Box<dyn AssetContext>>,
source: Vc<Box<dyn Source>>,
next_original_name: Vc<String>,
pages_structure: Vc<PagesStructure>,
runtime: NextRuntime,
next_config: Vc<NextConfig>,
) -> Result<Vc<Box<dyn EcmascriptChunkPlaceable>>> {
let definition_page = &*next_original_name.await?;
let definition_pathname = &*pathname.await?;
let ssr_module = ssr_module_context
.process(source, reference_type.clone())
.module();
let reference_type = reference_type.into_value();
let template_file = match (&reference_type, runtime) {
(ReferenceType::Entry(EntryReferenceSubType::Page), _) => {
// Load the Page entry file.
"pages.js"
}
(ReferenceType::Entry(EntryReferenceSubType::PagesApi), NextRuntime::NodeJs) => {
// Load the Pages API entry file.
"pages-api.js"
}
(ReferenceType::Entry(EntryReferenceSubType::PagesApi), NextRuntime::Edge) => {
// Load the Pages API entry file.
"pages-edge-api.js"
}
_ => bail!("Invalid path type"),
};
const INNER: &str = "INNER_PAGE";
const INNER_DOCUMENT: &str = "INNER_DOCUMENT";
const INNER_APP: &str = "INNER_APP";
let mut replacements = indexmap! {
"VAR_DEFINITION_PAGE" => definition_page.clone(),
"VAR_DEFINITION_PATHNAME" => definition_pathname.clone(),
"VAR_USERLAND" => INNER.to_string(),
};
if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) {
replacements.insert("VAR_MODULE_DOCUMENT", INNER_DOCUMENT.to_string());
replacements.insert("VAR_MODULE_APP", INNER_APP.to_string());
}
// Load the file from the next.js codebase.
let mut source = load_next_js_template(
template_file,
project_root,
replacements,
indexmap! {},
indexmap! {},
)
.await?;
// When we're building the instrumentation page (only when the
// instrumentation file conflicts with a page also labeled
// /instrumentation) hoist the `register` method.
if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page)
&& (*definition_page == "/instrumentation" || *definition_page == "/src/instrumentation")
{
let file = &*file_content_rope(source.content().file_content()).await?;
let mut result = RopeBuilder::default();
result += file;
writeln!(
result,
r#"export const register = hoist(userland, "register")"#
)?;
let file = File::from(result.build());
source = Vc::upcast(VirtualSource::new(
source.ident().path(),
AssetContent::file(file.into()),
));
}
let mut inner_assets = indexmap! {
INNER.to_string() => ssr_module,
};
if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) {
inner_assets.insert(
INNER_DOCUMENT.to_string(),
process_global_item(
pages_structure.document(),
Value::new(reference_type.clone()),
ssr_module_context,
),
);
inner_assets.insert(
INNER_APP.to_string(),
process_global_item(
pages_structure.app(),
Value::new(reference_type.clone()),
ssr_module_context,
),
);
}
let mut ssr_module = ssr_module_context
.process(
source,
Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
)
.module();
if matches!(runtime, NextRuntime::Edge) {
if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) {
ssr_module = wrap_edge_page(
ssr_module_context,
project_root,
ssr_module,
definition_page.clone(),
definition_pathname.clone(),
Value::new(reference_type),
pages_structure,
next_config,
);
} else {
ssr_module = wrap_edge_entry(
ssr_module_context,
project_root,
ssr_module,
definition_pathname.to_string(),
);
}
}
let Some(ssr_module) =
Vc::try_resolve_downcast::<Box<dyn EcmascriptChunkPlaceable>>(ssr_module).await?
else {
bail!("expected an ECMAScript chunk placeable module");
};
Ok(ssr_module)
}
#[turbo_tasks::function]
async fn process_global_item(
item: Vc<PagesStructureItem>,
reference_type: Value<ReferenceType>,
module_context: Vc<Box<dyn AssetContext>>,
) -> Result<Vc<Box<dyn Module>>> {
let source = Vc::upcast(FileSource::new(item.project_path()));
let module = module_context.process(source, reference_type).module();
Ok(module)
}
#[turbo_tasks::function]
async fn wrap_edge_page(
context: Vc<Box<dyn AssetContext>>,
project_root: Vc<FileSystemPath>,
entry: Vc<Box<dyn Module>>,
page: String,
pathname: String,
reference_type: Value<ReferenceType>,
pages_structure: Vc<PagesStructure>,
next_config: Vc<NextConfig>,
) -> Result<Vc<Box<dyn Module>>> {
const INNER: &str = "INNER_PAGE_ENTRY";
const INNER_DOCUMENT: &str = "INNER_DOCUMENT";
const INNER_APP: &str = "INNER_APP";
const INNER_ERROR: &str = "INNER_ERROR";
let next_config = &*next_config.await?;
// TODO(WEB-1824): add build support
let dev = true;
let sri_enabled = !dev
&& next_config
.experimental
.sri
.as_ref()
.map(|sri| sri.algorithm.as_ref())
.is_some();
let source = load_next_js_template(
"edge-ssr.js",
project_root,
indexmap! {
"VAR_USERLAND" => INNER.to_string(),
"VAR_PAGE" => pathname.clone(),
"VAR_MODULE_DOCUMENT" => INNER_DOCUMENT.to_string(),
"VAR_MODULE_APP" => INNER_APP.to_string(),
"VAR_MODULE_GLOBAL_ERROR" => INNER_ERROR.to_string(),
},
indexmap! {
"pagesType" => StringifyJs("pages").to_string(),
"sriEnabled" => serde_json::Value::Bool(sri_enabled).to_string(),
"nextConfig" => serde_json::to_string(next_config)?,
"dev" => serde_json::Value::Bool(dev).to_string(),
"pageRouteModuleOptions" => serde_json::to_string(&get_route_module_options(page.clone(), pathname.clone()))?,
"errorRouteModuleOptions" => serde_json::to_string(&get_route_module_options("/_error".to_string(), "/_error".to_string()))?,
"user500RouteModuleOptions" => serde_json::to_string(&get_route_module_options("/500".to_string(), "/500".to_string()))?,
},
indexmap! {
// TODO
"incrementalCacheHandler" => None,
"userland500Page" => None,
},
)
.await?;
let inner_assets = indexmap! {
INNER.to_string() => entry,
INNER_DOCUMENT.to_string() => process_global_item(pages_structure.document(), reference_type.clone(), context),
INNER_APP.to_string() => process_global_item(pages_structure.app(), reference_type.clone(), context),
INNER_ERROR.to_string() => process_global_item(pages_structure.error(), reference_type.clone(), context),
};
let wrapped = context
.process(
Vc::upcast(source),
Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
)
.module();
Ok(wrap_edge_entry(
context,
project_root,
wrapped,
pathname.clone(),
))
}
#[derive(Serialize)]
struct PartialRouteModuleOptions {
definition: RouteDefinition,
}
#[derive(Serialize)]
struct RouteDefinition {
kind: String,
bundle_path: String,
filename: String,
/// Describes the pathname including all internal modifiers such as
/// intercepting routes, parallel routes and route/page suffixes that are
/// not part of the pathname.
page: String,
/// The pathname (including dynamic placeholders) for a route to resolve.
pathname: String,
}
fn get_route_module_options(page: String, pathname: String) -> PartialRouteModuleOptions {
PartialRouteModuleOptions {
definition: RouteDefinition {
kind: "PAGES".to_string(),
page,
pathname,
// The following aren't used in production.
bundle_path: "".to_string(),
filename: "".to_string(),
},
}
}
VAR_MODULE_APP
으로 검색해서 관련된 코드를 찾았다. 근데 로그를 찍어보니까 문자열 치환이었다.
그래서 슬라이스 인덱스 이슈부터 보기로 했다.
로그 찍는 코드를 추가하고 다시 돌렸다.
해당 파일로 유닛 테스트 추가해보니 part_id 값이 정상이었다. 다른 모듈의 part_id 와 섞인 것 같아서
관련 코드에 로그 찍는 코드를 추가한 뒤 돌려봤다.
실행 결과를 보니까 섞인 게 맞는 것 같아서 로그를 더 추가했다.
export_part_id = 14
는 없었고, dep = 14
는 많았다. 참고로 app-route.js
는 14번 Part가 없는 모듈이다.
[turbo/crates/turbopack-ecmascript/src/references/mod.rs:417] part = Evaluation
✓ Compiled /favicon.ico in 24ms
⨯ Error: failed to analyse ecmascript module '[project]/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js [app-rsc] (ecmascript)'
Caused by:
- part_id is out of range: 14 >= 14; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}
Debug info:
- Execution of get_written_endpoint_with_issues failed
- Execution of <AppEndpoint as Endpoint>::write_to_disk failed
- Execution of Project::emit_all_output_assets failed
- Execution of VersionedContentMap::output_side_effects failed
- Execution of all_assets_from_entries failed
- Execution of AppEndpointOutput::output_assets failed
- Execution of AppEndpoint::output failed
- Execution of primary_referenced_modules failed
- Execution of <EcmascriptModulePartAsset as Module>::references failed
- Execution of analyse_ecmascript_module failed
- failed to analyse ecmascript module '[project]/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js [app-rsc] (ecmascript)'
- Execution of part_of_module failed
- part_id is out of range: 14 >= 14; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}
결과 해석하는데에 좀 걸렸는데 섞인 것이 아닐수도 있겠다는 생각이 들었다.
그래서 bail
에서 더 많은 값을 출력하도록 했다.
Caused by:
- part_id is out of range: 14 >= 14; uri = ./app-route.js; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}: part_deps = {0: [7, 8, 9, 10, 13], 13: [7, 8, 9, 10], 10: [7, 8, 9], 4: [12, 13], 1: [11, 13], 8: [7], 5: [13], 2: [12, 13], 12: [11], 9: [7, 8], 6: [13, 12], 3: [12, 13]}
Debug info:
- Execution of get_written_endpoint_with_issues failed
- Execution of <AppEndpoint as Endpoint>::write_to_disk failed
- Execution of Project::emit_all_output_assets failed
- Execution of VersionedContentMap::output_side_effects failed
- Execution of all_assets_from_entries failed
- Execution of AppEndpointOutput::output_assets failed
- Execution of AppEndpoint::output failed
- Execution of primary_referenced_modules failed
- Execution of <EcmascriptModulePartAsset as Module>::references failed
- Execution of analyse_ecmascript_module failed
- failed to analyse ecmascript module '[project]/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js [app-rsc] (ecmascript)'
- Execution of part_of_module failed
- part_id is out of range: 14 >= 14; uri = ./app-route.js; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}: part_deps = {0: [7, 8, 9, 10, 13], 13: [7, 8, 9, 10], 10: [7, 8, 9], 4: [12, 13], 1: [11, 13], 8: [7], 5: [13], 2: [12, 13], 12: [11], 9: [7, 8], 6: [13, 12], 3: [12, 13]}
at withErrorCause (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/swc/index.js:415:19)
at async EndpointImpl.writeToDisk (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/swc/index.js:598:20)
at async handleRouteType (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/turbopack-utils.js:414:41)
at async Object.ensurePage (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/hot-reloader-turbopack.js:644:17)
at async DevBundlerService.ensurePage (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/dev-bundler-service.js:18:20)
at async DevServer.ensurePage (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:551:9)
at async Object.ensure (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:169:17)
at async DevRouteMatcherManager.matchAll (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-managers/dev-route-matcher-manager.js:96:13)
at async DevRouteMatcherManager.match (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-managers/default-route-matcher-manager.js:155:26)
at async NextNodeServer.handleCatchallRenderRequest (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next-server.js:229:31)
at async DevServer.handleRequestImpl (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:796:17)
at async /Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:339:20
at async Span.traceAsyncFn (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/trace/trace.js:154:20)
at async DevServer.handleRequest (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:336:24)
at async invokeRender (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:174:21)
at async handleRequest (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:353:24)
at async requestHandlerImpl (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:377:13)
at async Server.requestListener (/Users/kdy1/projects/app-playground/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/start-server.js:142:13) {
[cause]: [Error: failed to analyse ecmascript module '[project]/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js [app-rsc] (ecmascript)'
Caused by:
- part_id is out of range: 14 >= 14; uri = ./app-route.js; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}: part_deps = {0: [7, 8, 9, 10, 13], 13: [7, 8, 9, 10], 10: [7, 8, 9], 4: [12, 13], 1: [11, 13], 8: [7], 5: [13], 2: [12, 13], 12: [11], 9: [7, 8], 6: [13, 12], 3: [12, 13]}
Debug info:
- Execution of get_written_endpoint_with_issues failed
- Execution of <AppEndpoint as Endpoint>::write_to_disk failed
- Execution of Project::emit_all_output_assets failed
- Execution of VersionedContentMap::output_side_effects failed
- Execution of all_assets_from_entries failed
- Execution of AppEndpointOutput::output_assets failed
- Execution of AppEndpoint::output failed
- Execution of primary_referenced_modules failed
- Execution of <EcmascriptModulePartAsset as Module>::references failed
- Execution of analyse_ecmascript_module failed
- failed to analyse ecmascript module '[project]/node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js [app-rsc] (ecmascript)'
- Execution of part_of_module failed
- part_id is out of range: 14 >= 14; uri = ./app-route.js; entrypoints = {ModuleEvaluation: 0, Export("serverHooks"): 4, Export("requestAsyncStorage"): 2, Export("staticGenerationAsyncStorage"): 3, Export("patchFetch"): 6, Export("routeModule"): 1, Export("originalPathname"): 5}: part_deps = {0: [7, 8, 9, 10, 13], 13: [7, 8, 9, 10], 10: [7, 8, 9], 4: [12, 13], 1: [11, 13], 8: [7], 5: [13], 2: [12, 13], 12: [11], 9: [7, 8], 6: [13, 12], 3: [12, 13]}] {
code: 'GenericFailure'
}
}
이것만 보면 14가 있는 게 이상하지만, 다른 로그까지 같이 보면 약간 다른 게 보인다.
[turbo/crates/turbopack-ecmascript/src/references/mod.rs:417] split_data = Ok {
entrypoints: {
ModuleEvaluation: 0,
Export(
"serverHooks",
): 4,
Export(
"requestAsyncStorage",
): 2,
Export(
"staticGenerationAsyncStorage",
): 3,
Export(
"patchFetch",
): 6,
Export(
"routeModule",
): 1,
Export(
"originalPathname",
): 5,
},
deps: {
0: [
7,
8,
9,
10,
14,
],
13: [
12,
],
10: [
7,
8,
9,
],
4: [
13,
14,
],
1: [
12,
14,
],
14: [
7,
8,
9,
10,
],
8: [
7,
],
5: [
14,
],
2: [
13,
14,
],
12: [
11,
],
9: [
7,
8,
],
6: [
14,
13,
],
3: [
13,
14,
],
},
uri_of_module: "./app-route.js",
}
0: [7, 8, 9, 10, 13],
13: [7, 8, 9, 10],
10: [7, 8, 9],
4: [12, 13],
1: [11, 13],
8: [7],
5: [13],
2: [12, 13],
12: [11],
9: [7, 8],
6: [13, 12],
3: [12, 13]
{
0: [7, 8, 9, 10, 14],
13: [12],
10: [7, 8, 9],
4: [13, 14],
1: [12, 14],
14: [7, 8, 9, 10],
8: [7],
5: [14],
2: [13, 14],
12: [11],
9: [7, 8],
6: [14, 13],
3: [13, 14],
}
대체로 비슷해서 고민해봤는데 중간에 숫자가 빠졌다면 10 ~ 11번에서 문제가 있었던 것 같은데 관련된 코드를 보다가 SplitResult
타입이 한 모듈에 대해 2번 생성되고 있다는 걸 깨달았다.
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] "Creating split result for " = "Creating split result for "
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &uri_of_module = "./app-route.js"
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &entrypoints = {
ModuleEvaluation: 0,
Export(
"serverHooks",
): 4,
Export(
"requestAsyncStorage",
): 2,
Export(
"staticGenerationAsyncStorage",
): 3,
Export(
"patchFetch",
): 6,
Export(
"routeModule",
): 1,
Export(
"originalPathname",
): 5,
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &part_deps = {
0: [
7,
8,
9,
10,
14,
],
13: [
12,
],
10: [
7,
8,
9,
],
4: [
13,
14,
],
1: [
12,
14,
],
14: [
7,
8,
9,
10,
],
8: [
7,
],
5: [
14,
],
2: [
13,
14,
],
12: [
11,
],
9: [
7,
8,
],
6: [
14,
13,
],
3: [
13,
14,
],
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] "Creating split result for " = "Creating split result for "
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &uri_of_module = "./app-route.js"
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &entrypoints = {
ModuleEvaluation: 0,
Export(
"serverHooks",
): 4,
Export(
"requestAsyncStorage",
): 2,
Export(
"staticGenerationAsyncStorage",
): 3,
Export(
"patchFetch",
): 6,
Export(
"routeModule",
): 1,
Export(
"originalPathname",
): 5,
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] &part_deps = {
0: [
7,
8,
9,
10,
14,
],
13: [
12,
],
10: [
7,
8,
9,
],
4: [
13,
14,
],
1: [
12,
14,
],
14: [
7,
8,
9,
10,
],
8: [
7,
],
5: [
14,
],
2: [
13,
14,
],
12: [
11,
],
9: [
7,
8,
],
6: [
14,
13,
],
3: [
13,
14,
],
}
이렇게 두개가 생성되고 있었다.
캐싱이 안 되고 있었던 것이므로 왜 캐싱이 안 됐는지 알아내기 위해 vdbg!
에 인자를 추가했다.
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] path = FileSystemPath {
fs: DiskFileSystem {
name: "project",
root: "/Users/kdy1/projects/app-playground",
},
path: "node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js",
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] source = VirtualSource {
ident: AssetIdent {
path: FileSystemPath {
fs: DiskFileSystem {
name: "project",
root: "/Users/kdy1/projects/app-playground",
},
path: "node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js",
},
query: "",
fragment: None,
assets: [],
modifiers: [],
part: None,
layer: None,
},
content: File(
Content(
File {
meta: FileMeta {
permissions: Writable,
content_type: None,
},
},
),
),
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] parsed = Ok
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] path = FileSystemPath {
fs: DiskFileSystem {
name: "project",
root: "/Users/kdy1/projects/app-playground",
},
path: "node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js",
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] source = FileSource {
path: FileSystemPath {
fs: DiskFileSystem {
name: "project",
root: "/Users/kdy1/projects/app-playground",
},
path: "node_modules/.pnpm/file+..+nextpack+tarballs+next.tar_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/esm/build/templates/app-route.js",
},
query: "",
}
[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] parsed = Ok[turbo/crates/turbopack-ecmascript/src/tree_shake/mod.rs:423] parsed = Ok
원인은 확실해졌다. 한 터보팩 인스턴스에 next/dist/esm/build/templates/app-route.js
가 2개 존재하는데, 내용물이 서로 달라서 모듈 스플리팅 결과가 서로 다른 와중에 path는 서로 같아서 모듈 스플리팅 결과 타입이 섞이는 것이 문제인 것이다.
이 둘을 구분해야하는지 하나를 없애야하는지 모르겠어서 팀 채널에 물어봤고 path
는 같지만 ident
가 다르기 때문에 구분해야한다는 답변을 받았다. 슬슬 피곤해서 관련된 질문만 하나 더 남기고 다른 이슈들 보기로 했다.
swc/plugins
의 rust 툴체인 업데이트
집중 안 해도 할 수 있는 작업이라 골랐다. stdsimd
라는 rustc feature이 사라진 것 때문에 툴체인 업데이트만 하는 것이 불가능한가 했는데 ahash
가 백포팅을 잘해주는 라이브러리라서 툴체인 + ahash 업데이트로 끊을 수 있었다.
swc/plugins
의 의존성 업데이트
의존성만 업데이트했는데 소스맵에 관련된 테스트 결과물이 바뀌어서 온라인 base64 디코더로 돌려보니까 rangeMappings
관련된 변경사항이었다. sourcemap
crate의 range mapping이나 관련된 최적화는 내가 구현해서 PR 보낸 것이라서 잘 이해하고 있는 것들이다. 그래서 바뀐 테스트 출력물들을 검증하는 데 어려움이 없었다.