PostCSS support in next-dev (vercel/turbo#3065)

This adds the ability to add Source transforms on assets, which modify
the source code of an asset before parsing.

This adds postcss via node.js as first source transform.

Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
This commit is contained in:
LongYinan 2022-12-20 03:38:05 +08:00 committed by GitHub
parent df7fa75b04
commit 78abb7e5d3
25 changed files with 414 additions and 101 deletions

View file

@ -1,9 +1,11 @@
const loadConfig = require("next/dist/server/config").default;
const { PHASE_DEVELOPMENT_SERVER } = require("next/dist/shared/lib/constants");
import loadConfig from "next/dist/server/config";
import { PHASE_DEVELOPMENT_SERVER } from "next/dist/shared/lib/constants";
module.exports = (async () => {
const loadNextConfig = async () => {
const nextConfig = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd());
nextConfig.rewrites = await nextConfig.rewrites?.();
nextConfig.redirects = await nextConfig.redirects?.();
return nextConfig;
})();
};
export { loadNextConfig as default };

View file

@ -35,9 +35,8 @@ use turbopack_ecmascript::{
};
use turbopack_env::ProcessEnvAssetVc;
use turbopack_node::{
create_node_rendered_source,
node_entry::{NodeRenderingEntry, NodeRenderingEntryVc},
NodeEntry, NodeEntryVc,
execution_context::ExecutionContextVc, render::rendered_source::create_node_rendered_source,
NodeEntry, NodeEntryVc, NodeRenderingEntry, NodeRenderingEntryVc,
};
use crate::{
@ -69,21 +68,22 @@ use crate::{
#[turbo_tasks::function]
fn next_client_chunks_transition(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
app_dir: FileSystemPathVc,
server_root: FileSystemPathVc,
browserslist_query: &str,
) -> TransitionVc {
let ty = Value::new(ContextType::App { app_dir });
let client_chunking_context = get_client_chunking_context(project_root, server_root, ty);
let client_chunking_context = get_client_chunking_context(project_path, server_root, ty);
let client_environment = get_client_environment(browserslist_query);
let client_module_options_context =
get_client_module_options_context(project_root, client_environment, ty);
get_client_module_options_context(project_path, execution_context, client_environment, ty);
NextClientChunksTransition {
client_chunking_context,
client_module_options_context,
client_resolve_options_context: get_client_resolve_options_context(project_root, ty),
client_resolve_options_context: get_client_resolve_options_context(project_path, ty),
client_environment,
server_root,
}
@ -93,7 +93,8 @@ fn next_client_chunks_transition(
#[turbo_tasks::function]
async fn next_client_transition(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
server_root: FileSystemPathVc,
app_dir: FileSystemPathVc,
env: ProcessEnvVc,
@ -101,12 +102,12 @@ async fn next_client_transition(
next_config: NextConfigVc,
) -> Result<TransitionVc> {
let ty = Value::new(ContextType::App { app_dir });
let client_chunking_context = get_client_chunking_context(project_root, server_root, ty);
let client_chunking_context = get_client_chunking_context(project_path, server_root, ty);
let client_environment = get_client_environment(browserslist_query);
let client_module_options_context =
get_client_module_options_context(project_root, client_environment, ty);
let client_runtime_entries = get_client_runtime_entries(project_root, env, ty, next_config);
let client_resolve_options_context = get_client_resolve_options_context(project_root, ty);
get_client_module_options_context(project_path, execution_context, client_environment, ty);
let client_runtime_entries = get_client_runtime_entries(project_path, env, ty, next_config);
let client_resolve_options_context = get_client_resolve_options_context(project_path, ty);
Ok(NextClientTransition {
is_app: true,
@ -123,16 +124,21 @@ async fn next_client_transition(
#[turbo_tasks::function]
fn next_ssr_client_module_transition(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
app_dir: FileSystemPathVc,
process_env: ProcessEnvVc,
next_config: NextConfigVc,
) -> TransitionVc {
let ty = Value::new(ServerContextType::AppSSR { app_dir });
NextSSRClientModuleTransition {
ssr_module_options_context: get_server_module_options_context(ty),
ssr_module_options_context: get_server_module_options_context(
project_path,
execution_context,
ty,
),
ssr_resolve_options_context: get_server_resolve_options_context(
project_root,
project_path,
ty,
next_config,
),
@ -144,7 +150,8 @@ fn next_ssr_client_module_transition(
#[turbo_tasks::function]
fn next_layout_entry_transition(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
app_dir: FileSystemPathVc,
server_root: FileSystemPathVc,
process_env: ProcessEnvVc,
@ -153,8 +160,9 @@ fn next_layout_entry_transition(
let ty = Value::new(ServerContextType::AppRSC { app_dir });
let rsc_environment = get_server_environment(ty, process_env);
let rsc_resolve_options_context =
get_server_resolve_options_context(project_root, ty, next_config);
let rsc_module_options_context = get_server_module_options_context(ty);
get_server_resolve_options_context(project_path, ty, next_config);
let rsc_module_options_context =
get_server_module_options_context(project_path, execution_context, ty);
NextLayoutEntryTransition {
rsc_environment,
@ -168,7 +176,8 @@ fn next_layout_entry_transition(
#[turbo_tasks::function]
fn app_context(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
server_root: FileSystemPathVc,
app_dir: FileSystemPathVc,
env: ProcessEnvVc,
@ -181,7 +190,14 @@ fn app_context(
let mut transitions = HashMap::new();
transitions.insert(
"next-layout-entry".to_string(),
next_layout_entry_transition(project_root, app_dir, server_root, env, next_config),
next_layout_entry_transition(
project_path,
execution_context,
app_dir,
server_root,
env,
next_config,
),
);
transitions.insert(
"server-to-client".to_string(),
@ -190,7 +206,8 @@ fn app_context(
transitions.insert(
"next-client".to_string(),
next_client_transition(
project_root,
project_path,
execution_context,
server_root,
app_dir,
env,
@ -200,19 +217,31 @@ fn app_context(
);
transitions.insert(
"next-client-chunks".to_string(),
next_client_chunks_transition(project_root, app_dir, server_root, browserslist_query),
next_client_chunks_transition(
project_path,
execution_context,
app_dir,
server_root,
browserslist_query,
),
);
transitions.insert(
"next-ssr-client-module".to_string(),
next_ssr_client_module_transition(project_root, app_dir, env, next_config),
next_ssr_client_module_transition(
project_path,
execution_context,
app_dir,
env,
next_config,
),
);
let ssr_ty = Value::new(ServerContextType::AppSSR { app_dir });
ModuleAssetContextVc::new(
TransitionsByNameVc::cell(transitions),
get_server_environment(ssr_ty, env),
get_server_module_options_context(ssr_ty),
get_server_resolve_options_context(project_root, ssr_ty, next_config),
get_server_module_options_context(project_path, execution_context, ssr_ty),
get_server_resolve_options_context(project_path, ssr_ty, next_config),
)
.into()
}
@ -222,6 +251,7 @@ fn app_context(
#[turbo_tasks::function]
pub async fn create_app_source(
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
output_path: FileSystemPathVc,
server_root: FileSystemPathVc,
env: ProcessEnvVc,
@ -246,6 +276,7 @@ pub async fn create_app_source(
let context_ssr = app_context(
project_path,
execution_context,
server_root,
app_dir,
env,
@ -255,6 +286,7 @@ pub async fn create_app_source(
);
let context = app_context(
project_path,
execution_context,
server_root,
app_dir,
env,
@ -271,6 +303,7 @@ pub async fn create_app_source(
let fallback_page = get_fallback_page(
project_path,
execution_context,
server_root,
env,
browserslist_query,
@ -298,7 +331,7 @@ pub async fn create_app_source(
async fn create_app_source_for_directory(
context_ssr: AssetContextVc,
context: AssetContextVc,
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
specificity: SpecificityVc,
position: u32,
input_dir: FileSystemPathVc,
@ -392,7 +425,7 @@ async fn create_app_source_for_directory(
layout_path: layouts,
page_path,
target,
project_root,
project_path,
intermediate_output_path,
}
.cell()
@ -422,7 +455,7 @@ async fn create_app_source_for_directory(
create_app_source_for_directory(
context_ssr,
context,
project_root,
project_path,
specificity,
position,
*dir,
@ -449,7 +482,7 @@ struct AppRenderer {
layout_path: LayoutSegmentsVc,
page_path: FileSystemPathVc,
target: FileSystemPathVc,
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
intermediate_output_path: FileSystemPathVc,
}
@ -580,7 +613,7 @@ import BOOTSTRAP from {};
};
let chunking_context = DevChunkingContextVc::builder(
self.project_root,
self.project_path,
intermediate_output_path,
intermediate_output_path.join("chunks"),
self.server_root.join("_next/static/assets"),

View file

@ -13,6 +13,7 @@ use turbopack_core::{
resolve::{options::ImportMap, origin::PlainResolveOriginVc},
};
use turbopack_dev_server::html::DevHtmlAssetVc;
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
next_client::context::{
@ -26,7 +27,8 @@ use crate::{
#[turbo_tasks::function]
pub async fn get_fallback_page(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
dev_server_root: FileSystemPathVc,
env: ProcessEnvVc,
browserslist_query: &str,
@ -34,13 +36,14 @@ pub async fn get_fallback_page(
) -> Result<DevHtmlAssetVc> {
let ty = Value::new(ContextType::Fallback);
let environment = get_client_environment(browserslist_query);
let resolve_options_context = get_client_resolve_options_context(project_root, ty);
let module_options_context = get_client_module_options_context(project_root, environment, ty);
let chunking_context = get_client_chunking_context(project_root, dev_server_root, ty);
let entries = get_client_runtime_entries(project_root, env, ty, next_config);
let resolve_options_context = get_client_resolve_options_context(project_path, ty);
let module_options_context =
get_client_module_options_context(project_path, execution_context, environment, ty);
let chunking_context = get_client_chunking_context(project_path, dev_server_root, ty);
let entries = get_client_runtime_entries(project_path, env, ty, next_config);
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(&mut import_map, project_root);
insert_next_shared_aliases(&mut import_map, project_path);
let context: AssetContextVc = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(HashMap::new()),
@ -53,7 +56,7 @@ pub async fn get_fallback_page(
let runtime_entries = entries.resolve_entries(context);
let fallback_chunk = resolve_runtime_request(
PlainResolveOriginVc::new(context, project_root).into(),
PlainResolveOriginVc::new(context, project_path).into(),
"entry/fallback",
);

View file

@ -7,6 +7,7 @@ mod embed_js;
pub mod env;
mod fallback;
pub mod manifest;
mod next_build;
pub mod next_client;
mod next_client_component;
pub mod next_config;
@ -23,7 +24,6 @@ mod web_entry_source;
pub use app_source::create_app_source;
pub use server_rendered_source::create_server_rendered_source;
pub use turbopack_node::source_map;
pub use web_entry_source::create_web_entry_source;
pub fn register() {
@ -31,7 +31,7 @@ pub fn register() {
turbo_tasks_fs::register();
turbo_tasks_fetch::register();
turbopack_dev_server::register();
turbopack::register();
turbopack_node::register();
turbopack::register();
include!(concat!(env!("OUT_DIR"), "/register.rs"));
}

View file

@ -7,8 +7,8 @@ use turbopack_core::asset::AssetContentVc;
use turbopack_dev_server::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
};
use turbopack_node::{
node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc,
use turbopack_node::render::{
node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc,
};
/// A content source which creates the next.js `_devPagesManifest.json` and
@ -29,6 +29,7 @@ impl DevManifestContentSourceVc {
while let Some(content_source) = queue.pop() {
queue.extend(content_source.get_children().await?.iter());
// TODO This shouldn't use casts but an public api instead
if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? {
routes.insert(format!("/{}", api_source.get_pathname().await?));

View file

@ -0,0 +1,49 @@
use anyhow::{Context, Result};
use turbo_tasks::Value;
use turbo_tasks_fs::FileSystemPathVc;
use turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext};
use turbopack_core::resolve::{
options::{ImportMapping, ImportMappingVc},
parse::RequestVc,
pattern::Pattern,
resolve,
};
#[turbo_tasks::function]
pub async fn get_next_package(project_root: FileSystemPathVc) -> Result<FileSystemPathVc> {
let result = resolve(
project_root,
RequestVc::parse(Value::new(Pattern::Constant(
"next/package.json".to_string(),
))),
resolve_options(
project_root,
ResolveOptionsContext {
enable_node_modules: true,
enable_node_native_modules: true,
custom_conditions: vec!["development".to_string()],
..Default::default()
}
.cell(),
),
);
let assets = result.primary_assets().await?;
let asset = assets.first().context("Next.js package not found")?;
Ok(asset.path().parent())
}
#[turbo_tasks::function]
pub async fn get_postcss_package_mapping(
project_path: FileSystemPathVc,
) -> Result<ImportMappingVc> {
Ok(ImportMapping::Alternatives(vec![
// Prefer the local installed version over the next.js version
ImportMapping::PrimaryAlternative("postcss".to_string(), Some(project_path)).cell(),
ImportMapping::PrimaryAlternative(
"postcss".to_string(),
Some(get_next_package(project_path)),
)
.cell(),
])
.cell())
}

View file

@ -8,7 +8,7 @@ use turbo_tasks_fs::FileSystemPathVc;
use turbopack::{
module_options::{
module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc},
ModuleRule, ModuleRuleCondition, ModuleRuleEffect,
ModuleRule, ModuleRuleCondition, ModuleRuleEffect, PostCssTransformOptions,
},
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc},
transition::TransitionsByNameVc,
@ -23,10 +23,12 @@ use turbopack_core::{
};
use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc};
use turbopack_env::ProcessEnvAssetVc;
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
embed_js::attached_next_js_package_path,
env::env_for_js,
next_build::get_postcss_package_mapping,
next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry},
next_config::NextConfigVc,
next_import_map::{
@ -63,12 +65,12 @@ pub enum ContextType {
#[turbo_tasks::function]
pub fn get_client_resolve_options_context(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
ty: Value<ContextType>,
) -> ResolveOptionsContextVc {
let next_client_import_map = get_next_client_import_map(project_root, ty);
let next_client_import_map = get_next_client_import_map(project_path, ty);
let next_client_fallback_import_map = get_next_client_fallback_import_map(ty);
let next_client_resolved_map = get_next_client_resolved_map(project_root, project_root);
let next_client_resolved_map = get_next_client_resolved_map(project_path, project_path);
ResolveOptionsContext {
enable_typescript: true,
enable_react: true,
@ -86,13 +88,14 @@ pub fn get_client_resolve_options_context(
#[turbo_tasks::function]
pub async fn get_client_module_options_context(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
env: EnvironmentVc,
ty: Value<ContextType>,
) -> Result<ModuleOptionsContextVc> {
let resolve_options_context = get_client_resolve_options_context(project_root, ty);
let resolve_options_context = get_client_resolve_options_context(project_path, ty);
let enable_react_refresh =
assert_can_resolve_react_refresh(project_root, resolve_options_context)
assert_can_resolve_react_refresh(project_path, resolve_options_context)
.await?
.is_found();
@ -104,8 +107,13 @@ pub async fn get_client_module_options_context(
enable_react_refresh,
enable_styled_components: true,
enable_styled_jsx: true,
enable_postcss_transform: Some(PostCssTransformOptions {
postcss_package: Some(get_postcss_package_mapping(project_path)),
..Default::default()
}),
enable_typescript_transform: true,
preset_env_versions: Some(env),
execution_context: Some(execution_context),
..Default::default()
};
@ -173,13 +181,15 @@ pub async fn add_next_font_transform(
#[turbo_tasks::function]
pub fn get_client_asset_context(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
browserslist_query: &str,
ty: Value<ContextType>,
) -> AssetContextVc {
let environment = get_client_environment(browserslist_query);
let resolve_options_context = get_client_resolve_options_context(project_root, ty);
let module_options_context = get_client_module_options_context(project_root, environment, ty);
let resolve_options_context = get_client_resolve_options_context(project_path, ty);
let module_options_context =
get_client_module_options_context(project_path, execution_context, environment, ty);
let context: AssetContextVc = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(HashMap::new()),
@ -194,12 +204,12 @@ pub fn get_client_asset_context(
#[turbo_tasks::function]
pub fn get_client_chunking_context(
project_root: FileSystemPathVc,
project_path: FileSystemPathVc,
server_root: FileSystemPathVc,
ty: Value<ContextType>,
) -> ChunkingContextVc {
DevChunkingContextVc::builder(
project_root,
project_path,
server_root,
match ty.into_value() {
ContextType::Pages { .. } | ContextType::App { .. } => {

View file

@ -7,25 +7,25 @@ use turbo_tasks::{
trace::TraceRawVcs,
Value,
};
use turbo_tasks_fs::{FileSystemEntryType, FileSystemPathVc};
use turbopack::{transition::TransitionsByNameVc, ModuleAssetContextVc};
use turbo_tasks_fs::FileSystemEntryType;
use turbopack::evaluate_context::node_evaluate_asset_context;
use turbopack_core::{
asset::Asset,
environment::{EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironment},
reference_type::{EntryReferenceSubType, ReferenceType},
resolve::options::{ImportMap, ImportMapping},
source_asset::SourceAssetVc,
};
use turbopack_ecmascript::{
chunk::EcmascriptChunkPlaceablesVc, EcmascriptInputTransformsVc, EcmascriptModuleAssetType,
EcmascriptModuleAssetVc,
};
use turbopack_node::evaluate::{evaluate, JavaScriptValue};
use crate::{
embed_js::next_asset,
next_server::{get_build_module_options_context, get_build_resolve_options_context},
use turbopack_node::{
evaluate::{evaluate, JavaScriptValue},
execution_context::{ExecutionContext, ExecutionContextVc},
};
use crate::embed_js::next_asset;
#[turbo_tasks::value(serialization = "custom")]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
@ -201,24 +201,19 @@ impl NextConfigVc {
}
#[turbo_tasks::function]
pub async fn load_next_config(
project_path: FileSystemPathVc,
intermediate_output_path: FileSystemPathVc,
) -> Result<NextConfigVc> {
let context = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(Default::default()),
EnvironmentVc::new(
Value::new(ExecutionEnvironment::NodeJsBuildTime(
NodeJsEnvironment::default().cell(),
)),
Value::new(EnvironmentIntention::Build),
),
get_build_module_options_context(),
get_build_resolve_options_context(project_path),
)
.as_asset_context();
let next_config_mjs_path = project_path.join("next.config.mjs").realpath();
let next_config_js_path = project_path.join("next.config.js").realpath();
pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result<NextConfigVc> {
let ExecutionContext {
project_root,
intermediate_output_path,
} = *execution_context.await?;
let mut import_map = ImportMap::default();
import_map.insert_exact_alias("next", ImportMapping::External(None).into());
import_map.insert_wildcard_alias("next/", ImportMapping::External(None).into());
let context = node_evaluate_asset_context(Some(import_map.cell()));
let next_config_mjs_path = project_root.join("next.config.mjs").realpath();
let next_config_js_path = project_root.join("next.config.js").realpath();
let config_asset = if matches!(
&*next_config_mjs_path.get_type().await?,
FileSystemEntryType::File
@ -246,19 +241,20 @@ pub async fn load_next_config(
EcmascriptChunkPlaceablesVc::cell(vec![config_chunk])
});
let asset_path = config_asset
.map_or(project_path, |a| a.path())
.map_or(project_root, |a| a.path())
.join("load-next-config.js");
let load_next_config_asset = context.process(
next_asset(asset_path, "entry/config/next.js"),
Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)),
);
let config_value = evaluate(
project_path,
project_root,
load_next_config_asset,
project_path,
project_root,
context,
intermediate_output_path,
runtime_entries,
vec![],
)
.await?;
match &*config_value {

View file

@ -2,15 +2,17 @@ use turbo_tasks::{primitives::StringVc, Value};
use turbo_tasks_env::ProcessEnvVc;
use turbo_tasks_fs::FileSystemPathVc;
use turbopack::{
module_options::{ModuleOptionsContext, ModuleOptionsContextVc},
module_options::{ModuleOptionsContext, ModuleOptionsContextVc, PostCssTransformOptions},
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc},
};
use turbopack_core::environment::{
EnvironmentIntention, EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc,
};
use turbopack_ecmascript::EcmascriptInputTransform;
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
next_build::get_postcss_package_mapping,
next_client::context::add_next_font_transform,
next_config::NextConfigVc,
next_import_map::{get_next_build_import_map, get_next_server_import_map},
@ -78,23 +80,42 @@ pub fn get_server_environment(
}
#[turbo_tasks::function]
pub fn get_server_module_options_context(ty: Value<ServerContextType>) -> ModuleOptionsContextVc {
pub fn get_server_module_options_context(
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
ty: Value<ServerContextType>,
) -> ModuleOptionsContextVc {
let module_options_context = match ty.into_value() {
ServerContextType::Pages { .. } => ModuleOptionsContext {
enable_typescript_transform: true,
enable_styled_jsx: true,
enable_postcss_transform: Some(PostCssTransformOptions {
postcss_package: Some(get_postcss_package_mapping(project_path)),
..Default::default()
}),
enable_typescript_transform: true,
execution_context: Some(execution_context),
..Default::default()
},
ServerContextType::AppSSR { .. } => ModuleOptionsContext {
enable_styled_jsx: true,
enable_postcss_transform: Some(PostCssTransformOptions {
postcss_package: Some(get_postcss_package_mapping(project_path)),
..Default::default()
}),
enable_typescript_transform: true,
execution_context: Some(execution_context),
..Default::default()
},
ServerContextType::AppRSC { .. } => ModuleOptionsContext {
enable_postcss_transform: Some(PostCssTransformOptions {
postcss_package: Some(get_postcss_package_mapping(project_path)),
..Default::default()
}),
enable_typescript_transform: true,
custom_ecmascript_transforms: vec![EcmascriptInputTransform::ClientDirective(
StringVc::cell("server-to-client".to_string()),
)],
execution_context: Some(execution_context),
..Default::default()
},
}

View file

@ -31,9 +31,11 @@ use turbopack_ecmascript::{
};
use turbopack_env::ProcessEnvAssetVc;
use turbopack_node::{
create_node_api_source, create_node_rendered_source,
node_entry::{NodeRenderingEntry, NodeRenderingEntryVc},
NodeEntry, NodeEntryVc,
execution_context::ExecutionContextVc,
render::{
node_api_source::create_node_api_source, rendered_source::create_node_rendered_source,
},
NodeEntry, NodeEntryVc, NodeRenderingEntry, NodeRenderingEntryVc,
};
use crate::{
@ -61,14 +63,15 @@ use crate::{
/// Next.js pages folder.
#[turbo_tasks::function]
pub async fn create_server_rendered_source(
project_path: FileSystemPathVc,
project_root: FileSystemPathVc,
execution_context: ExecutionContextVc,
output_path: FileSystemPathVc,
server_root: FileSystemPathVc,
env: ProcessEnvVc,
browserslist_query: &str,
next_config: NextConfigVc,
) -> Result<ContentSourceVc> {
let project_path = wrap_with_next_js_fs(project_path);
let project_path = wrap_with_next_js_fs(project_root);
let pages = project_path.join("pages");
let src_pages = project_path.join("src/pages");
@ -85,7 +88,7 @@ pub async fn create_server_rendered_source(
let client_environment = get_client_environment(browserslist_query);
let client_module_options_context =
get_client_module_options_context(project_path, client_environment, ty);
get_client_module_options_context(project_path, execution_context, client_environment, ty);
let client_module_options_context =
add_next_transforms_to_pages(client_module_options_context, pages_dir);
let client_resolve_options_context = get_client_resolve_options_context(project_path, ty);
@ -118,7 +121,7 @@ pub async fn create_server_rendered_source(
let context: AssetContextVc = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(transitions),
get_server_environment(server_ty, env),
get_server_module_options_context(server_ty),
get_server_module_options_context(project_path, execution_context, server_ty),
get_server_resolve_options_context(project_path, server_ty, next_config),
)
.into();
@ -131,6 +134,7 @@ pub async fn create_server_rendered_source(
let fallback_page = get_fallback_page(
project_path,
execution_context,
server_root,
env,
browserslist_query,

View file

@ -12,6 +12,7 @@ use turbopack_dev_server::{
html::DevHtmlAssetVc,
source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc},
};
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{
embed_js::wrap_with_next_js_fs,
@ -25,6 +26,7 @@ use crate::{
#[turbo_tasks::function]
pub async fn create_web_entry_source(
project_root: FileSystemPathVc,
execution_context: ExecutionContextVc,
entry_requests: Vec<RequestVc>,
server_root: FileSystemPathVc,
env: ProcessEnvVc,
@ -35,7 +37,7 @@ pub async fn create_web_entry_source(
let project_root = wrap_with_next_js_fs(project_root);
let ty = Value::new(ContextType::Other);
let context = get_client_asset_context(project_root, browserslist_query, ty);
let context = get_client_asset_context(project_root, execution_context, browserslist_query, ty);
let chunking_context = get_client_chunking_context(project_root, server_root, ty);
let entries = get_client_runtime_entries(project_root, env, ty, next_config);

View file

@ -55,6 +55,7 @@ turbo-tasks-memory = { path = "../turbo-tasks-memory" }
turbopack-cli-utils = { path = "../turbopack-cli-utils" }
turbopack-core = { path = "../turbopack-core" }
turbopack-dev-server = { path = "../turbopack-dev-server" }
turbopack-node = { path = "../turbopack-node" }
webbrowser = "0.7.1"
[dev-dependencies]

View file

@ -19,7 +19,7 @@ use devserver_options::DevServerOptions;
use next_core::{
create_app_source, create_server_rendered_source, create_web_entry_source, env::load_env,
manifest::DevManifestContentSource, next_config::load_next_config,
next_image::NextImageContentSourceVc, source_map::NextSourceMapTraceContentSourceVc,
next_image::NextImageContentSourceVc,
};
use owo_colors::OwoColorize;
use turbo_malloc::TurboMalloc;
@ -44,6 +44,9 @@ use turbopack_dev_server::{
},
DevServer,
};
use turbopack_node::{
execution_context::ExecutionContextVc, source_map::NextSourceMapTraceContentSourceVc,
};
#[derive(Clone)]
pub enum EntryRequest {
@ -276,8 +279,11 @@ async fn source(
let project_path = fs.root().join(project_relative);
let env = load_env(project_path);
let config_output_root = output_fs.root().join(".next/config");
let next_config = load_next_config(project_path, config_output_root);
let build_output_root = output_fs.root().join(".next/build");
let execution_context = ExecutionContextVc::new(project_path, build_output_root);
let next_config = load_next_config(execution_context.join("next_config"));
let output_root = output_fs.root().join(".next/server");
@ -295,6 +301,7 @@ async fn source(
let web_source = create_web_entry_source(
project_path,
execution_context,
entry_requests,
dev_server_root,
env,
@ -304,6 +311,7 @@ async fn source(
);
let rendered_source = create_server_rendered_source(
project_path,
execution_context,
output_root.join("pages"),
dev_server_root,
env,
@ -312,6 +320,7 @@ async fn source(
);
let app_source = create_app_source(
project_path,
execution_context,
output_root.join("app"),
dev_server_root,
env,

View file

@ -146,6 +146,9 @@ async fn run_test(resource: &str) -> JestRunResult {
.eager_compile(false)
.hostname(requested_addr.ip())
.port(requested_addr.port())
.log_level(turbopack_core::issue::IssueSeverity::Warning)
.log_detail(true)
.show_all(true)
.build()
.await
.unwrap();

View file

@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
};

View file

@ -0,0 +1,8 @@
import "../styles/globals.css";
import type { AppProps } from "next/app";
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
export default MyApp;

View file

@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
type Data = {
name: string;
};
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: "John Doe" });
}

View file

@ -0,0 +1,106 @@
import Head from "next/head";
import Image from "next/image";
import { useEffect } from "react";
import { Deferred } from "@turbo/pack-test-harness/deferred";
let testResult = new Deferred();
const Home = () => {
useEffect(() => {
// Only run on client
import("@turbo/pack-test-harness").then(runTests);
});
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex w-full flex-1 flex-col items-center justify-center px-20 text-center">
<h1 className="text-6xl font-bold">
Welcome to{" "}
<a className="text-blue-600" href="https://nextjs.org">
Next.js!
</a>
</h1>
<p className="mt-3 text-2xl">
Get started by editing{" "}
<code className="rounded-md bg-gray-100 p-3 font-mono text-lg">
pages/index.tsx
</code>
</p>
<div className="mt-6 flex max-w-4xl flex-wrap items-center justify-around sm:w-full">
<a
href="https://nextjs.org/docs"
className="mt-6 w-96 rounded-xl border p-6 text-left hover:text-blue-600 focus:text-blue-600"
>
<h3 className="text-2xl font-bold">Documentation &rarr;</h3>
<p className="mt-4 text-xl">
Find in-depth information about Next.js features and its API.
</p>
</a>
<a
href="https://nextjs.org/learn"
className="mt-6 w-96 rounded-xl border p-6 text-left hover:text-blue-600 focus:text-blue-600"
>
<h3 className="text-2xl font-bold">Learn &rarr;</h3>
<p className="mt-4 text-xl">
Learn about Next.js in an interactive course with quizzes!
</p>
</a>
<a
href="https://github.com/vercel/next.js/tree/canary/examples"
className="mt-6 w-96 rounded-xl border p-6 text-left hover:text-blue-600 focus:text-blue-600"
>
<h3 className="text-2xl font-bold">Examples &rarr;</h3>
<p className="mt-4 text-xl">
Discover and deploy boilerplate example Next.js projects.
</p>
</a>
<a
href="https://vercel.com/import?filter=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className="mt-6 w-96 rounded-xl border p-6 text-left hover:text-blue-600 focus:text-blue-600"
>
<h3 className="text-2xl font-bold">Deploy &rarr;</h3>
<p className="mt-4 text-xl">
Instantly deploy your Next.js site to a public URL with Vercel.
</p>
</a>
</div>
</main>
<footer className="flex h-24 w-full items-center justify-center border-t">
<a
className="flex items-center justify-center gap-2"
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{" "}
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
</a>
</footer>
</div>
);
};
export default Home;
globalThis.waitForTests = function () {
return testResult.promise;
};
function runTests() {
console.log(document.querySelectorAll("footer"));
it("it should apply tailwind styles", function () {
const footer = document.querySelector("footer");
expect(getComputedStyle(footer).alignItems).toBe("center");
});
testResult.resolve(__jest__.run());
}

View file

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -0,0 +1,12 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./app/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};

View file

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.jsx"],
"exclude": ["node_modules"]
}

View file

@ -2,10 +2,13 @@
"private": true,
"devDependencies": {
"@turbo/pack-test-harness": "*",
"autoprefixer": "^10.4.13",
"next": "13.0.1",
"postcss": "^8.4.20",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"styled-jsx": "^5.1.0"
"styled-jsx": "^5.1.0",
"tailwindcss": "^3.2.4"
}
}