From 282704e2643ecff6e91d915b13b2147cafcefb73 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 27 Jun 2023 14:00:35 +0200 Subject: [PATCH 1/8] Add support for CSS client references --- crates/turbopack-core/src/chunk/mod.rs | 33 ++- .../src/chunk/passthrough_asset.rs | 6 + crates/turbopack-core/src/lib.rs | 1 - crates/turbopack-core/src/reference_type.rs | 6 + crates/turbopack-css/src/asset.rs | 61 ++-- crates/turbopack-css/src/chunk/mod.rs | 4 +- crates/turbopack-css/src/global_asset.rs | 65 +++++ crates/turbopack-css/src/lib.rs | 29 +- crates/turbopack-css/src/module_asset.rs | 268 ++++-------------- crates/turbopack-css/src/parse.rs | 46 +-- .../turbopack-css/src/references/internal.rs | 46 +++ crates/turbopack-css/src/references/mod.rs | 9 +- crates/turbopack/src/lib.rs | 14 +- .../src/module_options/custom_module_type.rs} | 6 +- crates/turbopack/src/module_options/mod.rs | 52 +++- .../src/module_options/module_rule.rs | 15 +- 16 files changed, 342 insertions(+), 319 deletions(-) create mode 100644 crates/turbopack-core/src/chunk/passthrough_asset.rs create mode 100644 crates/turbopack-css/src/global_asset.rs create mode 100644 crates/turbopack-css/src/references/internal.rs rename crates/{turbopack-core/src/plugin.rs => turbopack/src/module_options/custom_module_type.rs} (56%) diff --git a/crates/turbopack-core/src/chunk/mod.rs b/crates/turbopack-core/src/chunk/mod.rs index 897279326ae71..b209b4c751b3c 100644 --- a/crates/turbopack-core/src/chunk/mod.rs +++ b/crates/turbopack-core/src/chunk/mod.rs @@ -5,6 +5,7 @@ pub(crate) mod containment_tree; pub(crate) mod data; pub(crate) mod evaluate; pub mod optimize; +pub(crate) mod passthrough_asset; use std::{ collections::HashSet, @@ -32,6 +33,7 @@ pub use self::{ chunking_context::{ChunkingContext, ChunkingContextVc}, data::{ChunkData, ChunkDataOption, ChunkDataOptionVc, ChunkDataVc, ChunksData, ChunksDataVc}, evaluate::{EvaluatableAsset, EvaluatableAssetVc, EvaluatableAssets, EvaluatableAssetsVc}, + passthrough_asset::{PassthroughAsset, PassthroughAssetVc}, }; use crate::{ asset::{Asset, AssetVc, AssetsVc}, @@ -283,6 +285,9 @@ where #[derive(Eq, PartialEq, Clone, Hash)] enum ChunkContentGraphNode { + // An asset not placed in the current chunk, but whose references we will + // follow to find more graph nodes. + PassthroughAsset { asset: AssetVc }, // Chunk items that are placed into the current chunk ChunkItem { item: I, ident: StringReadRef }, // Asset that is already available and doesn't need to be included @@ -342,6 +347,11 @@ where } } + if PassthroughAssetVc::resolve_from(asset).await?.is_some() { + graph_nodes.push((None, ChunkContentGraphNode::PassthroughAsset { asset })); + continue; + } + let chunkable_asset = match ChunkableAssetVc::resolve_from(asset).await? { Some(chunkable_asset) => chunkable_asset, _ => { @@ -504,24 +514,20 @@ where } fn edges(&mut self, node: &ChunkContentGraphNode) -> Self::EdgesFuture { - let chunk_item = if let ChunkContentGraphNode::ChunkItem { - item: chunk_item, .. - } = node - { - Some(chunk_item.clone()) - } else { - None - }; + let node = node.clone(); let context = self.context; async move { - let Some(chunk_item) = chunk_item else { - return Ok(vec![].into_iter().flatten()); + let references = match node { + ChunkContentGraphNode::PassthroughAsset { asset } => asset.references(), + ChunkContentGraphNode::ChunkItem { item, .. } => item.references(), + _ => { + return Ok(vec![].into_iter().flatten()); + } }; - Ok(chunk_item - .references() + Ok(references .await? .into_iter() .map(|reference| reference_to_graph_nodes::(context, *reference)) @@ -599,7 +605,8 @@ where for graph_node in graph_nodes { match graph_node { - ChunkContentGraphNode::AvailableAsset(_asset) => {} + ChunkContentGraphNode::AvailableAsset(_) + | ChunkContentGraphNode::PassthroughAsset { .. } => {} ChunkContentGraphNode::ChunkItem { item, .. } => { chunk_items.push(item); } diff --git a/crates/turbopack-core/src/chunk/passthrough_asset.rs b/crates/turbopack-core/src/chunk/passthrough_asset.rs new file mode 100644 index 0000000000000..0cbb81f5bc2aa --- /dev/null +++ b/crates/turbopack-core/src/chunk/passthrough_asset.rs @@ -0,0 +1,6 @@ +use crate::asset::{Asset, AssetVc}; + +/// An [Asset] that should never be placed into a chunk, but whose references +/// should still be followed. +#[turbo_tasks::value_trait] +pub trait PassthroughAsset: Asset {} diff --git a/crates/turbopack-core/src/lib.rs b/crates/turbopack-core/src/lib.rs index 6cdb524ded69c..dccee46620aa5 100644 --- a/crates/turbopack-core/src/lib.rs +++ b/crates/turbopack-core/src/lib.rs @@ -17,7 +17,6 @@ pub mod ident; pub mod introspect; pub mod issue; pub mod package_json; -pub mod plugin; pub mod proxied_asset; pub mod reference; pub mod reference_type; diff --git a/crates/turbopack-core/src/reference_type.rs b/crates/turbopack-core/src/reference_type.rs index 7b3d39bd3cb76..4db243e549514 100644 --- a/crates/turbopack-core/src/reference_type.rs +++ b/crates/turbopack-core/src/reference_type.rs @@ -45,6 +45,12 @@ pub enum EcmaScriptModulesReferenceSubType { pub enum CssReferenceSubType { AtImport, Compose, + /// Reference from any asset to a CSS-parseable asset. + /// + /// This marks the boundary between non-CSS and CSS assets. The Next.js App + /// Router implementation uses this to inject client references in-between + /// Global/Module CSS assets and the underlying CSS assets. + Internal, Custom(u8), Undefined, } diff --git a/crates/turbopack-css/src/asset.rs b/crates/turbopack-css/src/asset.rs index fc986785a2146..8a2e243c698b7 100644 --- a/crates/turbopack-css/src/asset.rs +++ b/crates/turbopack-css/src/asset.rs @@ -30,7 +30,9 @@ use crate::{ CssChunkPlaceable, CssChunkPlaceableVc, CssChunkVc, CssImport, }, code_gen::{CodeGenerateable, CodeGenerateableVc}, - parse::{parse, ParseResult, ParseResultSourceMap, ParseResultVc}, + parse::{ + parse_css, ParseCss, ParseCssResult, ParseCssResultSourceMap, ParseCssResultVc, ParseCssVc, + }, path_visitor::ApplyVisitors, references::{ analyze_css_stylesheet, compose::CssModuleComposeReferenceVc, @@ -48,47 +50,30 @@ fn modifier() -> StringVc { #[turbo_tasks::value] #[derive(Clone)] pub struct CssModuleAsset { - pub source: AssetVc, - pub context: AssetContextVc, - pub transforms: CssInputTransformsVc, - pub ty: CssModuleAssetType, + source: AssetVc, + context: AssetContextVc, + transforms: CssInputTransformsVc, + ty: CssModuleAssetType, } #[turbo_tasks::value_impl] impl CssModuleAssetVc { - /// Creates a new CSS asset. The CSS is treated as global CSS. - #[turbo_tasks::function] - pub fn new(source: AssetVc, context: AssetContextVc, transforms: CssInputTransformsVc) -> Self { - Self::cell(CssModuleAsset { - source, - context, - transforms, - ty: CssModuleAssetType::Global, - }) - } - - /// Creates a new CSS asset. The CSS is treated as CSS module. + /// Creates a new CSS asset. #[turbo_tasks::function] - pub fn new_module( + pub fn new( source: AssetVc, context: AssetContextVc, transforms: CssInputTransformsVc, + ty: CssModuleAssetType, ) -> Self { Self::cell(CssModuleAsset { source, context, transforms, - ty: CssModuleAssetType::Module, + ty, }) } - /// Returns the parsed css. - #[turbo_tasks::function] - pub(crate) async fn parse(self) -> Result { - let this = self.await?; - Ok(parse(this.source, Value::new(this.ty), this.transforms)) - } - /// Retrns the asset ident of the source without the "css" modifier #[turbo_tasks::function] pub async fn source_ident(self) -> Result { @@ -96,6 +81,14 @@ impl CssModuleAssetVc { } } +#[turbo_tasks::value_impl] +impl ParseCss for CssModuleAsset { + #[turbo_tasks::function] + fn parse_css(&self) -> ParseCssResultVc { + parse_css(self.source, self.ty, self.transforms) + } +} + #[turbo_tasks::value_impl] impl Asset for CssModuleAsset { #[turbo_tasks::function] @@ -115,7 +108,7 @@ impl Asset for CssModuleAsset { Ok(analyze_css_stylesheet( this.source, self_vc.as_resolve_origin(), - Value::new(this.ty), + this.ty, this.transforms, )) } @@ -137,7 +130,7 @@ impl ChunkableAsset for CssModuleAsset { impl CssChunkPlaceable for CssModuleAsset { #[turbo_tasks::function] fn as_chunk_item(self_vc: CssModuleAssetVc, context: ChunkingContextVc) -> CssChunkItemVc { - ModuleChunkItemVc::cell(ModuleChunkItem { + CssModuleChunkItemVc::cell(CssModuleChunkItem { module: self_vc, context, }) @@ -159,13 +152,13 @@ impl ResolveOrigin for CssModuleAsset { } #[turbo_tasks::value] -struct ModuleChunkItem { +struct CssModuleChunkItem { module: CssModuleAssetVc, context: ChunkingContextVc, } #[turbo_tasks::value_impl] -impl ChunkItem for ModuleChunkItem { +impl ChunkItem for CssModuleChunkItem { #[turbo_tasks::function] fn asset_ident(&self) -> AssetIdentVc { self.module.ident() @@ -178,7 +171,7 @@ impl ChunkItem for ModuleChunkItem { } #[turbo_tasks::value_impl] -impl CssChunkItem for ModuleChunkItem { +impl CssChunkItem for CssModuleChunkItem { #[turbo_tasks::function] async fn content(&self) -> Result { let references = &*self.module.references().await?; @@ -236,9 +229,9 @@ impl CssChunkItem for ModuleChunkItem { } } - let parsed = self.module.parse().await?; + let parsed = self.module.parse_css().await?; - if let ParseResult::Ok { + if let ParseCssResult::Ok { stylesheet, source_map, .. @@ -280,7 +273,7 @@ impl CssChunkItem for ModuleChunkItem { code_gen.emit(&stylesheet)?; - let srcmap = ParseResultSourceMap::new(source_map.clone(), srcmap).cell(); + let srcmap = ParseCssResultSourceMap::new(source_map.clone(), srcmap).cell(); Ok(CssChunkItemContent { inner_code: code_string.into(), diff --git a/crates/turbopack-css/src/chunk/mod.rs b/crates/turbopack-css/src/chunk/mod.rs index 3a2292472c055..483f767461e0d 100644 --- a/crates/turbopack-css/src/chunk/mod.rs +++ b/crates/turbopack-css/src/chunk/mod.rs @@ -35,7 +35,7 @@ use self::{ }; use crate::{ embed::{CssEmbed, CssEmbeddable, CssEmbeddableVc}, - parse::ParseResultSourceMapVc, + parse::ParseCssResultSourceMapVc, util::stringify_js, ImportAssetReferenceVc, }; @@ -485,7 +485,7 @@ pub enum CssImport { pub struct CssChunkItemContent { pub inner_code: Rope, pub imports: Vec, - pub source_map: Option, + pub source_map: Option, } #[turbo_tasks::value_trait] diff --git a/crates/turbopack-css/src/global_asset.rs b/crates/turbopack-css/src/global_asset.rs new file mode 100644 index 0000000000000..f14e4fb89b4e1 --- /dev/null +++ b/crates/turbopack-css/src/global_asset.rs @@ -0,0 +1,65 @@ +use anyhow::{bail, Result}; +use turbo_tasks::{primitives::StringVc, Value}; +use turbopack_core::{ + asset::{Asset, AssetContentVc, AssetVc}, + chunk::{PassthroughAsset, PassthroughAssetVc}, + context::{AssetContext, AssetContextVc}, + ident::AssetIdentVc, + reference::AssetReferencesVc, + reference_type::{CssReferenceSubType, ReferenceType}, +}; + +use crate::references::internal::InternalCssAssetReferenceVc; + +#[turbo_tasks::value] +#[derive(Clone)] +pub struct GlobalCssAsset { + source: AssetVc, + inner: AssetVc, +} + +#[turbo_tasks::value_impl] +impl GlobalCssAssetVc { + /// Creates a new CSS asset. The CSS is treated as global CSS. + #[turbo_tasks::function] + pub fn new(source: AssetVc, context: AssetContextVc) -> Self { + Self::cell(GlobalCssAsset { + source, + // The underlying CSS is processed through an internal CSS reference. + // This can then be picked up by other rules to treat CSS assets in + // a special way. For instance, in the Next App Router implementation, + // RSC CSS assets will be added to the client references manifest. + inner: context.process( + source, + Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), + ), + }) + } +} + +#[turbo_tasks::value_impl] +impl Asset for GlobalCssAsset { + #[turbo_tasks::function] + fn ident(&self) -> AssetIdentVc { + self.source.ident().with_modifier(modifier()) + } + + #[turbo_tasks::function] + fn content(&self) -> Result { + bail!("CSS global asset has no contents") + } + + #[turbo_tasks::function] + fn references(&self) -> AssetReferencesVc { + AssetReferencesVc::cell(vec![InternalCssAssetReferenceVc::new(self.inner).into()]) + } +} + +#[turbo_tasks::function] +fn modifier() -> StringVc { + StringVc::cell("global css".to_string()) +} + +/// A GlobalAsset is a transparent wrapper around an actual CSS asset. +#[turbo_tasks::value_impl] +impl PassthroughAsset for GlobalCssAsset {} diff --git a/crates/turbopack-css/src/lib.rs b/crates/turbopack-css/src/lib.rs index 7c18bc012cbb6..b6e067c3b18c3 100644 --- a/crates/turbopack-css/src/lib.rs +++ b/crates/turbopack-css/src/lib.rs @@ -7,6 +7,7 @@ mod asset; pub mod chunk; mod code_gen; pub mod embed; +mod global_asset; mod module_asset; pub(crate) mod parse; mod path_visitor; @@ -16,15 +17,35 @@ pub(crate) mod util; use anyhow::Result; pub use asset::CssModuleAssetVc; -pub use module_asset::ModuleCssModuleAssetVc; +pub use global_asset::GlobalCssAssetVc; +pub use module_asset::ModuleCssAssetVc; +pub use parse::{ParseCss, ParseCssResult, ParseCssResultVc, ParseCssVc}; +use serde::{Deserialize, Serialize}; pub use transform::{CssInputTransform, CssInputTransformsVc}; +use turbo_tasks::{trace::TraceRawVcs, TaskInput}; use crate::references::import::ImportAssetReferenceVc; -#[turbo_tasks::value(serialization = "auto_for_input")] -#[derive(PartialOrd, Ord, Hash, Debug, Copy, Clone)] +#[derive( + PartialOrd, + Ord, + Eq, + PartialEq, + Hash, + Debug, + Copy, + Clone, + Default, + Serialize, + Deserialize, + TaskInput, + TraceRawVcs, +)] pub enum CssModuleAssetType { - Global, + /// Default parsing mode. + #[default] + Default, + /// The CSS is parsed as CSS modules. Module, } diff --git a/crates/turbopack-css/src/module_asset.rs b/crates/turbopack-css/src/module_asset.rs index 93bc66b34fa49..2a08da164c86d 100644 --- a/crates/turbopack-css/src/module_asset.rs +++ b/crates/turbopack-css/src/module_asset.rs @@ -1,29 +1,28 @@ -use std::{fmt::Write, sync::Arc}; +use std::{fmt::Write, iter::once, sync::Arc}; -use anyhow::Result; +use anyhow::{bail, Result}; use indexmap::IndexMap; use indoc::formatdoc; use swc_core::{ common::{BytePos, FileName, LineCol, SourceMap}, css::modules::CssClassName, }; -use turbo_tasks::{primitives::StringVc, Value, ValueToString, ValueToStringVc}; +use turbo_tasks::{primitives::StringVc, Value, ValueToString}; use turbo_tasks_fs::FileSystemPathVc; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc}, chunk::{ availability_info::AvailabilityInfo, ChunkItem, ChunkItemVc, ChunkVc, ChunkableAsset, - ChunkableAssetReference, ChunkableAssetReferenceVc, ChunkableAssetVc, ChunkingContextVc, - ChunkingType, ChunkingTypeOptionVc, + ChunkableAssetVc, ChunkingContextVc, }, - context::AssetContextVc, + context::{AssetContext, AssetContextVc}, ident::AssetIdentVc, issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, - reference::{AssetReference, AssetReferenceVc, AssetReferencesVc}, + reference::{AssetReference, AssetReferencesVc}, + reference_type::{CssReferenceSubType, ReferenceType}, resolve::{ origin::{ResolveOrigin, ResolveOriginVc}, parse::RequestVc, - ResolveResult, ResolveResultVc, }, }; use turbopack_ecmascript::{ @@ -37,14 +36,8 @@ use turbopack_ecmascript::{ }; use crate::{ - chunk::{ - CssChunkItem, CssChunkItemContentVc, CssChunkItemVc, CssChunkPlaceable, - CssChunkPlaceableVc, CssChunkVc, - }, - parse::ParseResult, - references::compose::CssModuleComposeReferenceVc, - transform::CssInputTransformsVc, - CssModuleAssetVc, + parse::{ParseCss, ParseCssResult, ParseCssVc}, + references::{compose::CssModuleComposeReferenceVc, internal::InternalCssAssetReferenceVc}, }; #[turbo_tasks::function] @@ -54,41 +47,47 @@ fn modifier() -> StringVc { #[turbo_tasks::value] #[derive(Clone)] -pub struct ModuleCssModuleAsset { - pub inner: CssModuleAssetVc, +pub struct ModuleCssAsset { + pub inner: AssetVc, + pub context: AssetContextVc, } #[turbo_tasks::value_impl] -impl ModuleCssModuleAssetVc { +impl ModuleCssAssetVc { #[turbo_tasks::function] - pub fn new(source: AssetVc, context: AssetContextVc, transforms: CssInputTransformsVc) -> Self { - Self::cell(ModuleCssModuleAsset { - inner: CssModuleAssetVc::new_module(source, context, transforms), - }) + pub async fn new(source: AssetVc, context: AssetContextVc) -> Result { + let inner = context.process( + source, + Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), + ); + + Ok(Self::cell(ModuleCssAsset { inner, context })) } } #[turbo_tasks::value_impl] -impl Asset for ModuleCssModuleAsset { +impl Asset for ModuleCssAsset { #[turbo_tasks::function] fn ident(&self) -> AssetIdentVc { - self.inner.source_ident().with_modifier(modifier()) + self.inner.ident().with_modifier(modifier()) } #[turbo_tasks::function] - fn content(&self) -> AssetContentVc { - self.inner.content() + fn content(&self) -> Result { + bail!("CSS module asset has no contents") } #[turbo_tasks::function] - async fn references(self_vc: ModuleCssModuleAssetVc) -> Result { - let references = self_vc.await?.inner.references().await?; - let module_references = self_vc.module_references().await?; - - let references: Vec<_> = references - .iter() - .copied() - .chain(module_references.iter().copied()) + async fn references(self_vc: ModuleCssAssetVc) -> Result { + let this = self_vc.await?; + + // The inner reference must come first so it is processed before other potential + // references inside of the CSS, like `@import` and `composes:`. + // This affects the order in which the resulting CSS chunks will be loaded: + // later references are processed first in the post-order traversal of the + // reference tree, and as such they will be loaded first in the resulting HTML. + let references = once(InternalCssAssetReferenceVc::new(this.inner).into()) + .chain(self_vc.module_references().await?.iter().copied()) .collect(); Ok(AssetReferencesVc::cell(references)) @@ -140,15 +139,20 @@ enum ModuleCssClass { struct ModuleCssClasses(IndexMap>); #[turbo_tasks::value_impl] -impl ModuleCssModuleAssetVc { +impl ModuleCssAssetVc { #[turbo_tasks::function] async fn classes(self) -> Result { let inner = self.await?.inner; - let parse_result = inner.parse().await?; + + let Some(inner) = ParseCssVc::resolve_from(inner).await? else { + bail!("inner asset should be CSS parseable"); + }; + + let parse_result = inner.parse_css().await?; let mut classes = IndexMap::default(); // TODO(alexkirsz) Should we report an error on parse error here? - if let ParseResult::Ok { exports, .. } = &*parse_result { + if let ParseCssResult::Ok { exports, .. } = &*parse_result { for (class_name, export_class_names) in exports { let mut export = Vec::default(); @@ -197,10 +201,10 @@ impl ModuleCssModuleAssetVc { } #[turbo_tasks::value_impl] -impl ChunkableAsset for ModuleCssModuleAsset { +impl ChunkableAsset for ModuleCssAsset { #[turbo_tasks::function] fn as_chunk( - self_vc: ModuleCssModuleAssetVc, + self_vc: ModuleCssAssetVc, context: ChunkingContextVc, availability_info: Value, ) -> ChunkVc { @@ -209,10 +213,10 @@ impl ChunkableAsset for ModuleCssModuleAsset { } #[turbo_tasks::value_impl] -impl EcmascriptChunkPlaceable for ModuleCssModuleAsset { +impl EcmascriptChunkPlaceable for ModuleCssAsset { #[turbo_tasks::function] fn as_chunk_item( - self_vc: ModuleCssModuleAssetVc, + self_vc: ModuleCssAssetVc, context: EcmascriptChunkingContextVc, ) -> EcmascriptChunkItemVc { ModuleChunkItem { @@ -230,7 +234,7 @@ impl EcmascriptChunkPlaceable for ModuleCssModuleAsset { } #[turbo_tasks::value_impl] -impl ResolveOrigin for ModuleCssModuleAsset { +impl ResolveOrigin for ModuleCssAsset { #[turbo_tasks::function] fn origin_path(&self) -> FileSystemPathVc { self.inner.ident().path() @@ -238,13 +242,13 @@ impl ResolveOrigin for ModuleCssModuleAsset { #[turbo_tasks::function] fn context(&self) -> AssetContextVc { - self.inner.context() + self.context } } #[turbo_tasks::value] struct ModuleChunkItem { - module: ModuleCssModuleAssetVc, + module: ModuleCssAssetVc, context: EcmascriptChunkingContextVc, } @@ -256,21 +260,8 @@ impl ChunkItem for ModuleChunkItem { } #[turbo_tasks::function] - async fn references(&self) -> Result { - // The proxy reference must come first so it is processed before other potential - // references inside of the CSS, like `@import` and `composes:`. - // This affects the order in which the resulting CSS chunks will be loaded: - // later references are processed first in the post-order traversal of the - // reference tree, and as such they will be loaded first in the resulting HTML. - let mut references = vec![CssProxyToCssAssetReference { - module: self.module, - } - .cell() - .into()]; - - references.extend(self.module.references().await?.iter().copied()); - - Ok(AssetReferencesVc::cell(references)) + fn references(&self) -> AssetReferencesVc { + self.module.references() } } @@ -311,7 +302,7 @@ impl EcmascriptChunkItem for ModuleChunkItem { continue; }; - let Some(css_module) = ModuleCssModuleAssetVc::resolve_from(resolved_module).await? else { + let Some(css_module) = ModuleCssAssetVc::resolve_from(resolved_module).await? else { CssModuleComposesIssue { severity: IssueSeverity::Error.cell(), source: self.module.ident(), @@ -328,9 +319,7 @@ impl EcmascriptChunkItem for ModuleChunkItem { // TODO(alexkirsz) We should also warn if `original_name` can't be found in // the target module. - let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(css_module).await? else { - unreachable!("ModuleCssModuleAsset implements EcmascriptChunkPlaceableVc"); - }; + let placeable = css_module.as_ecmascript_chunk_placeable(); let module_id = placeable.as_chunk_item(self.context).id().await?; let module_id = StringifyJs(&*module_id); @@ -368,157 +357,6 @@ impl EcmascriptChunkItem for ModuleChunkItem { } } -#[turbo_tasks::value] -struct CssProxyToCssAssetReference { - module: ModuleCssModuleAssetVc, -} - -#[turbo_tasks::value_impl] -impl ValueToString for CssProxyToCssAssetReference { - #[turbo_tasks::function] - async fn to_string(&self) -> Result { - Ok(StringVc::cell(format!( - "proxy(css) {}", - self.module.ident().to_string().await?, - ))) - } -} - -#[turbo_tasks::value_impl] -impl AssetReference for CssProxyToCssAssetReference { - #[turbo_tasks::function] - fn resolve_reference(&self) -> ResolveResultVc { - ResolveResult::asset( - CssProxyModuleAsset { - module: self.module, - } - .cell() - .into(), - ) - .cell() - } -} - -#[turbo_tasks::value_impl] -impl ChunkableAssetReference for CssProxyToCssAssetReference { - #[turbo_tasks::function] - fn chunking_type(&self) -> ChunkingTypeOptionVc { - ChunkingTypeOptionVc::cell(Some(ChunkingType::Parallel)) - } -} - -/// This structure exists solely in order to extend the `references` returned by -/// a standard [`CssModuleAsset`] with CSS modules' `composes:` references. -#[turbo_tasks::value] -#[derive(Clone)] -struct CssProxyModuleAsset { - module: ModuleCssModuleAssetVc, -} - -#[turbo_tasks::value_impl] -impl Asset for CssProxyModuleAsset { - #[turbo_tasks::function] - async fn ident(&self) -> Result { - Ok(self.module.await?.inner.ident().with_modifier(modifier())) - } - - #[turbo_tasks::function] - fn content(&self) -> AssetContentVc { - self.module.content() - } - - #[turbo_tasks::function] - async fn references(&self) -> Result { - // The original references must come first so they're processed before other - // potential references inside of the CSS, like `@import` and `composes:`. This - // affects the order in which the resulting CSS chunks will be loaded: - // later references are processed first in the post-order traversal of - // the reference tree, and as such they will be loaded first in the - // resulting HTML. - let mut references = self.module.await?.inner.references().await?.clone_value(); - - references.extend(self.module.module_references().await?.iter().copied()); - - Ok(AssetReferencesVc::cell(references)) - } -} - -#[turbo_tasks::value_impl] -impl ChunkableAsset for CssProxyModuleAsset { - #[turbo_tasks::function] - fn as_chunk( - self_vc: CssProxyModuleAssetVc, - context: ChunkingContextVc, - availability_info: Value, - ) -> ChunkVc { - CssChunkVc::new(context, self_vc.into(), availability_info).into() - } -} - -#[turbo_tasks::value_impl] -impl CssChunkPlaceable for CssProxyModuleAsset { - #[turbo_tasks::function] - fn as_chunk_item(self_vc: CssProxyModuleAssetVc, context: ChunkingContextVc) -> CssChunkItemVc { - CssProxyModuleChunkItemVc::cell(CssProxyModuleChunkItem { - inner: self_vc, - context, - }) - .into() - } -} - -#[turbo_tasks::value_impl] -impl ResolveOrigin for CssProxyModuleAsset { - #[turbo_tasks::function] - fn origin_path(&self) -> FileSystemPathVc { - self.module.ident().path() - } - - #[turbo_tasks::function] - fn context(&self) -> AssetContextVc { - self.module.context() - } -} - -#[turbo_tasks::value] -struct CssProxyModuleChunkItem { - inner: CssProxyModuleAssetVc, - context: ChunkingContextVc, -} - -#[turbo_tasks::value_impl] -impl ChunkItem for CssProxyModuleChunkItem { - #[turbo_tasks::function] - fn asset_ident(&self) -> AssetIdentVc { - self.inner.ident() - } - - #[turbo_tasks::function] - fn references(&self) -> AssetReferencesVc { - self.inner.references() - } -} - -#[turbo_tasks::value_impl] -impl CssChunkItem for CssProxyModuleChunkItem { - #[turbo_tasks::function] - async fn content(&self) -> Result { - Ok(self - .inner - .await? - .module - .await? - .inner - .as_chunk_item(self.context) - .content()) - } - - #[turbo_tasks::function] - fn chunking_context(&self) -> ChunkingContextVc { - self.context - } -} - fn generate_minimal_source_map(filename: String, source: String) -> ParseResultSourceMapVc { let mut mappings = vec![]; // Start from 1 because 0 is reserved for dummy spans in SWC. diff --git a/crates/turbopack-css/src/parse.rs b/crates/turbopack-css/src/parse.rs index e50fae880a1ec..65e25682a08c6 100644 --- a/crates/turbopack-css/src/parse.rs +++ b/crates/turbopack-css/src/parse.rs @@ -15,7 +15,7 @@ use swc_core::{ }, ecma::atoms::JsWord, }; -use turbo_tasks::{Value, ValueToString}; +use turbo_tasks::ValueToString; use turbo_tasks_fs::{FileContent, FileSystemPath}; use turbopack_core::{ asset::{Asset, AssetContent, AssetVc}, @@ -33,7 +33,7 @@ use crate::{ static BASENAME_RE: Lazy = Lazy::new(|| Regex::new(r"^[^.]*").unwrap()); #[turbo_tasks::value(shared, serialization = "none", eq = "manual")] -pub enum ParseResult { +pub enum ParseCssResult { Ok { #[turbo_tasks(trace_ignore)] stylesheet: Stylesheet, @@ -48,7 +48,7 @@ pub enum ParseResult { NotFound, } -impl PartialEq for ParseResult { +impl PartialEq for ParseCssResult { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Ok { .. }, Self::Ok { .. }) => false, @@ -58,7 +58,7 @@ impl PartialEq for ParseResult { } #[turbo_tasks::value(shared, serialization = "none", eq = "manual")] -pub struct ParseResultSourceMap { +pub struct ParseCssResultSourceMap { #[turbo_tasks(debug_ignore, trace_ignore)] source_map: Arc, @@ -68,15 +68,15 @@ pub struct ParseResultSourceMap { mappings: Vec<(BytePos, LineCol)>, } -impl PartialEq for ParseResultSourceMap { +impl PartialEq for ParseCssResultSourceMap { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.source_map, &other.source_map) && self.mappings == other.mappings } } -impl ParseResultSourceMap { +impl ParseCssResultSourceMap { pub fn new(source_map: Arc, mappings: Vec<(BytePos, LineCol)>) -> Self { - ParseResultSourceMap { + ParseCssResultSourceMap { source_map, mappings, } @@ -84,7 +84,7 @@ impl ParseResultSourceMap { } #[turbo_tasks::value_impl] -impl GenerateSourceMap for ParseResultSourceMap { +impl GenerateSourceMap for ParseCssResultSourceMap { #[turbo_tasks::function] fn generate_source_map(&self) -> OptionSourceMapVc { let map = self.source_map.build_source_map_with_config( @@ -117,21 +117,20 @@ impl SourceMapGenConfig for InlineSourcesContentConfig { } #[turbo_tasks::function] -pub async fn parse( +pub async fn parse_css( source: AssetVc, - ty: Value, + ty: CssModuleAssetType, transforms: CssInputTransformsVc, -) -> Result { +) -> Result { let content = source.content(); let fs_path = &*source.ident().path().await?; let ident_str = &*source.ident().to_string().await?; - let ty = ty.into_value(); Ok(match &*content.await? { - AssetContent::Redirect { .. } => ParseResult::Unparseable.cell(), + AssetContent::Redirect { .. } => ParseCssResult::Unparseable.cell(), AssetContent::File(file) => match &*file.await? { - FileContent::NotFound => ParseResult::NotFound.cell(), + FileContent::NotFound => ParseCssResult::NotFound.cell(), FileContent::Content(file) => match file.content().to_str() { - Err(_err) => ParseResult::Unparseable.cell(), + Err(_err) => ParseCssResult::Unparseable.cell(), Ok(string) => { let transforms = &*transforms.await?; parse_content( @@ -156,7 +155,7 @@ async fn parse_content( source: AssetVc, ty: CssModuleAssetType, transforms: &[CssInputTransform], -) -> Result { +) -> Result { let source_map: Arc = Default::default(); let handler = Handler::with_emitter( true, @@ -183,7 +182,7 @@ async fn parse_content( Err(e) => { // TODO report in in a stream e.to_diagnostics(&handler).emit(); - return Ok(ParseResult::Unparseable.into()); + return Ok(ParseCssResult::Unparseable.into()); } }; @@ -194,7 +193,7 @@ async fn parse_content( } if has_errors { - return Ok(ParseResult::Unparseable.into()); + return Ok(ParseCssResult::Unparseable.into()); } let context = TransformContext { @@ -205,7 +204,7 @@ async fn parse_content( } let (imports, exports) = match ty { - CssModuleAssetType::Global => Default::default(), + CssModuleAssetType::Default => Default::default(), CssModuleAssetType::Module => { let imports = swc_core::css::modules::imports::analyze_imports(&parsed_stylesheet); let basename = BASENAME_RE @@ -232,7 +231,7 @@ async fn parse_content( } }; - Ok(ParseResult::Ok { + Ok(ParseCssResult::Ok { stylesheet: parsed_stylesheet, source_map, imports, @@ -250,3 +249,10 @@ impl TransformConfig for ModuleTransformConfig { format!("{}{}", *local, self.suffix).into() } } + +/// Trait to be implemented by assets which can be parsed as CSS. +#[turbo_tasks::value_trait] +pub trait ParseCss { + /// Returns the parsed css. + fn parse_css(&self) -> ParseCssResultVc; +} diff --git a/crates/turbopack-css/src/references/internal.rs b/crates/turbopack-css/src/references/internal.rs new file mode 100644 index 0000000000000..c2ab171e45830 --- /dev/null +++ b/crates/turbopack-css/src/references/internal.rs @@ -0,0 +1,46 @@ +use anyhow::Result; +use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; +use turbopack_core::{ + asset::{Asset, AssetVc}, + chunk::{ChunkableAssetReference, ChunkableAssetReferenceVc}, + reference::{AssetReference, AssetReferenceVc}, + resolve::{ResolveResult, ResolveResultVc}, +}; + +/// A reference to an internal CSS asset. +#[turbo_tasks::value] +#[derive(Hash, Debug)] +pub struct InternalCssAssetReference { + asset: AssetVc, +} + +#[turbo_tasks::value_impl] +impl InternalCssAssetReferenceVc { + /// Creates a new [`InternalCssAssetReferenceVc`]. + #[turbo_tasks::function] + pub fn new(asset: AssetVc) -> Self { + Self::cell(InternalCssAssetReference { asset }) + } +} + +#[turbo_tasks::value_impl] +impl AssetReference for InternalCssAssetReference { + #[turbo_tasks::function] + fn resolve_reference(&self) -> ResolveResultVc { + ResolveResult::asset(self.asset).cell() + } +} + +#[turbo_tasks::value_impl] +impl ValueToString for InternalCssAssetReference { + #[turbo_tasks::function] + async fn to_string(&self) -> Result { + Ok(StringVc::cell(format!( + "internal css {}", + self.asset.ident().to_string().await? + ))) + } +} + +#[turbo_tasks::value_impl] +impl ChunkableAssetReference for InternalCssAssetReference {} diff --git a/crates/turbopack-css/src/references/mod.rs b/crates/turbopack-css/src/references/mod.rs index 110817577619b..542f32508fc3e 100644 --- a/crates/turbopack-css/src/references/mod.rs +++ b/crates/turbopack-css/src/references/mod.rs @@ -26,7 +26,7 @@ use turbopack_core::{ use turbopack_swc_utils::emitter::IssueEmitter; use crate::{ - parse::{parse, ParseResult}, + parse::{parse_css, ParseCssResult}, references::{ import::{ImportAssetReferenceVc, ImportAttributes}, url::UrlAssetReferenceVc, @@ -36,20 +36,21 @@ use crate::{ pub(crate) mod compose; pub(crate) mod import; +pub(crate) mod internal; pub(crate) mod url; #[turbo_tasks::function] pub async fn analyze_css_stylesheet( source: AssetVc, origin: ResolveOriginVc, - ty: Value, + ty: CssModuleAssetType, transforms: CssInputTransformsVc, ) -> Result { let mut references = Vec::new(); - let parsed = parse(source, ty, transforms).await?; + let parsed = parse_css(source, ty, transforms).await?; - if let ParseResult::Ok { + if let ParseCssResult::Ok { stylesheet, source_map, .. diff --git a/crates/turbopack/src/lib.rs b/crates/turbopack/src/lib.rs index 97b372e949866..c7959067dd880 100644 --- a/crates/turbopack/src/lib.rs +++ b/crates/turbopack/src/lib.rs @@ -13,7 +13,7 @@ use std::{ }; use anyhow::Result; -use css::{CssModuleAssetVc, ModuleCssModuleAssetVc}; +use css::{CssModuleAssetVc, GlobalCssAssetVc, ModuleCssAssetVc}; use ecmascript::{ typescript::resolve::TypescriptTypesAssetReferenceVc, EcmascriptModuleAssetType, EcmascriptModuleAssetVc, @@ -34,7 +34,6 @@ use turbopack_core::{ context::{AssetContext, AssetContextVc}, ident::AssetIdentVc, issue::{Issue, IssueVc}, - plugin::CustomModuleType, reference::all_referenced_assets, reference_type::{EcmaScriptModulesReferenceSubType, InnerAssetsVc, ReferenceType}, resolve::{ @@ -62,6 +61,7 @@ use turbopack_mdx::MdxModuleAssetVc; use turbopack_static::StaticModuleAssetVc; use self::{ + module_options::CustomModuleType, resolve_options_context::ResolveOptionsContextVc, transition::{TransitionVc, TransitionsByNameVc}, }; @@ -164,14 +164,12 @@ async fn apply_module_type( builder.build() } - ModuleType::Json => JsonModuleAssetVc::new(source).into(), ModuleType::Raw => source, - ModuleType::Css(transforms) => { - CssModuleAssetVc::new(source, context.into(), *transforms).into() - } - ModuleType::CssModule(transforms) => { - ModuleCssModuleAssetVc::new(source, context.into(), *transforms).into() + ModuleType::CssGlobal => GlobalCssAssetVc::new(source, context.into()).into(), + ModuleType::CssModule => ModuleCssAssetVc::new(source, context.into()).into(), + ModuleType::Css { ty, transforms } => { + CssModuleAssetVc::new(source, context.into(), *transforms, *ty).into() } ModuleType::Static => StaticModuleAssetVc::new(source, context.into()).into(), ModuleType::Mdx { diff --git a/crates/turbopack-core/src/plugin.rs b/crates/turbopack/src/module_options/custom_module_type.rs similarity index 56% rename from crates/turbopack-core/src/plugin.rs rename to crates/turbopack/src/module_options/custom_module_type.rs index 352fd58bd6fbb..cdd67907d5d49 100644 --- a/crates/turbopack-core/src/plugin.rs +++ b/crates/turbopack/src/module_options/custom_module_type.rs @@ -1,11 +1,13 @@ -use crate::{asset::AssetVc, context::AssetContextVc, resolve::ModulePartVc}; +use turbopack_core::{asset::AssetVc, resolve::ModulePartVc}; + +use crate::ModuleAssetContextVc; #[turbo_tasks::value_trait] pub trait CustomModuleType { fn create_module( &self, source: AssetVc, - context: AssetContextVc, + context: ModuleAssetContextVc, part: Option, ) -> AssetVc; } diff --git a/crates/turbopack/src/module_options/mod.rs b/crates/turbopack/src/module_options/mod.rs index 5ac0d264cd3d3..b3811b7208ec6 100644 --- a/crates/turbopack/src/module_options/mod.rs +++ b/crates/turbopack/src/module_options/mod.rs @@ -1,19 +1,21 @@ +pub(crate) mod custom_module_type; pub mod module_options_context; pub mod module_rule; pub mod rule_condition; use anyhow::{Context, Result}; +pub use custom_module_type::{CustomModuleType, CustomModuleTypeVc}; pub use module_options_context::*; pub use module_rule::*; pub use rule_condition::*; use turbo_tasks::primitives::OptionStringVc; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; use turbopack_core::{ - reference_type::{ReferenceType, UrlReferenceSubType}, + reference_type::{CssReferenceSubType, ReferenceType, UrlReferenceSubType}, resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}, source_transform::SourceTransformsVc, }; -use turbopack_css::{CssInputTransform, CssInputTransformsVc}; +use turbopack_css::{CssInputTransform, CssInputTransformsVc, CssModuleAssetType}; use turbopack_ecmascript::{ EcmascriptInputTransform, EcmascriptInputTransformsVc, EcmascriptOptions, SpecifiedModuleType, }; @@ -223,7 +225,12 @@ impl ModuleOptionsVc { vec![ModuleRuleEffect::ModuleType(ModuleType::Json)], ), ModuleRule::new( - ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::Internal), + )), + ]), [ if let Some(options) = enable_postcss_transform { let execution_context = execution_context @@ -249,19 +256,44 @@ impl ModuleOptionsVc { } else { None }, - Some(ModuleRuleEffect::ModuleType(ModuleType::Css( - css_transforms, - ))), + Some(ModuleRuleEffect::ModuleType(ModuleType::CssGlobal)), ] .into_iter() .flatten() .collect(), ), ModuleRule::new( - ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), - vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule( - css_transforms, - ))], + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::Internal), + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::Internal, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Default, + transforms: css_transforms, + })], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::Internal, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Module, + transforms: css_transforms, + })], ), ModuleRule::new( ModuleRuleCondition::any(vec![ diff --git a/crates/turbopack/src/module_options/module_rule.rs b/crates/turbopack/src/module_options/module_rule.rs index fc7223dd0ed5c..2b97d8ff0e9dc 100644 --- a/crates/turbopack/src/module_options/module_rule.rs +++ b/crates/turbopack/src/module_options/module_rule.rs @@ -3,14 +3,13 @@ use serde::{Deserialize, Serialize}; use turbo_tasks::trace::TraceRawVcs; use turbo_tasks_fs::FileSystemPath; use turbopack_core::{ - asset::AssetVc, plugin::CustomModuleTypeVc, reference_type::ReferenceType, - source_transform::SourceTransformsVc, + asset::AssetVc, reference_type::ReferenceType, source_transform::SourceTransformsVc, }; -use turbopack_css::CssInputTransformsVc; +use turbopack_css::{CssInputTransformsVc, CssModuleAssetType}; use turbopack_ecmascript::{EcmascriptInputTransformsVc, EcmascriptOptions}; use turbopack_mdx::MdxTransformOptionsVc; -use super::ModuleRuleCondition; +use super::{CustomModuleTypeVc, ModuleRuleCondition}; #[derive(Debug, Clone, Serialize, Deserialize, TraceRawVcs, PartialEq, Eq)] pub struct ModuleRule { @@ -74,8 +73,12 @@ pub enum ModuleType { transforms: EcmascriptInputTransformsVc, options: MdxTransformOptionsVc, }, - Css(CssInputTransformsVc), - CssModule(CssInputTransformsVc), + CssGlobal, + CssModule, + Css { + ty: CssModuleAssetType, + transforms: CssInputTransformsVc, + }, Static, Custom(CustomModuleTypeVc), } From 41230e8f4db988c391a762cf3ef42ec1bfbebe5c Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 3 Jul 2023 13:36:29 +0200 Subject: [PATCH 2/8] Review comments --- crates/turbopack-css/src/module_asset.rs | 28 +++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/turbopack-css/src/module_asset.rs b/crates/turbopack-css/src/module_asset.rs index 2a08da164c86d..db0bed980d874 100644 --- a/crates/turbopack-css/src/module_asset.rs +++ b/crates/turbopack-css/src/module_asset.rs @@ -48,7 +48,7 @@ fn modifier() -> StringVc { #[turbo_tasks::value] #[derive(Clone)] pub struct ModuleCssAsset { - pub inner: AssetVc, + pub source: AssetVc, pub context: AssetContextVc, } @@ -56,12 +56,7 @@ pub struct ModuleCssAsset { impl ModuleCssAssetVc { #[turbo_tasks::function] pub async fn new(source: AssetVc, context: AssetContextVc) -> Result { - let inner = context.process( - source, - Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), - ); - - Ok(Self::cell(ModuleCssAsset { inner, context })) + Ok(Self::cell(ModuleCssAsset { source, context })) } } @@ -69,7 +64,7 @@ impl ModuleCssAssetVc { impl Asset for ModuleCssAsset { #[turbo_tasks::function] fn ident(&self) -> AssetIdentVc { - self.inner.ident().with_modifier(modifier()) + self.source.ident().with_modifier(modifier()) } #[turbo_tasks::function] @@ -79,14 +74,12 @@ impl Asset for ModuleCssAsset { #[turbo_tasks::function] async fn references(self_vc: ModuleCssAssetVc) -> Result { - let this = self_vc.await?; - // The inner reference must come first so it is processed before other potential // references inside of the CSS, like `@import` and `composes:`. // This affects the order in which the resulting CSS chunks will be loaded: // later references are processed first in the post-order traversal of the // reference tree, and as such they will be loaded first in the resulting HTML. - let references = once(InternalCssAssetReferenceVc::new(this.inner).into()) + let references = once(InternalCssAssetReferenceVc::new(self_vc.inner()).into()) .chain(self_vc.module_references().await?.iter().copied()) .collect(); @@ -140,9 +133,18 @@ struct ModuleCssClasses(IndexMap>); #[turbo_tasks::value_impl] impl ModuleCssAssetVc { + #[turbo_tasks::function] + async fn inner(self) -> Result { + let this = self.await?; + Ok(this.context.process( + this.source, + Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), + )) + } + #[turbo_tasks::function] async fn classes(self) -> Result { - let inner = self.await?.inner; + let inner = self.inner(); let Some(inner) = ParseCssVc::resolve_from(inner).await? else { bail!("inner asset should be CSS parseable"); @@ -237,7 +239,7 @@ impl EcmascriptChunkPlaceable for ModuleCssAsset { impl ResolveOrigin for ModuleCssAsset { #[turbo_tasks::function] fn origin_path(&self) -> FileSystemPathVc { - self.inner.ident().path() + self.source.ident().path() } #[turbo_tasks::function] From a3871d6ed23dcbc883009eed49fbedefda418616 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 3 Jul 2023 14:49:06 +0200 Subject: [PATCH 3/8] ModuleRule::new_internal --- crates/turbopack-core/src/reference_type.rs | 10 +++++ crates/turbopack/src/module_options/mod.rs | 40 +++++++------------ .../src/module_options/module_rule.rs | 38 +++++++++++++++++- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/crates/turbopack-core/src/reference_type.rs b/crates/turbopack-core/src/reference_type.rs index 4db243e549514..4b1fa832831a6 100644 --- a/crates/turbopack-core/src/reference_type.rs +++ b/crates/turbopack-core/src/reference_type.rs @@ -157,4 +157,14 @@ impl ReferenceType { ReferenceType::Undefined => true, } } + + /// Returns true if this reference type is internal. This will be used in + /// combination with [`ModuleRuleCondition::Internal`] to determine if a + /// rule should be applied to an internal asset/reference. + pub fn is_internal(&self) -> bool { + matches!( + self, + ReferenceType::Internal(_) | ReferenceType::Css(CssReferenceSubType::Internal) + ) + } } diff --git a/crates/turbopack/src/module_options/mod.rs b/crates/turbopack/src/module_options/mod.rs index b3811b7208ec6..9f97595c56c16 100644 --- a/crates/turbopack/src/module_options/mod.rs +++ b/crates/turbopack/src/module_options/mod.rs @@ -225,12 +225,9 @@ impl ModuleOptionsVc { vec![ModuleRuleEffect::ModuleType(ModuleType::Json)], ), ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), - ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( - ReferenceType::Css(CssReferenceSubType::Internal), - )), - ]), + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".css".to_string(), + )]), [ if let Some(options) = enable_postcss_transform { let execution_context = execution_context @@ -263,33 +260,24 @@ impl ModuleOptionsVc { .collect(), ), ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), - ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( - ReferenceType::Css(CssReferenceSubType::Internal), - )), - ]), + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".module.css".to_string(), + )]), vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)], ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), - ModuleRuleCondition::ReferenceType(ReferenceType::Css( - CssReferenceSubType::Internal, - )), - ]), + ModuleRule::new_internal( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".css".to_string(), + )]), vec![ModuleRuleEffect::ModuleType(ModuleType::Css { ty: CssModuleAssetType::Default, transforms: css_transforms, })], ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), - ModuleRuleCondition::ReferenceType(ReferenceType::Css( - CssReferenceSubType::Internal, - )), - ]), + ModuleRule::new_internal( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".module.css".to_string(), + )]), vec![ModuleRuleEffect::ModuleType(ModuleType::Css { ty: CssModuleAssetType::Module, transforms: css_transforms, diff --git a/crates/turbopack/src/module_options/module_rule.rs b/crates/turbopack/src/module_options/module_rule.rs index 2b97d8ff0e9dc..6a170ab1436de 100644 --- a/crates/turbopack/src/module_options/module_rule.rs +++ b/crates/turbopack/src/module_options/module_rule.rs @@ -15,11 +15,44 @@ use super::{CustomModuleTypeVc, ModuleRuleCondition}; pub struct ModuleRule { condition: ModuleRuleCondition, effects: Vec, + match_mode: MatchMode, +} + +#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs)] +enum MatchMode { + // Match all but internal references. + #[default] + Default, + // Only match internal references. + Internal, +} + +impl MatchMode { + fn matches(&self, reference_type: &ReferenceType) -> bool { + matches!( + (self, reference_type.is_internal()), + (MatchMode::Default, false) | (MatchMode::Internal, true) + ) + } } impl ModuleRule { + /// Creates a new module rule. Will not match internal references. pub fn new(condition: ModuleRuleCondition, effects: Vec) -> Self { - ModuleRule { condition, effects } + ModuleRule { + condition, + effects, + match_mode: Default::default(), + } + } + + /// Creates a new module rule. Will only matches internal references. + pub fn new_internal(condition: ModuleRuleCondition, effects: Vec) -> Self { + ModuleRule { + condition, + effects, + match_mode: MatchMode::Internal, + } } pub fn effects(&self) -> impl Iterator { @@ -32,7 +65,8 @@ impl ModuleRule { path: &FileSystemPath, reference_type: &ReferenceType, ) -> Result { - self.condition.matches(source, path, reference_type).await + Ok(self.match_mode.matches(reference_type) + && self.condition.matches(source, path, reference_type).await?) } } From 64195978b95624c5766db8f1a992fdc35e8c209d Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 3 Jul 2023 15:00:57 +0200 Subject: [PATCH 4/8] Clippy --- crates/turbopack/src/module_options/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/turbopack/src/module_options/mod.rs b/crates/turbopack/src/module_options/mod.rs index 9f97595c56c16..3e8a0d0a0513a 100644 --- a/crates/turbopack/src/module_options/mod.rs +++ b/crates/turbopack/src/module_options/mod.rs @@ -11,7 +11,7 @@ pub use rule_condition::*; use turbo_tasks::primitives::OptionStringVc; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; use turbopack_core::{ - reference_type::{CssReferenceSubType, ReferenceType, UrlReferenceSubType}, + reference_type::{ReferenceType, UrlReferenceSubType}, resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}, source_transform::SourceTransformsVc, }; From 11d0f154275eed1b831475cf915011206228995b Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 4 Jul 2023 11:43:41 +0200 Subject: [PATCH 5/8] Review comments --- crates/turbopack-css/src/global_asset.rs | 36 +++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/turbopack-css/src/global_asset.rs b/crates/turbopack-css/src/global_asset.rs index f14e4fb89b4e1..5dc651113fe6c 100644 --- a/crates/turbopack-css/src/global_asset.rs +++ b/crates/turbopack-css/src/global_asset.rs @@ -15,7 +15,7 @@ use crate::references::internal::InternalCssAssetReferenceVc; #[derive(Clone)] pub struct GlobalCssAsset { source: AssetVc, - inner: AssetVc, + context: AssetContextVc, } #[turbo_tasks::value_impl] @@ -23,17 +23,23 @@ impl GlobalCssAssetVc { /// Creates a new CSS asset. The CSS is treated as global CSS. #[turbo_tasks::function] pub fn new(source: AssetVc, context: AssetContextVc) -> Self { - Self::cell(GlobalCssAsset { - source, - // The underlying CSS is processed through an internal CSS reference. - // This can then be picked up by other rules to treat CSS assets in - // a special way. For instance, in the Next App Router implementation, - // RSC CSS assets will be added to the client references manifest. - inner: context.process( - source, - Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), - ), - }) + Self::cell(GlobalCssAsset { source, context }) + } +} + +#[turbo_tasks::value_impl] +impl GlobalCssAssetVc { + #[turbo_tasks::function] + async fn inner(self) -> Result { + let this = self.await?; + // The underlying CSS is processed through an internal CSS reference. + // This can then be picked up by other rules to treat CSS assets in + // a special way. For instance, in the Next App Router implementation, + // RSC CSS assets will be added to the client references manifest. + Ok(this.context.process( + this.source, + Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), + )) } } @@ -50,8 +56,10 @@ impl Asset for GlobalCssAsset { } #[turbo_tasks::function] - fn references(&self) -> AssetReferencesVc { - AssetReferencesVc::cell(vec![InternalCssAssetReferenceVc::new(self.inner).into()]) + fn references(self_vc: GlobalCssAssetVc) -> AssetReferencesVc { + AssetReferencesVc::cell(vec![ + InternalCssAssetReferenceVc::new(self_vc.inner()).into() + ]) } } From 24cc0dc00c7dc53cda0cf861f728a2a304615ce3 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 4 Jul 2023 11:44:28 +0200 Subject: [PATCH 6/8] Fix tests and reference WEB-1261 for future improvements --- crates/turbopack-css/src/chunk/mod.rs | 1 + crates/turbopack-css/src/chunk/writer.rs | 1 + ..._b5a149.css => 8697f_foo_style_module.css} | 6 +-- ...css.map => 8697f_foo_style_module.css.map} | 0 ....css => 8697f_foo_style_module_c9a116.css} | 4 +- ... => 8697f_foo_style_module_c9a116.css.map} | 0 ...sts_snapshot_css_css_input_index_5771e1.js | 4 +- ...ts_snapshot_css_css_input_index_c6e36c.js} | 4 +- ...napshot_css_css_input_index_c6e36c.js.map} | 0 ...s_snapshot_css_css_input_style_module.css} | 6 +-- ...apshot_css_css_input_style_module.css.map} | 0 ...hot_css_css_input_style_module_c9a116.css} | 4 +- ...css_css_input_style_module_c9a116.css.map} | 0 crates/turbopack/src/module_options/mod.rs | 50 ++++++++++++++++--- 14 files changed, 59 insertions(+), 21 deletions(-) rename crates/turbopack-tests/tests/snapshot/css/css/output/{8697f_foo_style_module_b5a149.css => 8697f_foo_style_module.css} (53%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{8697f_foo_style_module_b5a149.css.map => 8697f_foo_style_module.css.map} (100%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{8697f_foo_style_module_fb38f0.css => 8697f_foo_style_module_c9a116.css} (50%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{8697f_foo_style_module_fb38f0.css.map => 8697f_foo_style_module_c9a116.css.map} (100%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js => crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js} (64%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js.map => crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js.map} (100%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css => crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css} (84%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css.map => crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css.map} (100%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css => crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css} (84%) rename crates/turbopack-tests/tests/snapshot/css/css/output/{crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css.map => crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css.map} (100%) diff --git a/crates/turbopack-css/src/chunk/mod.rs b/crates/turbopack-css/src/chunk/mod.rs index 483f767461e0d..8d4efc0dfcdc5 100644 --- a/crates/turbopack-css/src/chunk/mod.rs +++ b/crates/turbopack-css/src/chunk/mod.rs @@ -152,6 +152,7 @@ impl CssChunkContentVc { let entry_placeable = CssChunkPlaceableVc::cast_from(entry); let entry_item = entry_placeable.as_chunk_item(this.context); + // TODO(WEB-1261) for external_import in expand_imports(&mut body, entry_item).await? { external_imports.insert(external_import.await?.to_owned()); } diff --git a/crates/turbopack-css/src/chunk/writer.rs b/crates/turbopack-css/src/chunk/writer.rs index b1d1493c03a53..8580cf526e41a 100644 --- a/crates/turbopack-css/src/chunk/writer.rs +++ b/crates/turbopack-css/src/chunk/writer.rs @@ -10,6 +10,7 @@ use turbopack_core::{chunk::ChunkItem, code_builder::CodeBuilder}; use super::{CssChunkItemVc, CssImport}; use crate::chunk::CssChunkItem; +// TODO(WEB-1261) pub async fn expand_imports( code: &mut CodeBuilder, chunk_item: CssChunkItemVc, diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css similarity index 53% rename from crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css rename to crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css index fe483417d7fe2..5c3d701d22c5e 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css @@ -1,8 +1,8 @@ -/* chunk [workspace]/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css */ -/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css, css module) */ +/* chunk [workspace]/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css */ +/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css) */ .foo-module-style__style__abf9e738 { color: blue; } -/*# sourceMappingURL=8697f_foo_style_module_b5a149.css.map*/ \ No newline at end of file +/*# sourceMappingURL=8697f_foo_style_module.css.map*/ \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css.map b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css.map similarity index 100% rename from crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_b5a149.css.map rename to crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module.css.map diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_fb38f0.css b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_c9a116.css similarity index 50% rename from crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_fb38f0.css rename to crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_c9a116.css index c3e49b9995fe1..7fd72ca3b1a9e 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_fb38f0.css +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_c9a116.css @@ -1,5 +1,5 @@ -/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css, css module) */ +/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css) */ .foo-module-style__style__abf9e738 { color: blue; } -/*# sourceMappingURL=8697f_foo_style_module_fb38f0.css.map*/ \ No newline at end of file +/*# sourceMappingURL=8697f_foo_style_module_c9a116.css.map*/ \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_fb38f0.css.map b/crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_c9a116.css.map similarity index 100% rename from crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_fb38f0.css.map rename to crates/turbopack-tests/tests/snapshot/css/css/output/8697f_foo_style_module_c9a116.css.map diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_5771e1.js b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_5771e1.js index 3ab75d6c878f3..37eceef903059 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_5771e1.js +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_5771e1.js @@ -9,8 +9,8 @@ "output/8697f_foo_style_module_css_7740ee._.js", "output/8697f_foo_style.css", "output/crates_turbopack-tests_tests_snapshot_css_css_input_style.css", - "output/8697f_foo_style_module_b5a149.css", - "output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css" + "output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css", + "output/8697f_foo_style_module.css" ], "source": "entry" }); \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js similarity index 64% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js index 43c13cb0ef627..1a5b076c8065f 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js @@ -1,6 +1,6 @@ (globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([ - "output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js", + "output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js", {}, - {"otherChunks":[{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_index_b53fce.js","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/index.js (ecmascript)"]},{"path":"output/8697f_foo_style_module_css_7740ee._.js","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css module)"]},{"path":"output/8697f_foo_style.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.css (css)"],"moduleChunks":["output/8697f_foo_style_c9a116.css"]},{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_style.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.css (css)"],"moduleChunks":["output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_style_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css"]},{"path":"output/8697f_foo_style_module_b5a149.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css, css module)"],"moduleChunks":["output/8697f_foo_style_module_fb38f0.css"]},{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css, css module)"],"moduleChunks":["output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css"]}],"runtimeModuleIds":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/index.js (ecmascript)"]} + {"otherChunks":[{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_index_b53fce.js","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/index.js (ecmascript)"]},{"path":"output/8697f_foo_style_module_css_7740ee._.js","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css module)"]},{"path":"output/8697f_foo_style.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.css (css)"],"moduleChunks":["output/8697f_foo_style_c9a116.css"]},{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_style.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.css (css)"],"moduleChunks":["output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_style_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css","output/crates_turbopack-tests_tests_snapshot_css_css_input_imported_c9a116.css"]},{"path":"output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css)"],"moduleChunks":["output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css"]},{"path":"output/8697f_foo_style_module.css","included":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/node_modules/foo/style.module.css (css)"],"moduleChunks":["output/8697f_foo_style_module_c9a116.css"]}],"runtimeModuleIds":["[project]/crates/turbopack-tests/tests/snapshot/css/css/input/index.js (ecmascript)"]} ]); // Dummy runtime \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js.map b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js.map similarity index 100% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_011705.js.map rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_index_c6e36c.js.map diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css similarity index 84% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css index 8248098dc11c0..c2f418d237546 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css @@ -1,5 +1,5 @@ -/* chunk [workspace]/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css */ -/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css, css module) */ +/* chunk [workspace]/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css */ +/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css) */ .module-style__style__9bcf751c { color: magenta; } @@ -15,4 +15,4 @@ } -/*# sourceMappingURL=crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css.map*/ \ No newline at end of file +/*# sourceMappingURL=crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css.map*/ \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css.map b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css.map similarity index 100% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_b5a149.css.map rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module.css.map diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css similarity index 84% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css index da7abc9a5bc75..5a62e1740bf1d 100644 --- a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css +++ b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css @@ -1,4 +1,4 @@ -/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css, css module) */ +/* [project]/crates/turbopack-tests/tests/snapshot/css/css/input/style.module.css (css) */ .module-style__style__9bcf751c { color: magenta; } @@ -12,4 +12,4 @@ .another-composed-module-style__style__9bcf751c { color: yellow; } -/*# sourceMappingURL=crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css.map*/ \ No newline at end of file +/*# sourceMappingURL=crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css.map*/ \ No newline at end of file diff --git a/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css.map b/crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css.map similarity index 100% rename from crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_fb38f0.css.map rename to crates/turbopack-tests/tests/snapshot/css/css/output/crates_turbopack-tests_tests_snapshot_css_css_input_style_module_c9a116.css.map diff --git a/crates/turbopack/src/module_options/mod.rs b/crates/turbopack/src/module_options/mod.rs index 3e8a0d0a0513a..2f870fb2a71cf 100644 --- a/crates/turbopack/src/module_options/mod.rs +++ b/crates/turbopack/src/module_options/mod.rs @@ -11,7 +11,7 @@ pub use rule_condition::*; use turbo_tasks::primitives::OptionStringVc; use turbo_tasks_fs::{glob::GlobVc, FileSystemPathVc}; use turbopack_core::{ - reference_type::{ReferenceType, UrlReferenceSubType}, + reference_type::{CssReferenceSubType, ReferenceType, UrlReferenceSubType}, resolve::options::{ImportMap, ImportMapVc, ImportMapping, ImportMappingVc}, source_transform::SourceTransformsVc, }; @@ -225,9 +225,13 @@ impl ModuleOptionsVc { vec![ModuleRuleEffect::ModuleType(ModuleType::Json)], ), ModuleRule::new( - ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( - ".css".to_string(), - )]), + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + // Only create a global CSS asset if not `@import`ed from CSS already. + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::AtImport), + )), + ]), [ if let Some(options) = enable_postcss_transform { let execution_context = execution_context @@ -260,11 +264,43 @@ impl ModuleOptionsVc { .collect(), ), ModuleRule::new( - ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( - ".module.css".to_string(), - )]), + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + // Only create a module CSS asset if not `@import`ed from CSS already. + // NOTE: `composes` references should not be treated as `@import`s and should + // also create a module CSS asset. + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::AtImport), + )), + ]), vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)], ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + // Create a normal CSS asset if `@import`ed from CSS already. + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::AtImport, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Default, + transforms: css_transforms, + })], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + // Create a normal CSS asset if `@import`ed from CSS already. + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::AtImport, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Module, + transforms: css_transforms, + })], + ), ModuleRule::new_internal( ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( ".css".to_string(), From 29c7333d491c7d5bcae4b4d436710ea387e70a7c Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 4 Jul 2023 13:25:17 +0200 Subject: [PATCH 7/8] Clippy --- crates/turbopack/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/turbopack/src/lib.rs b/crates/turbopack/src/lib.rs index c7959067dd880..04a707c346bf3 100644 --- a/crates/turbopack/src/lib.rs +++ b/crates/turbopack/src/lib.rs @@ -176,7 +176,7 @@ async fn apply_module_type( transforms, options, } => MdxModuleAssetVc::new(source, context.into(), *transforms, *options).into(), - ModuleType::Custom(custom) => custom.create_module(source, context.into(), part), + ModuleType::Custom(custom) => custom.create_module(source, context, part), }) } From 5b846f7ff360f4ed8f62b5fd127111b47a229a25 Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Tue, 4 Jul 2023 13:55:41 +0200 Subject: [PATCH 8/8] Use raw CSS assets with NFT --- crates/turbopack/src/module_options/mod.rs | 218 ++++++++++-------- .../module_options/module_options_context.rs | 6 + crates/turbopack/tests/node-file-trace.rs | 1 + 3 files changed, 130 insertions(+), 95 deletions(-) diff --git a/crates/turbopack/src/module_options/mod.rs b/crates/turbopack/src/module_options/mod.rs index 2f870fb2a71cf..bd9677f8dbcff 100644 --- a/crates/turbopack/src/module_options/mod.rs +++ b/crates/turbopack/src/module_options/mod.rs @@ -70,6 +70,7 @@ impl ModuleOptionsVc { ref decorators, enable_mdx, enable_mdx_rs, + enable_raw_css, ref enable_postcss_transform, ref enable_webpack_loaders, preset_env_versions, @@ -224,101 +225,6 @@ impl ModuleOptionsVc { ModuleRuleCondition::ResourcePathEndsWith(".json".to_string()), vec![ModuleRuleEffect::ModuleType(ModuleType::Json)], ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), - // Only create a global CSS asset if not `@import`ed from CSS already. - ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( - ReferenceType::Css(CssReferenceSubType::AtImport), - )), - ]), - [ - if let Some(options) = enable_postcss_transform { - let execution_context = execution_context - .context("execution_context is required for the postcss_transform")? - .with_layer("postcss"); - - let import_map = if let Some(postcss_package) = options.postcss_package { - package_import_map_from_import_mapping("postcss", postcss_package) - } else { - package_import_map_from_context("postcss", path) - }; - Some(ModuleRuleEffect::SourceTransforms( - SourceTransformsVc::cell(vec![PostCssTransformVc::new( - node_evaluate_asset_context( - execution_context, - Some(import_map), - None, - ), - execution_context, - ) - .into()]), - )) - } else { - None - }, - Some(ModuleRuleEffect::ModuleType(ModuleType::CssGlobal)), - ] - .into_iter() - .flatten() - .collect(), - ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), - // Only create a module CSS asset if not `@import`ed from CSS already. - // NOTE: `composes` references should not be treated as `@import`s and should - // also create a module CSS asset. - ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( - ReferenceType::Css(CssReferenceSubType::AtImport), - )), - ]), - vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)], - ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), - // Create a normal CSS asset if `@import`ed from CSS already. - ModuleRuleCondition::ReferenceType(ReferenceType::Css( - CssReferenceSubType::AtImport, - )), - ]), - vec![ModuleRuleEffect::ModuleType(ModuleType::Css { - ty: CssModuleAssetType::Default, - transforms: css_transforms, - })], - ), - ModuleRule::new( - ModuleRuleCondition::all(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), - // Create a normal CSS asset if `@import`ed from CSS already. - ModuleRuleCondition::ReferenceType(ReferenceType::Css( - CssReferenceSubType::AtImport, - )), - ]), - vec![ModuleRuleEffect::ModuleType(ModuleType::Css { - ty: CssModuleAssetType::Module, - transforms: css_transforms, - })], - ), - ModuleRule::new_internal( - ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( - ".css".to_string(), - )]), - vec![ModuleRuleEffect::ModuleType(ModuleType::Css { - ty: CssModuleAssetType::Default, - transforms: css_transforms, - })], - ), - ModuleRule::new_internal( - ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( - ".module.css".to_string(), - )]), - vec![ModuleRuleEffect::ModuleType(ModuleType::Css { - ty: CssModuleAssetType::Module, - transforms: css_transforms, - })], - ), ModuleRule::new( ModuleRuleCondition::any(vec![ ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), @@ -451,6 +357,128 @@ impl ModuleOptionsVc { ), ]; + if enable_raw_css { + rules.extend([ + ModuleRule::new( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".css".to_string(), + )]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Default, + transforms: css_transforms, + })], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".module.css".to_string(), + )]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Module, + transforms: css_transforms, + })], + ), + ]); + } else { + rules.extend([ + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + // Only create a global CSS asset if not `@import`ed from CSS already. + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::AtImport), + )), + ]), + [ + if let Some(options) = enable_postcss_transform { + let execution_context = execution_context + .context("execution_context is required for the postcss_transform")? + .with_layer("postcss"); + + let import_map = if let Some(postcss_package) = options.postcss_package + { + package_import_map_from_import_mapping("postcss", postcss_package) + } else { + package_import_map_from_context("postcss", path) + }; + Some(ModuleRuleEffect::SourceTransforms( + SourceTransformsVc::cell(vec![PostCssTransformVc::new( + node_evaluate_asset_context( + execution_context, + Some(import_map), + None, + ), + execution_context, + ) + .into()]), + )) + } else { + None + }, + Some(ModuleRuleEffect::ModuleType(ModuleType::CssGlobal)), + ] + .into_iter() + .flatten() + .collect(), + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + // Only create a module CSS asset if not `@import`ed from CSS already. + // NOTE: `composes` references should not be treated as `@import`s and + // should also create a module CSS asset. + ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType( + ReferenceType::Css(CssReferenceSubType::AtImport), + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".css".to_string()), + // Create a normal CSS asset if `@import`ed from CSS already. + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::AtImport, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Default, + transforms: css_transforms, + })], + ), + ModuleRule::new( + ModuleRuleCondition::all(vec![ + ModuleRuleCondition::ResourcePathEndsWith(".module.css".to_string()), + // Create a normal CSS asset if `@import`ed from CSS already. + ModuleRuleCondition::ReferenceType(ReferenceType::Css( + CssReferenceSubType::AtImport, + )), + ]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Module, + transforms: css_transforms, + })], + ), + ModuleRule::new_internal( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".css".to_string(), + )]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Default, + transforms: css_transforms, + })], + ), + ModuleRule::new_internal( + ModuleRuleCondition::all(vec![ModuleRuleCondition::ResourcePathEndsWith( + ".module.css".to_string(), + )]), + vec![ModuleRuleEffect::ModuleType(ModuleType::Css { + ty: CssModuleAssetType::Module, + transforms: css_transforms, + })], + ), + ]); + } + if enable_mdx || enable_mdx_rs.is_some() { let (jsx_runtime, jsx_import_source) = if let Some(enable_jsx) = enable_jsx { let jsx = enable_jsx.await?; diff --git a/crates/turbopack/src/module_options/module_options_context.rs b/crates/turbopack/src/module_options/module_options_context.rs index 646a28460e68b..f9565a6c395c6 100644 --- a/crates/turbopack/src/module_options/module_options_context.rs +++ b/crates/turbopack/src/module_options/module_options_context.rs @@ -157,6 +157,12 @@ pub struct ModuleOptionsContext { pub enable_typescript_transform: Option, pub decorators: Option, pub enable_mdx: bool, + /// This skips `GlobalCss` and `ModuleCss` module assets from being + /// generated in the module graph, generating only `Css` module assets. + /// + /// This is useful for node-file-trace, which tries to emit all assets in + /// the module graph, but neither asset types can be emitted directly. + pub enable_raw_css: bool, // [Note]: currently mdx, and mdx_rs have different configuration entrypoint from next.config.js, // however we might want to unify them in the future. pub enable_mdx_rs: Option, diff --git a/crates/turbopack/tests/node-file-trace.rs b/crates/turbopack/tests/node-file-trace.rs index 63e1f63afc206..782e6c722f161 100644 --- a/crates/turbopack/tests/node-file-trace.rs +++ b/crates/turbopack/tests/node-file-trace.rs @@ -420,6 +420,7 @@ fn node_file_trace( ))), ModuleOptionsContext { enable_types: true, + enable_raw_css: true, ..Default::default() } .cell(),