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; import loadConfig from "next/dist/server/config";
const { PHASE_DEVELOPMENT_SERVER } = require("next/dist/shared/lib/constants"); 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()); const nextConfig = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd());
nextConfig.rewrites = await nextConfig.rewrites?.(); nextConfig.rewrites = await nextConfig.rewrites?.();
nextConfig.redirects = await nextConfig.redirects?.(); nextConfig.redirects = await nextConfig.redirects?.();
return nextConfig; return nextConfig;
})(); };
export { loadNextConfig as default };

View file

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

View file

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

View file

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

View file

@ -7,8 +7,8 @@ use turbopack_core::asset::AssetContentVc;
use turbopack_dev_server::source::{ use turbopack_dev_server::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc, ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
}; };
use turbopack_node::{ use turbopack_node::render::{
node_api_source::NodeApiContentSourceVc, node_rendered_source::NodeRenderContentSourceVc, node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc,
}; };
/// A content source which creates the next.js `_devPagesManifest.json` and /// A content source which creates the next.js `_devPagesManifest.json` and
@ -29,6 +29,7 @@ impl DevManifestContentSourceVc {
while let Some(content_source) = queue.pop() { while let Some(content_source) = queue.pop() {
queue.extend(content_source.get_children().await?.iter()); 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? { if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? {
routes.insert(format!("/{}", api_source.get_pathname().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::{ use turbopack::{
module_options::{ module_options::{
module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc},
ModuleRule, ModuleRuleCondition, ModuleRuleEffect, ModuleRule, ModuleRuleCondition, ModuleRuleEffect, PostCssTransformOptions,
}, },
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc},
transition::TransitionsByNameVc, transition::TransitionsByNameVc,
@ -23,10 +23,12 @@ use turbopack_core::{
}; };
use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc}; use turbopack_ecmascript::{EcmascriptInputTransform, EcmascriptInputTransformsVc};
use turbopack_env::ProcessEnvAssetVc; use turbopack_env::ProcessEnvAssetVc;
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{ use crate::{
embed_js::attached_next_js_package_path, embed_js::attached_next_js_package_path,
env::env_for_js, env::env_for_js,
next_build::get_postcss_package_mapping,
next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry},
next_config::NextConfigVc, next_config::NextConfigVc,
next_import_map::{ next_import_map::{
@ -63,12 +65,12 @@ pub enum ContextType {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_resolve_options_context( pub fn get_client_resolve_options_context(
project_root: FileSystemPathVc, project_path: FileSystemPathVc,
ty: Value<ContextType>, ty: Value<ContextType>,
) -> ResolveOptionsContextVc { ) -> 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_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 { ResolveOptionsContext {
enable_typescript: true, enable_typescript: true,
enable_react: true, enable_react: true,
@ -86,13 +88,14 @@ pub fn get_client_resolve_options_context(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_client_module_options_context( pub async fn get_client_module_options_context(
project_root: FileSystemPathVc, project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
env: EnvironmentVc, env: EnvironmentVc,
ty: Value<ContextType>, ty: Value<ContextType>,
) -> Result<ModuleOptionsContextVc> { ) -> 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 = 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? .await?
.is_found(); .is_found();
@ -104,8 +107,13 @@ pub async fn get_client_module_options_context(
enable_react_refresh, enable_react_refresh,
enable_styled_components: true, enable_styled_components: true,
enable_styled_jsx: 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, enable_typescript_transform: true,
preset_env_versions: Some(env), preset_env_versions: Some(env),
execution_context: Some(execution_context),
..Default::default() ..Default::default()
}; };
@ -173,13 +181,15 @@ pub async fn add_next_font_transform(
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_asset_context( pub fn get_client_asset_context(
project_root: FileSystemPathVc, project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
browserslist_query: &str, browserslist_query: &str,
ty: Value<ContextType>, ty: Value<ContextType>,
) -> AssetContextVc { ) -> AssetContextVc {
let environment = get_client_environment(browserslist_query); let environment = get_client_environment(browserslist_query);
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 module_options_context = get_client_module_options_context(project_root, environment, ty); let module_options_context =
get_client_module_options_context(project_path, execution_context, environment, ty);
let context: AssetContextVc = ModuleAssetContextVc::new( let context: AssetContextVc = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(HashMap::new()), TransitionsByNameVc::cell(HashMap::new()),
@ -194,12 +204,12 @@ pub fn get_client_asset_context(
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_chunking_context( pub fn get_client_chunking_context(
project_root: FileSystemPathVc, project_path: FileSystemPathVc,
server_root: FileSystemPathVc, server_root: FileSystemPathVc,
ty: Value<ContextType>, ty: Value<ContextType>,
) -> ChunkingContextVc { ) -> ChunkingContextVc {
DevChunkingContextVc::builder( DevChunkingContextVc::builder(
project_root, project_path,
server_root, server_root,
match ty.into_value() { match ty.into_value() {
ContextType::Pages { .. } | ContextType::App { .. } => { ContextType::Pages { .. } | ContextType::App { .. } => {

View file

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

View file

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

View file

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

View file

@ -12,6 +12,7 @@ use turbopack_dev_server::{
html::DevHtmlAssetVc, html::DevHtmlAssetVc,
source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc}, source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc},
}; };
use turbopack_node::execution_context::ExecutionContextVc;
use crate::{ use crate::{
embed_js::wrap_with_next_js_fs, embed_js::wrap_with_next_js_fs,
@ -25,6 +26,7 @@ use crate::{
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn create_web_entry_source( pub async fn create_web_entry_source(
project_root: FileSystemPathVc, project_root: FileSystemPathVc,
execution_context: ExecutionContextVc,
entry_requests: Vec<RequestVc>, entry_requests: Vec<RequestVc>,
server_root: FileSystemPathVc, server_root: FileSystemPathVc,
env: ProcessEnvVc, env: ProcessEnvVc,
@ -35,7 +37,7 @@ pub async fn create_web_entry_source(
let project_root = wrap_with_next_js_fs(project_root); let project_root = wrap_with_next_js_fs(project_root);
let ty = Value::new(ContextType::Other); 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 chunking_context = get_client_chunking_context(project_root, server_root, ty);
let entries = get_client_runtime_entries(project_root, env, ty, next_config); 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-cli-utils = { path = "../turbopack-cli-utils" }
turbopack-core = { path = "../turbopack-core" } turbopack-core = { path = "../turbopack-core" }
turbopack-dev-server = { path = "../turbopack-dev-server" } turbopack-dev-server = { path = "../turbopack-dev-server" }
turbopack-node = { path = "../turbopack-node" }
webbrowser = "0.7.1" webbrowser = "0.7.1"
[dev-dependencies] [dev-dependencies]

View file

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

View file

@ -146,6 +146,9 @@ async fn run_test(resource: &str) -> JestRunResult {
.eager_compile(false) .eager_compile(false)
.hostname(requested_addr.ip()) .hostname(requested_addr.ip())
.port(requested_addr.port()) .port(requested_addr.port())
.log_level(turbopack_core::issue::IssueSeverity::Warning)
.log_detail(true)
.show_all(true)
.build() .build()
.await .await
.unwrap(); .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, "private": true,
"devDependencies": { "devDependencies": {
"@turbo/pack-test-harness": "*", "@turbo/pack-test-harness": "*",
"autoprefixer": "^10.4.13",
"next": "13.0.1", "next": "13.0.1",
"postcss": "^8.4.20",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0", "react-test-renderer": "^18.2.0",
"styled-jsx": "^5.1.0" "styled-jsx": "^5.1.0",
"tailwindcss": "^3.2.4"
} }
} }