mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Scan Next.js dynamic route segments with manual @source rules (#16457)
Part of #16287 ## Test plan Added unit and integration tests --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This commit is contained in:
parent
f0141084c2
commit
08972f294f
@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Ensure drop shadow utilities don't inherit unexpectedly ([#16471](https://github.com/tailwindlabs/tailwindcss/pull/16471))
|
||||
- Export backwards compatible config and plugin types from `tailwindcss/plugin` ([#16505](https://github.com/tailwindlabs/tailwindcss/pull/16505))
|
||||
- Ensure JavaScript plugins that emit nested rules referencing to the utility name work as expected ([#16539](https://github.com/tailwindlabs/tailwindcss/pull/16539))
|
||||
- Ensure that Next.js splat routes are automatically scanned for classes ([#16457](https://github.com/tailwindlabs/tailwindcss/pull/16457))
|
||||
- Pin exact versions of `tailwindcss` and `@tailwindcss/*` ([#16623](https://github.com/tailwindlabs/tailwindcss/pull/16623))
|
||||
- Upgrade: Report errors when updating dependencies ([#16504](https://github.com/tailwindlabs/tailwindcss/pull/16504))
|
||||
- Upgrade: Ensure a `darkMode` JS config setting with block syntax converts to use `@slot` ([#16507](https://github.com/tailwindlabs/tailwindcss/pull/16507))
|
||||
|
||||
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -11,6 +11,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "bexpand"
|
||||
version = "1.2.0"
|
||||
@ -141,18 +147,21 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fast-glob"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eca69ef247d19faa15ac0156968637440824e5ff22baa5ee0cd35b2f7ea6a0f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "glob-match"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.15"
|
||||
@ -524,7 +533,7 @@ dependencies = [
|
||||
"bstr",
|
||||
"crossbeam",
|
||||
"dunce",
|
||||
"glob-match",
|
||||
"fast-glob",
|
||||
"globwalk",
|
||||
"ignore",
|
||||
"log",
|
||||
|
||||
@ -16,7 +16,7 @@ walkdir = "2.5.0"
|
||||
ignore = "0.4.23"
|
||||
dunce = "1.0.5"
|
||||
bexpand = "1.2.0"
|
||||
glob-match = "0.2.1"
|
||||
fast-glob = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.13.0"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use fast_glob::glob_match;
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
use glob_match::glob_match;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tracing::event;
|
||||
|
||||
@ -173,7 +173,7 @@ pub fn path_matches_globs(path: &Path, globs: &[GlobEntry]) -> bool {
|
||||
|
||||
globs
|
||||
.iter()
|
||||
.any(|g| glob_match(&format!("{}/{}", g.base, g.pattern), &path))
|
||||
.any(|g| glob_match(&format!("{}/{}", g.base, g.pattern), path.as_bytes()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -4,9 +4,9 @@ use crate::scanner::allowed_paths::resolve_paths;
|
||||
use crate::scanner::detect_sources::DetectSources;
|
||||
use bexpand::Expression;
|
||||
use bstr::ByteSlice;
|
||||
use fast_glob::glob_match;
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
use glob::optimize_patterns;
|
||||
use glob_match::glob_match;
|
||||
use paths::Path;
|
||||
use rayon::prelude::*;
|
||||
use scanner::allowed_paths::read_dir;
|
||||
|
||||
@ -415,6 +415,32 @@ mod scanner {
|
||||
assert_eq!(candidates, vec!["content-['foo.styl']"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_scan_next_dynamic_folders() {
|
||||
let candidates = scan_with_globs(
|
||||
&[
|
||||
// We know that `.styl` extensions are ignored, so they are not covered by auto content
|
||||
// detection.
|
||||
("app/[slug]/page.styl", "content-['[slug]']"),
|
||||
("app/[...slug]/page.styl", "content-['[...slug]']"),
|
||||
("app/[[...slug]]/page.styl", "content-['[[...slug]]']"),
|
||||
("app/(theme)/page.styl", "content-['(theme)']"),
|
||||
],
|
||||
vec!["./**/*.{styl}"],
|
||||
)
|
||||
.1;
|
||||
|
||||
assert_eq!(
|
||||
candidates,
|
||||
vec![
|
||||
"content-['(theme)']",
|
||||
"content-['[...slug]']",
|
||||
"content-['[[...slug]]']",
|
||||
"content-['[slug]']",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_scan_absolute_paths() {
|
||||
// Create a temporary working directory
|
||||
|
||||
@ -162,3 +162,89 @@ describe.each(['turbo', 'webpack'])('%s', (bundler) => {
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'should scan dynamic route segments',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next": "^14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'postcss.config.mjs': js`
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
`,
|
||||
'next.config.mjs': js`
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
|
||||
export default nextConfig
|
||||
`,
|
||||
'app/a/[slug]/page.js': js`
|
||||
export default function Page() {
|
||||
return <h1 className="content-['[slug]']">Hello, Next.js!</h1>
|
||||
}
|
||||
`,
|
||||
'app/b/[...slug]/page.js': js`
|
||||
export default function Page() {
|
||||
return <h1 className="content-['[...slug]']">Hello, Next.js!</h1>
|
||||
}
|
||||
`,
|
||||
'app/c/[[...slug]]/page.js': js`
|
||||
export default function Page() {
|
||||
return <h1 className="content-['[[...slug]]']">Hello, Next.js!</h1>
|
||||
}
|
||||
`,
|
||||
'app/d/(theme)/page.js': js`
|
||||
export default function Page() {
|
||||
return <h1 className="content-['(theme)']">Hello, Next.js!</h1>
|
||||
}
|
||||
`,
|
||||
'app/layout.js': js`
|
||||
import './globals.css'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
`,
|
||||
'app/globals.css': css`
|
||||
@import 'tailwindcss/utilities' source(none);
|
||||
@source './**/*.{js,ts,jsx,tsx,mdx}';
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ fs, exec, expect }) => {
|
||||
await exec('pnpm next build')
|
||||
|
||||
let files = await fs.glob('.next/static/css/**/*.css')
|
||||
expect(files).toHaveLength(1)
|
||||
let [filename] = files[0]
|
||||
|
||||
await fs.expectFileToContain(filename, [
|
||||
candidate`content-['[slug]']`,
|
||||
candidate`content-['[...slug]']`,
|
||||
candidate`content-['[[...slug]]']`,
|
||||
candidate`content-['(theme)']`,
|
||||
])
|
||||
},
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user